From b3813f9fffdcb96dca14231cdafca4a7c6b0d032 Mon Sep 17 00:00:00 2001 From: Howard Butler Date: Mon, 4 Jan 2010 08:48:28 -0600 Subject: [PATCH] It compiles! (on os x) --- AUTHORS | 5 + COPYING | 505 +++++++++++++ Makefile.am | 8 + autogen.sh | 42 ++ configure.ac | 147 ++++ include/Makefile.am | 18 + include/lasdefinitions.h | 285 ++++++++ include/laspointreader.h | 60 ++ include/laspointreader0compressed.h | 87 +++ include/laspointreader0raw.h | 68 ++ include/laspointreader1compressed.h | 92 +++ include/laspointreader1raw.h | 69 ++ include/laspointreader2compressed.h | 90 +++ include/laspointreader2raw.h | 68 ++ include/laspointreader3compressed.h | 95 +++ include/laspointreader3raw.h | 69 ++ include/laspointwriter.h | 60 ++ include/laspointwriter0compressed.h | 87 +++ include/laspointwriter0raw.h | 69 ++ include/laspointwriter1compressed.h | 92 +++ include/laspointwriter1raw.h | 69 ++ include/laspointwriter2compressed.h | 90 +++ include/laspointwriter2raw.h | 69 ++ include/laspointwriter3compressed.h | 95 +++ include/laspointwriter3raw.h | 69 ++ include/lasreader.h | 92 +++ include/laswriter.h | 80 ++ laszip-config.in | 53 ++ src/Makefile.am | 19 + src/alternate_coder_src/Makefile.am | 14 + src/alternate_coder_src/arithmeticdecoder.cpp | 288 ++++++++ src/alternate_coder_src/arithmeticdecoder.h | 109 +++ src/alternate_coder_src/arithmeticencoder.cpp | 307 ++++++++ src/alternate_coder_src/arithmeticencoder.h | 113 +++ src/alternate_coder_src/arithmeticmodel.cpp | 178 +++++ src/alternate_coder_src/arithmeticmodel.h | 103 +++ .../integercompressor_newest.cpp | 567 +++++++++++++++ .../integercompressor_newest.h | 140 ++++ .../laspointreader0compressed.cpp | 246 +++++++ .../laspointreader0compressed.h | 91 +++ .../laspointreader1compressed.cpp | 302 ++++++++ .../laspointreader1compressed.h | 97 +++ .../laspointreader2compressed.cpp | 274 +++++++ .../laspointreader2compressed.h | 94 +++ .../laspointreader3compressed.cpp | 329 +++++++++ .../laspointreader3compressed.h | 100 +++ .../laspointwriter0compressed.cpp | 253 +++++++ .../laspointwriter0compressed.h | 92 +++ .../laspointwriter1compressed.cpp | 321 +++++++++ .../laspointwriter1compressed.h | 96 +++ .../laspointwriter2compressed.cpp | 281 ++++++++ .../laspointwriter2compressed.h | 94 +++ .../laspointwriter3compressed.cpp | 348 +++++++++ .../laspointwriter3compressed.h | 99 +++ src/integercompressor_newer.cpp | 596 +++++++++++++++ src/integercompressor_newer.h | 136 ++++ src/laspointreader0compressed.cpp | 242 +++++++ src/laspointreader1compressed.cpp | 298 ++++++++ src/laspointreader2compressed.cpp | 270 +++++++ src/laspointreader3compressed.cpp | 325 +++++++++ src/laspointwriter0compressed.cpp | 249 +++++++ src/laspointwriter1compressed.cpp | 317 ++++++++ src/laspointwriter2compressed.cpp | 277 +++++++ src/laspointwriter3compressed.cpp | 344 +++++++++ src/lasreader.cpp | 681 ++++++++++++++++++ src/laswriter.cpp | 594 +++++++++++++++ src/mydefs.h | 59 ++ src/rangedecoder.cpp | 327 +++++++++ src/rangedecoder.h | 124 ++++ src/rangeencoder.cpp | 375 ++++++++++ src/rangeencoder.h | 119 +++ src/rangemodel.cpp | 254 +++++++ src/rangemodel.h | 120 +++ 73 files changed, 13295 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 Makefile.am create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 include/Makefile.am create mode 100644 include/lasdefinitions.h create mode 100644 include/laspointreader.h create mode 100644 include/laspointreader0compressed.h create mode 100644 include/laspointreader0raw.h create mode 100644 include/laspointreader1compressed.h create mode 100644 include/laspointreader1raw.h create mode 100644 include/laspointreader2compressed.h create mode 100644 include/laspointreader2raw.h create mode 100644 include/laspointreader3compressed.h create mode 100644 include/laspointreader3raw.h create mode 100644 include/laspointwriter.h create mode 100644 include/laspointwriter0compressed.h create mode 100644 include/laspointwriter0raw.h create mode 100644 include/laspointwriter1compressed.h create mode 100644 include/laspointwriter1raw.h create mode 100644 include/laspointwriter2compressed.h create mode 100644 include/laspointwriter2raw.h create mode 100644 include/laspointwriter3compressed.h create mode 100644 include/laspointwriter3raw.h create mode 100644 include/lasreader.h create mode 100644 include/laswriter.h create mode 100644 laszip-config.in create mode 100644 src/Makefile.am create mode 100644 src/alternate_coder_src/Makefile.am create mode 100644 src/alternate_coder_src/arithmeticdecoder.cpp create mode 100644 src/alternate_coder_src/arithmeticdecoder.h create mode 100644 src/alternate_coder_src/arithmeticencoder.cpp create mode 100644 src/alternate_coder_src/arithmeticencoder.h create mode 100644 src/alternate_coder_src/arithmeticmodel.cpp create mode 100644 src/alternate_coder_src/arithmeticmodel.h create mode 100644 src/alternate_coder_src/integercompressor_newest.cpp create mode 100644 src/alternate_coder_src/integercompressor_newest.h create mode 100644 src/alternate_coder_src/laspointreader0compressed.cpp create mode 100644 src/alternate_coder_src/laspointreader0compressed.h create mode 100644 src/alternate_coder_src/laspointreader1compressed.cpp create mode 100644 src/alternate_coder_src/laspointreader1compressed.h create mode 100644 src/alternate_coder_src/laspointreader2compressed.cpp create mode 100644 src/alternate_coder_src/laspointreader2compressed.h create mode 100644 src/alternate_coder_src/laspointreader3compressed.cpp create mode 100644 src/alternate_coder_src/laspointreader3compressed.h create mode 100644 src/alternate_coder_src/laspointwriter0compressed.cpp create mode 100644 src/alternate_coder_src/laspointwriter0compressed.h create mode 100644 src/alternate_coder_src/laspointwriter1compressed.cpp create mode 100644 src/alternate_coder_src/laspointwriter1compressed.h create mode 100644 src/alternate_coder_src/laspointwriter2compressed.cpp create mode 100644 src/alternate_coder_src/laspointwriter2compressed.h create mode 100644 src/alternate_coder_src/laspointwriter3compressed.cpp create mode 100644 src/alternate_coder_src/laspointwriter3compressed.h create mode 100644 src/integercompressor_newer.cpp create mode 100644 src/integercompressor_newer.h create mode 100644 src/laspointreader0compressed.cpp create mode 100644 src/laspointreader1compressed.cpp create mode 100644 src/laspointreader2compressed.cpp create mode 100644 src/laspointreader3compressed.cpp create mode 100644 src/laspointwriter0compressed.cpp create mode 100644 src/laspointwriter1compressed.cpp create mode 100644 src/laspointwriter2compressed.cpp create mode 100644 src/laspointwriter3compressed.cpp create mode 100644 src/lasreader.cpp create mode 100644 src/laswriter.cpp create mode 100644 src/mydefs.h create mode 100644 src/rangedecoder.cpp create mode 100644 src/rangedecoder.h create mode 100644 src/rangeencoder.cpp create mode 100644 src/rangeencoder.h create mode 100644 src/rangemodel.cpp create mode 100644 src/rangemodel.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..4d9bbc0e --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +Martin Isenburg +martin.isenburg at gmail.com + +Howard Butler +hobu.inc at gmail.com diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..cc679a98 --- /dev/null +++ b/COPYING @@ -0,0 +1,505 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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! + + + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..87b9da66 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,8 @@ +SUBDIRS = src . include + +lib_LTLIBRARIES = liblaszip.la + +liblaszip_la_SOURCES = +liblaszip_la_LIBADD = src/liblibrary.la src/alternate_coder_src/liblaszip_alternate.la + +liblaszip_la_LDFLAGS = -version-info 1:0:0 \ No newline at end of file diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 00000000..77c250a0 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# $Id$ +# +# Autotools boostrapping script +# +giveup() +{ + echo + echo " Something went wrong, giving up!" + echo + exit 1 +} + +OSTYPE=`uname -s` + +for libtoolize in glibtoolize libtoolize; do + LIBTOOLIZE=`which $libtoolize 2>/dev/null` + if test "$LIBTOOLIZE"; then + break; + fi +done + +#AMFLAGS="--add-missing --copy --force-missing" +AMFLAGS="--add-missing --copy" +if test "$OSTYPE" = "IRIX" -o "$OSTYPE" = "IRIX64"; then + AMFLAGS=$AMFLAGS" --include-deps"; +fi + +echo "Running aclocal " +aclocal || giveup +#echo "Running autoheader" +#autoheader || giveup +echo "Running libtoolize" +$LIBTOOLIZE --force --copy || giveup +echo "Running automake" +automake $AMFLAGS # || giveup +echo "Running autoconf" +autoconf || giveup + +echo "======================================" +echo "Now you are ready to run './configure'" +echo "======================================" diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..fe4fc191 --- /dev/null +++ b/configure.ac @@ -0,0 +1,147 @@ +dnl $Id$ +dnl +dnl This is main autoconf bootstrap script of libLAS project. +dnl +m4_define([laszip_version_major], [0]) +m4_define([laszip_version_minor], [1]) +m4_define([laszip_version_micro], [0]) +m4_define([laszip_version], + [laszip_version_major.laszip_version_minor.laszip_version_micro]) + +AC_PREREQ([2.59]) +AC_INIT([laszip], [laszip_version], [hobu.inc@gmail.com],[laszip-src]) +AC_CANONICAL_BUILD + +RELEASE_VERSION=laszip_version +AC_SUBST([RELEASE_VERSION]) + +dnl ######################################################################### +dnl Default compilation flags +dnl ######################################################################### + +m4_define([debug_default],[no]) + +CFLAGS="-Wall -Wno-long-long -pedantic $CFLAGS" +CXXFLAGS="-Wall -Wno-long-long -pedantic -std=c++98 $CXXFLAGS" + +dnl ######################################################################### +dnl Checks for programs. +dnl ######################################################################### + +AM_INIT_AUTOMAKE([dist-bzip2]) +AC_PROG_CXX +AC_PROG_CXXCPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_LIBTOOL + +dnl ######################################################################### +dnl Check platform endianness +dnl ######################################################################### + +AC_C_BIGENDIAN + +dnl ######################################################################### +dnl Checks for header files. +dnl ######################################################################### + +AC_CHECK_HEADERS([string.h],, [AC_MSG_ERROR([cannot find string.h, bailing out])]) +AC_CHECK_HEADERS([stdio.h],, [AC_MSG_ERROR([cannot find stdio.h, bailing out])]) +AC_CHECK_HEADERS([stdlib.h],, [AC_MSG_ERROR([cannot find stdlib.h, bailing out])]) + + +LIBS="${LIBS}" + + +dnl ######################################################################### +dnl Build mode configuration (debug/optimized) +dnl ######################################################################### + +AC_ARG_ENABLE([debug], + AC_HELP_STRING([--enable-debug=ARG], [Enable debug compilation mode @<:@yes|no@:>@, default=debug_default]),,) + +AC_MSG_CHECKING([for debug enabled]) + +if test "x$enable_debug" = "xyes"; then + CFLAGS="$CFLAGS -g -DDEBUG" + CXXFLAGS="$CXXFLAGS -g -DDEBUG" + AC_MSG_RESULT(yes) +else + CFLAGS="$CFLAGS -O3 -DNDEBUG" + CXXFLAGS="$CXXFLAGS -O3 -DNDEBUG" + AC_MSG_RESULT(no) +fi + +dnl ######################################################################### +dnl Definiion of custom Autoconf macros +dnl ######################################################################### + +AC_DEFUN([LOC_MSG],[ +echo "$1" +]) + +AC_DEFUN([AC_HAVE_LONG_LONG], +[ + AC_MSG_CHECKING([for 64bit integer type]) + + echo 'int main() { long long off=0; }' >> conftest.c + if test -z "`${CC} -o conftest conftest.c 2>&1`" ; then + AC_DEFINE(HAVE_LONG_LONG, 1, [Define to 1, if your compiler supports long long data type]) + AC_MSG_RESULT([long long]) + else + AC_MSG_RESULT([no]) + fi + rm -f conftest* +]) + + + + +dnl ######################################################################### +dnl Determine other features of compiler +dnl ######################################################################### + +AC_HAVE_LONG_LONG + +dnl ######################################################################### +dnl Checks for library functions. +dnl ######################################################################### + +AC_CHECK_FUNCS([gettimeofday bzero memset memcpy bcopy]) + +dnl ######################################################################### +dnl Generate makefiles +dnl ######################################################################### + +AC_CONFIG_FILES([ + Makefile + include/Makefile + src/Makefile + src/alternate_coder_src/Makefile + laszip-config + +]) + +AC_OUTPUT + +dnl ######################################################################### +dnl Print configuration summary +dnl ######################################################################### + +LOC_MSG() +LOC_MSG([libLAS configuration summary:]) +LOC_MSG() +LOC_MSG([ Version..................: ${RELEASE_VERSION}]) +LOC_MSG([ Installation directory...: ${prefix}]) +LOC_MSG([ C compiler...............: ${CC} ${CFLAGS}]) +LOC_MSG([ C++ compiler.............: ${CXX} ${CXXFLAGS}]) +LOC_MSG([ Debugging support........: ${enable_debug}]) + +LOC_MSG() +LOC_MSG([ LIBS.....................: ${LIBS}]) +LOC_MSG() +LOC_MSG([ libLAS - http://liblas.org]) +LOC_MSG() + +dnl EOF diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 00000000..0b8c448c --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,18 @@ +laszipdir = $(includedir)/laszip + +laszip_HEADERS = lasdefinitions.h \ + laspointreader.h \ + laspointreader0compressed.h \ + laspointreader1compressed.h \ + laspointreader2compressed.h \ + laspointwriter0compressed.h \ + laspointwriter1compressed.h \ + laspointwriter2compressed.h \ + laspointreader0raw.h \ + laspointreader1raw.h \ + laspointreader2raw.h \ + laspointwriter0raw.h \ + laspointwriter1raw.h \ + laspointwriter2raw.h \ + lasreader.h \ + laswriter.h \ No newline at end of file diff --git a/include/lasdefinitions.h b/include/lasdefinitions.h new file mode 100644 index 00000000..eb8f1af0 --- /dev/null +++ b/include/lasdefinitions.h @@ -0,0 +1,285 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: LASdefinitions.h + + CONTENTS: + + Contains the Header and Point classes for reading and writing LIDAR points + in the LAS format + + Version 1.2, April 29, 2008. + Version 1.1, March 07, 2005. + Version 1.0, May 09, 2003 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 11 June 2007 -- number of return / scan direction bitfield order was wrong + 18 February 2007 -- created after repairing 2 vacuum cleaners in the garden + +=============================================================================== +*/ +#ifndef LAS_DEFINITIONS_H +#define LAS_DEFINITIONS_H + +class LASpoint +{ +public: + int x; + int y; + int z; + unsigned short intensity; + unsigned char return_number : 3; + unsigned char number_of_returns_of_given_pulse : 3; + unsigned char scan_direction_flag : 1; + unsigned char edge_of_flight_line : 1; + unsigned char classification; + char scan_angle_rank; + unsigned char user_data; + unsigned short point_source_ID; + + LASpoint() + { + x=0; + y=0; + z=0; + intensity=0; + edge_of_flight_line=0; + scan_direction_flag=0; + number_of_returns_of_given_pulse = 0; + return_number = 0; + classification = 0; + scan_angle_rank = 0; + user_data = 0; + point_source_ID = 0; + }; +}; + +class LASvlr +{ +public: + unsigned short reserved; + char user_id[16]; + unsigned short record_id; + unsigned short record_length_after_header; + char description[32]; + char* data; +}; + +class LASvlr_geo_keys +{ +public: + unsigned short key_directory_version; + unsigned short key_revision; + unsigned short minor_revision; + unsigned short number_of_keys; +}; + +class LASvlr_key_entry +{ +public: + unsigned short key_id; + unsigned short tiff_tag_location; + unsigned short count; + unsigned short value_offset; +}; + +class LASheader +{ +public: + char file_signature[4]; + unsigned short file_source_id; + unsigned short global_encoding; + unsigned int project_ID_GUID_data_1; + unsigned short project_ID_GUID_data_2; + unsigned short project_ID_GUID_data_3; + char project_ID_GUID_data_4[8]; + char version_major; + char version_minor; + char system_identifier[32]; + char generating_software[32]; + unsigned short file_creation_day; + unsigned short file_creation_year; + unsigned short header_size; + unsigned int offset_to_point_data; + unsigned int number_of_variable_length_records; + unsigned char point_data_format; + unsigned short point_data_record_length; + unsigned int number_of_point_records; + unsigned int number_of_points_by_return[5]; + double x_scale_factor; + double y_scale_factor; + double z_scale_factor; + double x_offset; + double y_offset; + double z_offset; + double max_x; + double min_x; + double max_y; + double min_y; + double max_z; + double min_z; + + int user_data_in_header_size; + char* user_data_in_header; + + LASvlr* vlrs; + LASvlr_geo_keys* vlr_geo_keys; + LASvlr_key_entry* vlr_geo_key_entries; + double* vlr_geo_double_params; + char* vlr_geo_ascii_params; + + int user_data_after_header_size; + char* user_data_after_header; + + LASheader() + { + for (int i = 0; i < sizeof(LASheader); i++) ((char*)this)[i] = 0; + file_signature[0] = 'L'; file_signature[1] = 'A'; file_signature[2] = 'S'; file_signature[3] = 'F'; + version_major = 1; + version_minor = 1; + header_size = 227; + offset_to_point_data = 227; + point_data_record_length = 20; + x_scale_factor = 0.01; + y_scale_factor = 0.01; + z_scale_factor = 0.01; + }; + + void clean_user_data_in_header() + { + if (user_data_in_header) + { + header_size -= user_data_in_header_size; + delete [] user_data_in_header; + user_data_in_header = 0; + user_data_in_header_size = 0; + } + }; + + void clean_vlrs() + { + if (vlrs) + { + unsigned i; + for (i = 0; i < number_of_variable_length_records; i++) + { + offset_to_point_data -= (54 + vlrs[i].record_length_after_header); + delete [] vlrs[i].data; + } + delete [] vlrs; + vlrs = 0; + vlr_geo_keys = 0; + vlr_geo_key_entries = 0; + vlr_geo_double_params = 0; + vlr_geo_ascii_params = 0; + number_of_variable_length_records = 0; + } + }; + + void clean_vlrs(int i) + { + if (i < (int)number_of_variable_length_records) + { + offset_to_point_data -= (54 + vlrs[i].record_length_after_header); + delete [] vlrs[i].data; + number_of_variable_length_records--; + if (number_of_variable_length_records) + { + vlrs[i] = vlrs[number_of_variable_length_records]; + } + } + }; + + void clean_user_data_after_header() + { + if (user_data_after_header) + { + offset_to_point_data -= user_data_after_header_size; + delete [] user_data_after_header; + user_data_after_header = 0; + user_data_after_header_size = 0; + } + }; + + void clean() + { + clean_user_data_in_header(); + clean_vlrs(); + clean_user_data_after_header(); + }; + + ~LASheader() + { + clean(); + }; +}; + +static const char * LASpointClassification [] = { + "Created, never classified", + "Unclassified", + "Ground", + "Low Vegetation", + "Medium Vegetation", + "High Vegetation", + "Building", + "Low Point (noise)", + "Model Key-point (mass point)", + "Water", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Overlap Points", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition", + "Reserved for ASPRS Definition" +}; + +#endif diff --git a/include/laspointreader.h b/include/laspointreader.h new file mode 100644 index 00000000..a81adffa --- /dev/null +++ b/include/laspointreader.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: LASpointReader.h + + CONTENTS: + + Common interface for the classes that read points raw or compressed. + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007-2008 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 22 February 2007 -- created about an hour before henna's birthday + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_H +#define LAS_POINT_READER_H + +#include "lasdefinitions.h" + +class LASpointReader +{ +public: + virtual bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0)=0; + virtual ~LASpointReader(){}; +}; + +#endif diff --git a/include/laspointreader0compressed.h b/include/laspointreader0compressed.h new file mode 100644 index 00000000..998ceeaf --- /dev/null +++ b/include/laspointreader0compressed.h @@ -0,0 +1,87 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader0compressed.h + + CONTENTS: + + Reads a point of type 0 (without gps_time) from our compressed LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 22 February 2007 -- created 45 minutes before henna's 32nd birthday + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_0COMPRESSED_H +#define LAS_POINT_READER_0COMPRESSED_H + +#include "laspointreader.h" + +#include "rangemodel.h" +#include "rangedecoder.h" +#include "integercompressor_newer.h" + +#include + +class LASpointReader0compressed : public LASpointReader +{ +public: + bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0); + LASpointReader0compressed(FILE* file); + ~LASpointReader0compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + void init_decoder(); + RangeDecoder* rd; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + RangeModel* rm_changed_values; + IntegerCompressorContext* ic_intensity; + RangeModel* rm_bit_byte; + RangeModel* rm_classification; + IntegerCompressorContext* ic_scan_angle_rank; + RangeModel* rm_user_data; + IntegerCompressorContext* ic_point_source_ID; +}; + +#endif diff --git a/include/laspointreader0raw.h b/include/laspointreader0raw.h new file mode 100644 index 00000000..04871b95 --- /dev/null +++ b/include/laspointreader0raw.h @@ -0,0 +1,68 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader0raw.h + + CONTENTS: + + Reads a point of type 0 (without gps_time) in standard LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 22 February 2007 -- created about an hour before henna's 32nd birthday + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_0RAW_H +#define LAS_POINT_READER_0RAW_H + +#include "laspointreader.h" + +#include + +class LASpointReader0raw : public LASpointReader +{ +public: + inline bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0) + { + return (fread(point, sizeof(LASpoint), 1, file) == 1); + }; + LASpointReader0raw(FILE* file){this->file = file;}; + ~LASpointReader0raw(){}; +private: + FILE* file; +}; + +#endif diff --git a/include/laspointreader1compressed.h b/include/laspointreader1compressed.h new file mode 100644 index 00000000..fea53602 --- /dev/null +++ b/include/laspointreader1compressed.h @@ -0,0 +1,92 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader1compressed.h + + CONTENTS: + + Reads a point of type 1 (with gps_time) from our compressed LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 23 February 2007 -- created 12 hours into henna's 32nd birthday + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_1COMPRESSED_H +#define LAS_POINT_READER_1COMPRESSED_H + +#include "laspointreader.h" + +#include "rangemodel.h" +#include "rangedecoder.h" +#include "integercompressor_newer.h" + +#include + +class LASpointReader1compressed : public LASpointReader +{ +public: + bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0); + LASpointReader1compressed(FILE* file); + ~LASpointReader1compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + double last_gps_time; + int last_gps_time_diff; + void init_decoder(); + RangeDecoder* rd; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + RangeModel* rm_changed_values; + IntegerCompressorContext* ic_intensity; + RangeModel* rm_bit_byte; + RangeModel* rm_classification; + IntegerCompressorContext* ic_scan_angle_rank; + RangeModel* rm_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_gps_time; + RangeModel** rm_gps_time_multi; + int multi_extreme_counter; +}; + +#endif diff --git a/include/laspointreader1raw.h b/include/laspointreader1raw.h new file mode 100644 index 00000000..3fc109d2 --- /dev/null +++ b/include/laspointreader1raw.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader1raw.h + + CONTENTS: + + Reads a point of type 1 (with gps_time) in standard LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 22 February 2007 -- created about an hour before henna's 32nd birthday + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_1RAW_H +#define LAS_POINT_READER_1RAW_H + +#include "laspointreader.h" + +#include + +class LASpointReader1raw : public LASpointReader +{ +public: + inline bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0) + { + fread(point, sizeof(LASpoint), 1, file); + return (fread(gps_time, sizeof(double), 1, file) == 1); + }; + LASpointReader1raw(FILE* file){this->file = file;}; + ~LASpointReader1raw(){}; +private: + FILE* file; +}; + +#endif diff --git a/include/laspointreader2compressed.h b/include/laspointreader2compressed.h new file mode 100644 index 00000000..220269f2 --- /dev/null +++ b/include/laspointreader2compressed.h @@ -0,0 +1,90 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader2compressed.h + + CONTENTS: + + Reads a point of type 2 (with rgb color) from our compressed LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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: + + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_2COMPRESSED_H +#define LAS_POINT_READER_2COMPRESSED_H + +#include "laspointreader.h" + +#include "rangemodel.h" +#include "rangedecoder.h" +#include "integercompressor_newer.h" + +#include + +class LASpointReader2compressed : public LASpointReader +{ +public: + bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0); + LASpointReader2compressed(FILE* file); + ~LASpointReader2compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + unsigned short last_rgb[3]; + void init_decoder(); + RangeDecoder* rd; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + RangeModel* rm_changed_values; + IntegerCompressorContext* ic_intensity; + RangeModel* rm_bit_byte; + RangeModel* rm_classification; + IntegerCompressorContext* ic_scan_angle_rank; + RangeModel* rm_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_r; + IntegerCompressorContext* ic_g; + IntegerCompressorContext* ic_b; +}; + +#endif diff --git a/include/laspointreader2raw.h b/include/laspointreader2raw.h new file mode 100644 index 00000000..42704a45 --- /dev/null +++ b/include/laspointreader2raw.h @@ -0,0 +1,68 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader2raw.h + + CONTENTS: + + Reads a point of type 2 (without gps_time but with rgb color) in LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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: + + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_2RAW_H +#define LAS_POINT_READER_2RAW_H + +#include "laspointreader.h" + +#include + +class LASpointReader2raw : public LASpointReader +{ +public: + inline bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0) + { + fread(point, sizeof(LASpoint), 1, file); + return (fread(rgb, sizeof(unsigned short), 3, file) == 3); + }; + LASpointReader2raw(FILE* file){this->file = file;}; + ~LASpointReader2raw(){}; +private: + FILE* file; +}; + +#endif diff --git a/include/laspointreader3compressed.h b/include/laspointreader3compressed.h new file mode 100644 index 00000000..141cd9d0 --- /dev/null +++ b/include/laspointreader3compressed.h @@ -0,0 +1,95 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader3compressed.h + + CONTENTS: + + Reads a point of type 3 (with gps_time and rgb color) from our compressed LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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: + + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_3COMPRESSED_H +#define LAS_POINT_READER_3COMPRESSED_H + +#include "laspointreader.h" + +#include "rangemodel.h" +#include "rangedecoder.h" +#include "integercompressor_newer.h" + +#include + +class LASpointReader3compressed : public LASpointReader +{ +public: + bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0); + LASpointReader3compressed(FILE* file); + ~LASpointReader3compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + double last_gps_time; + int last_gps_time_diff; + unsigned short last_rgb[3]; + void init_decoder(); + RangeDecoder* rd; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + RangeModel* rm_changed_values; + IntegerCompressorContext* ic_intensity; + RangeModel* rm_bit_byte; + RangeModel* rm_classification; + IntegerCompressorContext* ic_scan_angle_rank; + RangeModel* rm_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_gps_time; + RangeModel** rm_gps_time_multi; + int multi_extreme_counter; + IntegerCompressorContext* ic_r; + IntegerCompressorContext* ic_g; + IntegerCompressorContext* ic_b; +}; + +#endif diff --git a/include/laspointreader3raw.h b/include/laspointreader3raw.h new file mode 100644 index 00000000..f22ad696 --- /dev/null +++ b/include/laspointreader3raw.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader3raw.h + + CONTENTS: + + Reads a point of type 3 (with gps_time and rgb colors) in LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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: + + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_3RAW_H +#define LAS_POINT_READER_3RAW_H + +#include "laspointreader.h" + +#include + +class LASpointReader3raw : public LASpointReader +{ +public: + inline bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0) + { + fread(point, sizeof(LASpoint), 1, file); + fread(gps_time, sizeof(double), 1, file); + return (fread(rgb, sizeof(unsigned short), 3, file) == 3); + }; + LASpointReader3raw(FILE* file){this->file = file;}; + ~LASpointReader3raw(){}; +private: + FILE* file; +}; + +#endif diff --git a/include/laspointwriter.h b/include/laspointwriter.h new file mode 100644 index 00000000..9cd960f5 --- /dev/null +++ b/include/laspointwriter.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: LASpointWriter.h + + CONTENTS: + + Common interface for the two classes that write points raw or compressed. + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 21 February 2007 -- created after having the longest talk ever with my aunt + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_H +#define LAS_POINT_WRITER_H + +#include "lasdefinitions.h" + +class LASpointWriter +{ +public: + virtual bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0)=0; + virtual ~LASpointWriter(){}; +}; + +#endif diff --git a/include/laspointwriter0compressed.h b/include/laspointwriter0compressed.h new file mode 100644 index 00000000..91053b98 --- /dev/null +++ b/include/laspointwriter0compressed.h @@ -0,0 +1,87 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter0compressed.h + + CONTENTS: + + Writes a point of type 0 (without gps_time) in our compressed LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 21 February 2007 -- created after having the longest talk ever with my aunt + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_0COMPRESSED_H +#define LAS_POINT_WRITER_0COMPRESSED_H + +#include "laspointwriter.h" + +#include "rangemodel.h" +#include "rangeencoder.h" +#include "integercompressor_newer.h" + +#include + +class LASpointWriter0compressed : public LASpointWriter +{ +public: + bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0); + LASpointWriter0compressed(FILE* file); + ~LASpointWriter0compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + void init_encoder(); + RangeEncoder* re; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + RangeModel* rm_changed_values; + IntegerCompressorContext* ic_intensity; + RangeModel* rm_bit_byte; + RangeModel* rm_classification; + IntegerCompressorContext* ic_scan_angle_rank; + RangeModel* rm_user_data; + IntegerCompressorContext* ic_point_source_ID; +}; + +#endif diff --git a/include/laspointwriter0raw.h b/include/laspointwriter0raw.h new file mode 100644 index 00000000..43cd03a0 --- /dev/null +++ b/include/laspointwriter0raw.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter0raw.h + + CONTENTS: + + Writes a point of type 0 (without gps_time) in standard LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 21 February 2007 -- created after having the longest talk ever with my aunt + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_0RAW_H +#define LAS_POINT_WRITER_0RAW_H + +#include "laspointwriter.h" + +#include + +class LASpointWriter0raw : public LASpointWriter +{ +public: + inline bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0) + { + return (fwrite(point, sizeof(LASpoint), 1, file) == 1); + }; + + LASpointWriter0raw(FILE* file){this->file = file;}; + ~LASpointWriter0raw(){}; +private: + FILE* file; +}; + +#endif diff --git a/include/laspointwriter1compressed.h b/include/laspointwriter1compressed.h new file mode 100644 index 00000000..5f5dfe81 --- /dev/null +++ b/include/laspointwriter1compressed.h @@ -0,0 +1,92 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter1compressed.h + + CONTENTS: + + Writes a point of type 1 (with gps_time) in our compressed LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 21 February 2007 -- created after having the longest talk ever with my aunt + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_1COMPRESSED_H +#define LAS_POINT_WRITER_1COMPRESSED_H + +#include "laspointwriter.h" + +#include "rangemodel.h" +#include "rangeencoder.h" +#include "integercompressor_newer.h" + +#include + +class LASpointWriter1compressed : public LASpointWriter +{ +public: + bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0); + LASpointWriter1compressed(FILE* file); + ~LASpointWriter1compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + double last_gps_time; + int last_gps_time_diff; + void init_encoder(); + RangeEncoder* re; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + RangeModel* rm_changed_values; + IntegerCompressorContext* ic_intensity; + RangeModel* rm_bit_byte; + RangeModel* rm_classification; + IntegerCompressorContext* ic_scan_angle_rank; + RangeModel* rm_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_gps_time; + RangeModel** rm_gps_time_multi; + int multi_extreme_counter; +}; + +#endif diff --git a/include/laspointwriter1raw.h b/include/laspointwriter1raw.h new file mode 100644 index 00000000..45daa1dd --- /dev/null +++ b/include/laspointwriter1raw.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter1raw.h + + CONTENTS: + + Writes a point of type 1 (with gps_time) in standard LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 21 February 2007 -- created after having the longest talk ever with my aunt + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_1RAW_H +#define LAS_POINT_WRITER_1RAW_H + +#include "laspointwriter.h" + +#include + +class LASpointWriter1raw : public LASpointWriter +{ +public: + inline bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0) + { + fwrite(point, sizeof(LASpoint), 1, file); + return (fwrite(&(gps_time), sizeof(double), 1, file) == 1); + } + LASpointWriter1raw(FILE* file){this->file = file;}; + ~LASpointWriter1raw(){}; +private: + FILE* file; +}; + +#endif diff --git a/include/laspointwriter2compressed.h b/include/laspointwriter2compressed.h new file mode 100644 index 00000000..2b90aec1 --- /dev/null +++ b/include/laspointwriter2compressed.h @@ -0,0 +1,90 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter2compressed.h + + CONTENTS: + + Writes a point of type 2 (with rgb color) in our compressed LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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: + + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_2COMPRESSED_H +#define LAS_POINT_WRITER_2COMPRESSED_H + +#include "laspointwriter.h" + +#include "rangemodel.h" +#include "rangeencoder.h" +#include "integercompressor_newer.h" + +#include + +class LASpointWriter2compressed : public LASpointWriter +{ +public: + bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0); + LASpointWriter2compressed(FILE* file); + ~LASpointWriter2compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + unsigned short last_rgb[3]; + void init_encoder(); + RangeEncoder* re; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + RangeModel* rm_changed_values; + IntegerCompressorContext* ic_intensity; + RangeModel* rm_bit_byte; + RangeModel* rm_classification; + IntegerCompressorContext* ic_scan_angle_rank; + RangeModel* rm_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_r; + IntegerCompressorContext* ic_g; + IntegerCompressorContext* ic_b; +}; + +#endif diff --git a/include/laspointwriter2raw.h b/include/laspointwriter2raw.h new file mode 100644 index 00000000..5476768e --- /dev/null +++ b/include/laspointwriter2raw.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter2raw.h + + CONTENTS: + + Writes a point of type 2 (without gps_time but with rgb color) in LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007-2008 martin 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: + + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_2RAW_H +#define LAS_POINT_WRITER_2RAW_H + +#include "laspointwriter.h" + +#include + +class LASpointWriter2raw : public LASpointWriter +{ +public: + inline bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0) + { + fwrite(point, sizeof(LASpoint), 1, file); + return (fwrite(rgb, sizeof(unsigned short), 3, file) == 3); + }; + + LASpointWriter2raw(FILE* file){this->file = file;}; + ~LASpointWriter2raw(){}; +private: + FILE* file; +}; + +#endif diff --git a/include/laspointwriter3compressed.h b/include/laspointwriter3compressed.h new file mode 100644 index 00000000..b67a65e9 --- /dev/null +++ b/include/laspointwriter3compressed.h @@ -0,0 +1,95 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter3compressed.h + + CONTENTS: + + Writes a point of type 3 (with gps_time and rgb color) in our compressed LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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: + + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_3COMPRESSED_H +#define LAS_POINT_WRITER_3COMPRESSED_H + +#include "laspointwriter.h" + +#include "rangemodel.h" +#include "rangeencoder.h" +#include "integercompressor_newer.h" + +#include + +class LASpointWriter3compressed : public LASpointWriter +{ +public: + bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0); + LASpointWriter3compressed(FILE* file); + ~LASpointWriter3compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + double last_gps_time; + int last_gps_time_diff; + unsigned short last_rgb[3]; + void init_encoder(); + RangeEncoder* re; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + RangeModel* rm_changed_values; + IntegerCompressorContext* ic_intensity; + RangeModel* rm_bit_byte; + RangeModel* rm_classification; + IntegerCompressorContext* ic_scan_angle_rank; + RangeModel* rm_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_gps_time; + RangeModel** rm_gps_time_multi; + int multi_extreme_counter; + IntegerCompressorContext* ic_r; + IntegerCompressorContext* ic_g; + IntegerCompressorContext* ic_b; +}; + +#endif diff --git a/include/laspointwriter3raw.h b/include/laspointwriter3raw.h new file mode 100644 index 00000000..33c48b63 --- /dev/null +++ b/include/laspointwriter3raw.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter1raw.h + + CONTENTS: + + Writes a point of type 1 (with gps_time and rgb color) in LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007-2008 martin 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: + + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_3RAW_H +#define LAS_POINT_WRITER_3RAW_H + +#include "laspointwriter.h" + +#include + +class LASpointWriter3raw : public LASpointWriter +{ +public: + inline bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0) + { + fwrite(point, sizeof(LASpoint), 1, file); + fwrite(&(gps_time), sizeof(double), 1, file); + return (fwrite(rgb, sizeof(unsigned short), 3, file) == 3); + } + LASpointWriter3raw(FILE* file){this->file = file;}; + ~LASpointWriter3raw(){}; +private: + FILE* file; +}; + +#endif diff --git a/include/lasreader.h b/include/lasreader.h new file mode 100644 index 00000000..1b6eb8e2 --- /dev/null +++ b/include/lasreader.h @@ -0,0 +1,92 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: LASreader.h + + CONTENTS: + + Reads LIDAR points from the LAS format (Version 1.x , April 29, 2008). + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007-2008 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 18 February 2007 -- created after repairing 2 vacuum cleaners in the garden + +=============================================================================== +*/ +#ifndef LAS_READER_H +#define LAS_READER_H + +#include "lasdefinitions.h" +#include "laspointreader.h" + +#include + +class LASreader +{ +public: + LASheader header; + + LASpoint point; + double gps_time; + unsigned short rgb[3]; + + bool points_have_gps_time; + bool points_have_rgb; + + int npoints; + int p_count; + + int additional_bytes_per_point; + + bool open(FILE* file, bool skip_all_headers = false); + + bool read_point(); + bool read_point(float* coordinates); + bool read_point(double* coordinates); + + void get_coordinates(float* coordinates); + void get_coordinates(double* coordinates); + + void close(); + + LASreader(); + ~LASreader(); + +private: + FILE* file; + LASpointReader* pointReader; +}; + +#endif diff --git a/include/laswriter.h b/include/laswriter.h new file mode 100644 index 00000000..eaa8d257 --- /dev/null +++ b/include/laswriter.h @@ -0,0 +1,80 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: LASwriter.h + + CONTENTS: + + Writes LIDAR points to the LAS format (Version 1.x , April 29, 2008). + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007-2008 martin 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: + + 7 September 2008 -- updated to support LAS format 1.2 + 21 February 2007 -- created after eating Sarah's veggies with peanutsauce + +=============================================================================== +*/ +#ifndef LAS_WRITER_H +#define LAS_WRITER_H + +#include "lasdefinitions.h" +#include "laspointwriter.h" + +#include + +class LASwriter +{ +public: + int npoints; + int p_count; + + bool open(FILE* file, LASheader* header, int compression = 0); + + bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0); + bool write_point(double* coordinates); + bool write_point(double x, double y, double z); + + void close(); + + LASwriter(); + ~LASwriter(); + +private: + FILE* file; + LASpointWriter* pointWriter; + LASheader* header; + bool created_header; +}; + +#endif diff --git a/laszip-config.in b/laszip-config.in new file mode 100644 index 00000000..9bd01257 --- /dev/null +++ b/laszip-config.in @@ -0,0 +1,53 @@ +#!/bin/sh + + + +usage() +{ + cat <&2 +fi + +case $1 in + --libs) + echo @LIBS@ + ;; + + --defines) + echo @DEFS@ + ;; + + --includes) + echo + ;; + + --cflags) + echo @CFLAGS@ + ;; + + --cxxflags) + echo @CXXFLAGS@ + ;; + + --version) + echo @RELEASE_VERSION@ + ;; + + *) + usage 1 1>&2 + ;; + +esac diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..f79858de --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,19 @@ +SUBDIRS = alternate_coder_src . + +AM_CPPFLAGS = -I../include +noinst_LTLIBRARIES = liblibrary.la + +liblibrary_la_SOURCES = integercompressor_newer.cpp \ + laspointreader0compressed.cpp \ + laspointreader1compressed.cpp \ + laspointreader2compressed.cpp \ + laspointwriter0compressed.cpp \ + laspointwriter1compressed.cpp \ + laspointwriter2compressed.cpp \ + lasreader.cpp \ + laswriter.cpp \ + rangedecoder.cpp \ + rangeencoder.cpp \ + rangemodel.cpp + +#liblibrary_la_LIBADD = src/alternate_coder_src/liblaszip_alternate.la diff --git a/src/alternate_coder_src/Makefile.am b/src/alternate_coder_src/Makefile.am new file mode 100644 index 00000000..e49c9e00 --- /dev/null +++ b/src/alternate_coder_src/Makefile.am @@ -0,0 +1,14 @@ + +AM_CPPFLAGS = -I../../include -I.. + +noinst_LTLIBRARIES = liblaszip_alternate.la +liblaszip_alternate_la_SOURCES = arithmeticdecoder.cpp \ + arithmeticencoder.cpp \ + arithmeticmodel.cpp \ + integercompressor_newest.cpp \ + laspointreader0compressed.cpp \ + laspointreader1compressed.cpp \ + laspointreader2compressed.cpp \ + laspointwriter0compressed.cpp \ + laspointwriter1compressed.cpp \ + laspointwriter2compressed.cpp \ No newline at end of file diff --git a/src/alternate_coder_src/arithmeticdecoder.cpp b/src/alternate_coder_src/arithmeticdecoder.cpp new file mode 100644 index 00000000..fecaeb73 --- /dev/null +++ b/src/alternate_coder_src/arithmeticdecoder.cpp @@ -0,0 +1,288 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: arithmeticdecoder.cpp + + CONTENTS: + + see header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2009 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 +#include +#include +#include + + + +#include "arithmeticdecoder.h" + + +namespace laszipalternate { + +ArithmeticDecoder::ArithmeticDecoder(unsigned char* bytes, unsigned int number_bytes) +{ + inbuffer = bytes; + endbuffer = bytes + number_bytes; + fp = 0; + + /* + if ((value = get_inbyte()) != AC_HEADER_BYTE) + { + fprintf(stderr, "ArithmeticDecoder: wrong AC_HEADER_BYTE of %d. is should be %d\n", value, AC_HEADER_BYTE); + return; + } + */ + + length = AC__MaxLength; + value = (get_inbyte() << 24); + value |= (get_inbyte() << 16); + value |= (get_inbyte() << 8); + value |= (get_inbyte()); +} + +ArithmeticDecoder::ArithmeticDecoder(FILE* fp) +{ + inbuffer = 0; + endbuffer = 0; + this->fp = fp; + +/* + if ((value = get_inbyte()) != AC_HEADER_BYTE) + { + fprintf(stderr, "ArithmeticDecoder: wrong AC_HEADER_BYTE of %d. is should be %d\n", value, AC_HEADER_BYTE); + return; + } +*/ + + length = AC__MaxLength; + value = (get_inbyte() << 24); + value |= (get_inbyte() << 16); + value |= (get_inbyte() << 8); + value |= (get_inbyte()); +} + +unsigned int ArithmeticDecoder::decode(ArithmeticBitModel* m) +{ + unsigned int x = m->bit_0_prob * (length >> BM__LengthShift); // product l x p0 + unsigned int 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 +} + +unsigned int ArithmeticDecoder::decode(ArithmeticModel* m) +{ + unsigned 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 + unsigned int 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; + unsigned int k = (n = m->data_symbols) >> 1; + // decode via bisection search + do { + unsigned int 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(false); // periodic model update + + return sym; +} + +unsigned int ArithmeticDecoder::readBits(unsigned int bits) +{ + assert(bits && (bits <= 32)); + + if (bits > 20) + { + unsigned int tmp = readShort(); + bits = bits - 16; + unsigned int tmp1 = readBits(bits) << 16; + return (tmp1|tmp); + } + + unsigned int sym = value / (length >>= bits);// decode symbol, change length + value -= length * sym; // update interval + + if (length < AC__MinLength) renorm_dec_interval(); // renormalization + + return sym; +} + +unsigned char ArithmeticDecoder::readByte() +{ + unsigned int sym = value / (length >>= 8); // decode symbol, change length + value -= length * sym; // update interval + + if (length < AC__MinLength) renorm_dec_interval(); // renormalization + + assert(sym < (1<<8)); + + return (unsigned char)sym; +} + +unsigned short ArithmeticDecoder::readShort() +{ + unsigned int sym = value / (length >>= 16); // decode symbol, change length + value -= length * sym; // update interval + + if (length < AC__MinLength) renorm_dec_interval(); // renormalization + + assert(sym < (1<<16)); + + return (unsigned short)sym; +} + +unsigned int ArithmeticDecoder::readInt() +{ + unsigned int lowerInt = readShort(); + unsigned int upperInt = readShort(); + return upperInt*65536+lowerInt; +} + +float ArithmeticDecoder::readFloat() +{ + float f; + *((unsigned int*)(&f)) = readInt(); + return f; +} + +U64 ArithmeticDecoder::readInt64() +{ + U64 lowerInt = readInt(); + U64 upperInt = readInt(); + return upperInt*4294967296+lowerInt; +} + +double ArithmeticDecoder::readDouble() +{ + double d; + *((U64*)(&d)) = readInt64(); + return d; +} + +void ArithmeticDecoder::done() +{ +} + +ArithmeticDecoder::~ArithmeticDecoder() +{ +} + +inline void ArithmeticDecoder::renorm_dec_interval() +{ + do { // read least-significant byte + value = (value << 8) | get_inbyte(); + } while ((length <<= 8) < AC__MinLength); // length multiplied by 256 +} + +int read_bytes = 0; + +inline unsigned int ArithmeticDecoder::get_inbyte() +{ + unsigned int c; + if (fp) + { + read_bytes++; + c = getc(fp); + if (c == EOF) + { + c = 0; + } + } + else + { + if (inbuffer == endbuffer) + { + c = 0; + } + else + { + c = *inbuffer++; + } + } + return c; +} + +} \ No newline at end of file diff --git a/src/alternate_coder_src/arithmeticdecoder.h b/src/alternate_coder_src/arithmeticdecoder.h new file mode 100644 index 00000000..e46d99be --- /dev/null +++ b/src/alternate_coder_src/arithmeticdecoder.h @@ -0,0 +1,109 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: arithmeticdecoder.h + + CONTENTS: + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2009 martin 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: + + 30 October 2009 -- merged michael schindler's and amir said's code + +=============================================================================== +*/ +#ifndef ARITHMETIC_DECODER_H +#define ARITHMETIC_DECODER_H + + + +#include "mydefs.h" +#include + +#include "arithmeticmodel.h" + +namespace laszipalternate { + +class ArithmeticDecoder +{ +public: + +/* Start the decoder */ + ArithmeticDecoder(unsigned char* chars, unsigned int number_chars); + ArithmeticDecoder(FILE* fp); + ~ArithmeticDecoder(); + +/* Decode a bit with modelling */ + unsigned int decode(ArithmeticBitModel* m); + +/* Decode s symbol with modelling */ + unsigned int decode(ArithmeticModel* m); + +/* Decode bits without modelling */ + unsigned int readBits(unsigned int bits); + +/* Decode an unsigned char without modelling */ + unsigned char readByte(); + +/* Decode an unsigned short without modelling */ + unsigned short readShort(); + +/* Decode an unsigned int without modelling */ + unsigned int readInt(); + +/* Decode a float without modelling (endian-ness dependent) */ + float readFloat(); + +/* Decode an unsigned int64 without modelling */ + U64 readInt64(); + +/* Decode a double without modelling */ + double readDouble(); + +/* Finish decoding */ + void done(); + +private: + + unsigned int get_inbyte(); + void renorm_dec_interval(); + + FILE* fp; + + unsigned char* inbuffer; + unsigned char* endbuffer; + unsigned int base, value, length; +}; + +} //namespace +#endif diff --git a/src/alternate_coder_src/arithmeticencoder.cpp b/src/alternate_coder_src/arithmeticencoder.cpp new file mode 100644 index 00000000..213f8f32 --- /dev/null +++ b/src/alternate_coder_src/arithmeticencoder.cpp @@ -0,0 +1,307 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: arithmeticencoder.cpp + + CONTENTS: + + see header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2009 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 "arithmeticencoder.h" + +#include +#include +#include + + +namespace laszipalternate { + +ArithmeticEncoder::ArithmeticEncoder(FILE* fp, int store_bytes) +{ + if (fp || store_bytes == 0) + { + this->fp = fp; + this->store_bytes = false; + outbuffer = (unsigned char*)malloc(sizeof(unsigned char)*2*AC_BUFFER_SIZE); + endbuffer = outbuffer + 2 * AC_BUFFER_SIZE; + } + else + { + this->fp = 0; + this->store_bytes = true; + outbuffer = (unsigned char*)malloc(sizeof(unsigned char)*store_bytes); + endbuffer = outbuffer + store_bytes; + } + this->fp = fp; + outbyte = outbuffer; + endbyte = endbuffer; + bytes_output = 0; + base = 0; + length = AC__MaxLength; +} + +void ArithmeticEncoder::encode(ArithmeticBitModel* m, unsigned int sym) +{ + assert(m && (sym <= 1)); + + unsigned int x = m->bit_0_prob * (length >> BM__LengthShift); // product l x p0 + // update interval + if (sym == 0) { + length = x; + ++m->bit_0_count; + } + else { + unsigned int 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::encode(ArithmeticModel* m, unsigned int sym) +{ + assert(m && (sym <= m->last_symbol)); + + unsigned int 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(true); // periodic model update +} + +void ArithmeticEncoder::writeBits(unsigned int bits, unsigned int sym) +{ + assert(bits && (bits <= 32) && (sym < (1u< 19) + { + writeShort(sym&65535); + sym = sym >> 16; + bits = bits - 16; + } + + unsigned 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(unsigned char c) +{ + unsigned int init_base = base; + base += (unsigned int)(c) * (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(unsigned short s) +{ + unsigned int init_base = base; + base += (unsigned int)(s) * (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(unsigned int i) +{ + writeShort((unsigned short)(i % 65536)); // lower 16 bits + writeShort((unsigned short)(i / 65536)); // UPPER 16 bits +} + +void ArithmeticEncoder::writeInt64(U64 l) +{ + writeInt((unsigned int)(l % 4294967296)); // lower 32 bits + writeInt((unsigned int)(l / 4294967296)); // UPPER 32 bits +} + +void ArithmeticEncoder::writeFloat(float f) +{ + writeInt(*((unsigned int*)(&f))); +} + +void ArithmeticEncoder::writeDouble(double d) +{ + writeInt64(*((U64*)(&d))); +} + +unsigned int ArithmeticEncoder::done() +{ + unsigned int init_base = base; // done encoding: set final data bytes + + 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 + } + + if (init_base > base) propagate_carry(); // overflow = carry + renorm_enc_interval(); // renormalization = output last bytes + + if (fp) + { + if (endbyte != endbuffer) + { + assert(outbyte < outbuffer + AC_BUFFER_SIZE); + fwrite(outbuffer + AC_BUFFER_SIZE, 1, AC_BUFFER_SIZE, fp); + bytes_output += AC_BUFFER_SIZE; + } + unsigned int buffer_size = outbyte - outbuffer; + fwrite(outbuffer, 1, buffer_size, fp); + bytes_output += buffer_size; + } + else if (store_bytes == false) + { + bytes_output += (outbyte - outbuffer); + } + + return getNumberBytes(); // number of bytes used +} + +ArithmeticEncoder::~ArithmeticEncoder() +{ +// free(outbuffer); +} + +unsigned char* ArithmeticEncoder::getBytes() +{ + if (store_bytes) + return outbuffer; + else + return 0; +} + +unsigned int ArithmeticEncoder::getNumberBytes() +{ + if (store_bytes) + return outbyte - outbuffer; + else + return bytes_output; +} + +int max_carry = 0; + +inline void ArithmeticEncoder::propagate_carry() +{ + int carry = 0; + unsigned char * 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); + carry++; + } + ++*p; + if (carry > max_carry) max_carry = carry; +} + +inline void ArithmeticEncoder::renorm_enc_interval() +{ + do { // output and discard top byte + assert(outbuffer <= outbyte); + assert(outbyte < endbuffer); + assert(outbyte < endbyte); + *outbyte++ = (unsigned char)(base >> 24); + if (outbyte == endbyte) manage_outbuffer(); + base <<= 8; + } while ((length <<= 8) < AC__MinLength); // length multiplied by 256 +} + +inline void ArithmeticEncoder::manage_outbuffer() +{ + if (fp) + { + if (outbyte == endbuffer) outbyte = outbuffer; + fwrite(outbyte, 1, AC_BUFFER_SIZE, fp); + bytes_output += AC_BUFFER_SIZE; + endbyte = outbyte + AC_BUFFER_SIZE; + assert(endbyte > outbyte); + assert(outbyte < endbuffer); + } + else if (store_bytes) + { + unsigned int buffer_size = endbyte - outbuffer; + unsigned char* newbuffer = (unsigned char*) malloc(sizeof(unsigned char)*buffer_size*2); + memcpy(newbuffer,outbuffer,sizeof(unsigned char)*buffer_size); + free(outbuffer); + outbuffer = newbuffer; + endbuffer = newbuffer + buffer_size * 2; + outbyte = outbuffer + buffer_size; + endbyte = endbuffer; + } + else + { + bytes_output += 2 * AC_BUFFER_SIZE; + outbyte = outbuffer; + } +} + +} \ No newline at end of file diff --git a/src/alternate_coder_src/arithmeticencoder.h b/src/alternate_coder_src/arithmeticencoder.h new file mode 100644 index 00000000..ec604fa4 --- /dev/null +++ b/src/alternate_coder_src/arithmeticencoder.h @@ -0,0 +1,113 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: arithmeticencoder.h + + CONTENTS: + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2009 martin 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: + + 30 October 2009 -- merged michael schindler's and amir said's code + +=============================================================================== +*/ +#ifndef ARITHMETIC_ENCODER_H +#define ARITHMETIC_ENCODER_H + + +#include "mydefs.h" +#include "arithmeticmodel.h" +#include + +namespace laszipalternate { + +class ArithmeticEncoder +{ +public: + +/* Start the encoder */ + ArithmeticEncoder(FILE* fp, int store_bytes = 0); + ~ArithmeticEncoder(); + +/* Encode bit with modelling */ + void encode(ArithmeticBitModel* m, unsigned int sym); + +/* Encode symbol with modelling */ + void encode(ArithmeticModel* m, unsigned int sym); + +/* Encode bits without modelling */ + void writeBits(unsigned int bits, unsigned int sym); + +/* Encode an unsigned char without modelling */ + void writeByte(unsigned char b); + +/* Encode an unsigned short without modelling */ + void writeShort(unsigned short s); + +/* Encode an unsigned int without modelling */ + void writeInt(unsigned int i); + +/* Encode a float without modelling */ + void writeFloat(float f); + +/* Encode an unsigned int64 without modelling */ + void writeInt64(U64 l); + +/* Encode a double without modelling */ + void writeDouble(double d); + +/* Finish encoding, returns number of bytes written */ + unsigned int done(); + + unsigned char* getBytes(); + unsigned int getNumberBytes(); + +private: + void propagate_carry(); + void renorm_enc_interval(); + void manage_outbuffer(); + + FILE* fp; + bool store_bytes; + + unsigned char* outbuffer; + unsigned char* endbuffer; + unsigned char* outbyte; + unsigned char* endbyte; + unsigned int bytes_output; + unsigned int base, value, length; +}; + +} +#endif diff --git a/src/alternate_coder_src/arithmeticmodel.cpp b/src/alternate_coder_src/arithmeticmodel.cpp new file mode 100644 index 00000000..0d86572f --- /dev/null +++ b/src/alternate_coder_src/arithmeticmodel.cpp @@ -0,0 +1,178 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: arithmeticmodel.cpp + + CONTENTS: + + see header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2009 martin 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 "arithmeticmodel.h" + +#include +#include + + +void AC_ERROR(const char* msg) { + fprintf(stderr, "Arithmetic coding ERROR: %s\n", msg); exit(1); +} + +namespace laszipalternate { + +ArithmeticModel::ArithmeticModel(unsigned int n, unsigned int *init, int compress) +{ + data_symbols = 0; + distribution = 0; + reset(n, init, compress); +} + +ArithmeticModel::~ArithmeticModel() +{ + if (distribution) delete [] distribution; +} + +void ArithmeticModel::reset(unsigned int n, unsigned int *init, int compress) +{ + if ( (n < 2) || (n > (1 << 11)) ) AC_ERROR("invalid number of symbols"); + + if (data_symbols != n) { + data_symbols = n; + last_symbol = data_symbols - 1; + if (distribution) delete [] distribution; + // define size of table for fast decoding + if ((compress == 0) && (data_symbols > 16)) { + unsigned int table_bits = 3; + while (data_symbols > (1U << (table_bits + 2))) ++table_bits; + table_size = 1 << table_bits; + table_shift = DM__LengthShift - table_bits; + distribution = new unsigned int[2*data_symbols+table_size+2]; + decoder_table = distribution + 2 * data_symbols; + } + else { // small alphabet: no table needed + decoder_table = 0; + table_size = table_shift = 0; + distribution = new unsigned int[2*data_symbols]; + } + if (distribution == 0) AC_ERROR("cannot allocate model memory"); + symbol_count = distribution + data_symbols; + } + + total_count = 0; + update_cycle = data_symbols; + if (init) + for (unsigned int k = 0; k < data_symbols; k++) symbol_count[k] = init[k]; + else + for (unsigned int k = 0; k < data_symbols; k++) symbol_count[k] = 1; + + update(compress == 1); + symbols_until_update = update_cycle = (data_symbols + 6) >> 1; +} + +void ArithmeticModel::update(bool from_encoder) +{ + // halve counts when a threshold is reached + if ((total_count += update_cycle) > DM__MaxCount) { + total_count = 0; + for (unsigned int n = 0; n < data_symbols; n++) + total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1); + } + // compute cumulative distribution, decoder table + unsigned int k, sum = 0, s = 0; + unsigned int scale = 0x80000000U / total_count; + + if (from_encoder || (table_size == 0)) + for (k = 0; k < data_symbols; k++) { + distribution[k] = (scale * sum) >> (31 - DM__LengthShift); + sum += symbol_count[k]; + } + else { + for (k = 0; k < data_symbols; k++) { + distribution[k] = (scale * sum) >> (31 - DM__LengthShift); + sum += symbol_count[k]; + unsigned int w = distribution[k] >> table_shift; + while (s < w) decoder_table[++s] = k - 1; + } + decoder_table[0] = 0; + while (s <= table_size) decoder_table[++s] = data_symbols - 1; + } + // set frequency of model updates + update_cycle = (5 * update_cycle) >> 2; + unsigned int max_cycle = (data_symbols + 6) << 3; + if (update_cycle > max_cycle) update_cycle = max_cycle; + symbols_until_update = update_cycle; +} + +ArithmeticBitModel::ArithmeticBitModel() +{ + reset(); +} + +ArithmeticBitModel::~ArithmeticBitModel() +{ +} + +void ArithmeticBitModel::reset() +{ + // initialization to equiprobable model + bit_0_count = 1; + bit_count = 2; + bit_0_prob = 1U << (BM__LengthShift - 1); + update_cycle = bits_until_update = 4; // start with frequent updates +} + +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 + unsigned int 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; +} + +} \ No newline at end of file diff --git a/src/alternate_coder_src/arithmeticmodel.h b/src/alternate_coder_src/arithmeticmodel.h new file mode 100644 index 00000000..4f2fa07e --- /dev/null +++ b/src/alternate_coder_src/arithmeticmodel.h @@ -0,0 +1,103 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: arithmeticmodel.h + + CONTENTS: + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2009 martin 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: + + 30 October 2009 -- merged michael schindler's and amir said's code + +=============================================================================== +*/ +#ifndef ARITHMETIC_MODEL_H +#define ARITHMETIC_MODEL_H + + +namespace laszipalternate { + +/* this header byte needs to change in case incompatible change happen */ +#define AC_HEADER_BYTE 2 +#define AC_BUFFER_SIZE 1024 + +void AC_ERROR(const char* msg); + +const unsigned AC__MinLength = 0x01000000U; // threshold for renormalization +const unsigned AC__MaxLength = 0xFFFFFFFFU; // maximum AC interval length + + // Maximum values for binary models +const unsigned BM__LengthShift = 13; // length bits discarded before mult. +const unsigned BM__MaxCount = 1 << BM__LengthShift; // for adaptive models + + // Maximum values for general models +const unsigned DM__LengthShift = 15; // length bits discarded before mult. +const unsigned DM__MaxCount = 1 << DM__LengthShift; // for adaptive models + +class ArithmeticModel +{ +public: + ArithmeticModel(unsigned int n, unsigned int *init, int compress); + ~ArithmeticModel(); + + void reset(unsigned int n, unsigned int *init, int compress); + +private: + void update(bool); + unsigned int * distribution, * symbol_count, * decoder_table; + unsigned int total_count, update_cycle, symbols_until_update; + unsigned int data_symbols, last_symbol, table_size, table_shift; + friend class ArithmeticEncoder; + friend class ArithmeticDecoder; +}; + +class ArithmeticBitModel +{ +public: + ArithmeticBitModel(); + ~ArithmeticBitModel(); + + void reset(); + +private: + void update(); + unsigned int update_cycle, bits_until_update; + unsigned int bit_0_prob, bit_0_count, bit_count; + friend class ArithmeticEncoder; + friend class ArithmeticDecoder; +}; + +} + +#endif diff --git a/src/alternate_coder_src/integercompressor_newest.cpp b/src/alternate_coder_src/integercompressor_newest.cpp new file mode 100644 index 00000000..99fa38b4 --- /dev/null +++ b/src/alternate_coder_src/integercompressor_newest.cpp @@ -0,0 +1,567 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: integercompressor_newest.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2009 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "integercompressor_newest.h" + +#define COMPRESS_ONLY_K +//#undef COMPRESS_ONLY_K + +#define CREATE_HISTOGRAMS +#undef CREATE_HISTOGRAMS + +#include +#include + +#ifdef CREATE_HISTOGRAMS +#include +#endif + +namespace laszipalternate { + +IntegerCompressorContext::IntegerCompressorContext() +{ + bits = 16; + range = 0; + + last = 0; + + enc = 0; + dec = 0; + + mBitsNone = 0; + mBitsLast = 0; + + mCorrector = 0; +} + +IntegerCompressorContext::~IntegerCompressorContext() +{ + int i; + if (mBitsNone) delete mBitsNone; + if (mBitsLast) + { + for (i = 0; i < contexts; i++) + { + delete mBitsLast[i]; + } + free(mBitsLast); + } + if (mCorrector) + { + delete (ArithmeticBitModel*)mCorrector[0]; + for (i = 1; i <= corr_bits; i++) + { + delete mCorrector[i]; + } + free(mCorrector); + } +} + +void IntegerCompressorContext::SetupCompressor(ArithmeticEncoder* enc, int contexts, int bits_high) +{ + int i; + + this->enc = enc; + this->contexts = contexts; + this->bits_high = bits_high; + + // the corrector's significant bits and range + + if (range) + { + corr_bits = 0; + corr_range = range; + while (range) + { + range = range >> 1; + corr_bits++; + } + if (corr_range == (1 << (corr_bits-1))) + { + corr_bits--; + } + // the corrector must fall into this interval + corr_min = -(corr_range/2); + } + else if (bits && bits < 32) + { + corr_bits = bits; + corr_range = 1 << bits; + // the corrector must fall into this interval + corr_min = -(corr_range/2); + } + else + { + corr_bits = 32; + corr_range = 0; + // the corrector must fall into this interval + corr_min = -(1 << 31); + } + corr_max = corr_min + corr_range - 1; + + // allocate the arithmetic range tables + + mBitsNone = new ArithmeticModel(corr_bits+1,0,1); + mBitsLast = (ArithmeticModel**)malloc(sizeof(ArithmeticModel*) * (contexts)); + for (i = 0; i < contexts; i++) + { + mBitsLast[i] = new ArithmeticModel(corr_bits+1,0,1); + } + +#if defined(COMPRESS_ONLY_K) + mCorrector = 0; +#else + mCorrector = (ArithmeticModel**)malloc(sizeof(ArithmeticModel*) * (corr_bits+1)); + mCorrector[0] = (ArithmeticModel*) new ArithmeticBitModel(); + for (i = 1; i <= corr_bits; i++) + { + if (i <= bits_high) + { + mCorrector[i] = new ArithmeticModel((1<dec = dec; + this->contexts = contexts; + this->bits_high = bits_high; + + // the corrector's significant bits and range + + if (range) + { + corr_bits = 0; + corr_range = range; + while (range) + { + range = range >> 1; + corr_bits++; + } + if (corr_range == (1 << (corr_bits-1))) + { + corr_bits--; + } + // the corrector must fall into this interval + corr_min = -(corr_range/2); + } + else if (bits && bits < 32) + { + corr_bits = bits; + corr_range = 1 << bits; + // the corrector must fall into this interval + corr_min = -(corr_range/2); + } + else + { + corr_bits = 32; + corr_range = 0; + // the corrector must fall into this interval + corr_min = -(1 << 31); + } + corr_max = corr_min + corr_range - 1; + + // allocate the arithmetic range tables + + mBitsNone = new ArithmeticModel(corr_bits+1,0,0); + mBitsLast = (ArithmeticModel**)malloc(sizeof(ArithmeticModel*) * (contexts)); + for (i = 0; i < contexts; i++) + { + mBitsLast[i] = new ArithmeticModel(corr_bits+1,0,0); + } + +#if defined(COMPRESS_ONLY_K) + mCorrector = 0; +#else + mCorrector = (ArithmeticModel**)malloc(sizeof(ArithmeticModel*) * (corr_bits+1)); + mCorrector[0] = (ArithmeticModel*) new ArithmeticBitModel(); + for (i = 1; i <= corr_bits; i++) + { + if (i <= bits_high) + { + mCorrector[i] = new ArithmeticModel((1<> 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->encode(mBits, k); + +#ifdef COMPRESS_ONLY_K + if (k) // then c is either smaller than 0 or bigger than 1 + { + assert((c != 0) && (c != 1)); + // 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->writeBits(1,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)); + // 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<encode(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->encode(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->encode((ArithmeticBitModel*)mCorrector[0],c); + } +#endif // COMPRESS_ONLY_K + return k; +} + +I32 IntegerCompressorContext::CompressNone(I32 real) +{ + // the corrector will be within the interval [ - (corr_range - 1) ... + (corr_range - 1) ] + int corr = real - last; + // 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; + last = real; + return writeCorrector(corr, mBitsNone); +} + +I32 IntegerCompressorContext::CompressLast(I32 pred, I32 real, int context) +{ + // the corrector will be within the interval [ - (corr_range - 1) ... + (corr_range - 1) ] + int corr = real - pred; + // we fold the corrector into the interval [ corr_min ... corr_max ] + if (corr < corr_min) corr += corr_range; + else if (corr > corr_max) corr -= corr_range; + last = real; + return writeCorrector(corr, mBitsLast[context]); +} + +I32 IntegerCompressorContext::readCorrector(ArithmeticModel* mBits) +{ + I32 c; + + // decode within which interval the corrector is falling + + int k = dec->decode(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 + { + 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<readBits(1); + } +#else // COMPRESS_ONLY_K + if (k) // then c is either smaller than 0 or bigger than 1 + { + if (k <= bits_high) // for small k we can do this in one step + { + // decompress c with the range coder + c = dec->decode(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->decode(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<decode((ArithmeticBitModel*)mCorrector[0]); + } +#endif // COMPRESS_ONLY_K + + return c; +} + +I32 IntegerCompressorContext::DecompressNone() +{ + I32 real = last + readCorrector(mBitsNone); + if (real < 0) real += corr_range; + else if (real >= corr_range) real -= corr_range; + last = real; + return real; +} + +I32 IntegerCompressorContext::DecompressLast(I32 pred, int context) +{ + I32 real = pred + readCorrector(mBitsLast[context]); + if (real < 0) real += corr_range; + else if (real >= corr_range) real -= corr_range; + last = real; + return real; +} + +} \ No newline at end of file diff --git a/src/alternate_coder_src/integercompressor_newest.h b/src/alternate_coder_src/integercompressor_newest.h new file mode 100644 index 00000000..3f43d0c0 --- /dev/null +++ b/src/alternate_coder_src/integercompressor_newest.h @@ -0,0 +1,140 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: integercompressor_newest.h + + 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. Two of the encoding functions + take a integer prediction as input. The other will predict the integer + simply using the last integer that was encoded. + + 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@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2005 martin 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: + + 31 October 2009 -- switched from the Rangecoder to the Arithmeticcoder + 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_NEWEST_H +#define INTEGER_COMPRESSOR_NEWEST_H + +#include "mydefs.h" + +#include "arithmeticencoder.h" +#include "arithmeticdecoder.h" + +namespace laszipalternate { + +class IntegerCompressorContext +{ +public: + + // SetPrecision: + void SetPrecision(I32 iBits); + // GetPrecision: + I32 GetPrecision(); + + // SetRange: + void SetRange(I32 iRange); + // GetRange: + I32 GetRange(); + + // SetupCompressor: + void SetupCompressor(ArithmeticEncoder* enc, int contexts=1, int BITS_HIGH=8); + void FinishCompressor(); + + // Compress: + I32 CompressNone(I32 iReal); + I32 CompressLast(I32 iPred, I32 iReal, int context=0); + + // SetupDecompressor: + void SetupDecompressor(ArithmeticDecoder* dec, int contexts=1, int BITS_HIGH=8); + void FinishDecompressor(); + + // Deompress: + I32 DecompressNone(); + I32 DecompressLast(I32 iPred, int context=0); + + // Constructor: + IntegerCompressorContext(); + // Destructor: + ~IntegerCompressorContext(); + +private: + // Private Functions + I32 writeCorrector(I32 c, ArithmeticModel* mBits); + I32 readCorrector(ArithmeticModel* mBits); + + int contexts; + int bits_high; + + // Private Variables + int bits; + int range; + + int corr_bits; + int corr_range; + int corr_max; + int corr_min; + + int last; + + ArithmeticEncoder* enc; + ArithmeticDecoder* dec; + + ArithmeticModel* mBitsNone; + ArithmeticModel** mBitsLast; + + ArithmeticModel** mCorrector; + + int** corr_histogram; +}; + +} + +#endif diff --git a/src/alternate_coder_src/laspointreader0compressed.cpp b/src/alternate_coder_src/laspointreader0compressed.cpp new file mode 100644 index 00000000..a76d3e88 --- /dev/null +++ b/src/alternate_coder_src/laspointreader0compressed.cpp @@ -0,0 +1,246 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader0compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointreader0compressed.h" + +namespace laszipalternate { + +bool LASpointReader0compressed::read_point(LASpoint* point, double* gps_time, unsigned short* rgb) +{ + if (dec) + { + *point = last_point; + + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // decompress x y z coordinates + int x_diff = ic_dx->DecompressLast(median_x, last_dir); + point->x += x_diff; + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + int y_diff; + if (messy < 0 || messy > 6) + { + y_diff = ic_dy->DecompressNone(); + point->z = ic_z->DecompressNone(); + } + else + { + y_diff = ic_dy->DecompressLast(median_y, (last_dir?messy+7:messy)); + point->z = ic_z->DecompressLast(last_point.z, messy); + } + point->y += y_diff; + + // decompress which other values have changed + int changed_values = dec->decode(m_changed_values); + + // decompress the intensity if it has changed + if (changed_values & 32) + { + point->intensity = ic_intensity->DecompressLast(last_point.intensity); + } + + // decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + ((unsigned char*)point)[14] = dec->decode(m_bit_byte); + } + + // decompress the classification ... if it has changed + if (changed_values & 8) + { + point->classification = dec->decode(m_classification); + } + + // decompress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + point->scan_angle_rank = ic_scan_angle_rank->DecompressLast(last_point.scan_angle_rank, messy == 2); // this is the best messy + } + + // decompress the user_data ... if it has changed + if (changed_values & 2) + { + point->user_data = dec->decode(m_user_data); + } + + // decompress the point_source_ID ... if it has changed + if (changed_values & 1) + { + point->point_source_ID = ic_point_source_ID->DecompressLast(last_point.point_source_ID); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fread(point, sizeof(LASpoint), 1, file); + init_decoder(); + } + last_dir = point->scan_direction_flag; + last_point = *point; + + return true; +} + +LASpointReader0compressed::LASpointReader0compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + dec = 0; +} + +void LASpointReader0compressed::init_decoder() +{ + dec = new ArithmeticDecoder(file); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupDecompressor(dec, 2); + ic_dy->SetupDecompressor(dec, 14); + ic_z->SetupDecompressor(dec, 7); + + m_changed_values = new ArithmeticModel(64,0,0); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupDecompressor(dec); + + m_bit_byte = new ArithmeticModel(256,0,0); + m_classification = new ArithmeticModel(256,0,0); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupDecompressor(dec, 2); + + m_user_data = new ArithmeticModel(256,0,0); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupDecompressor(dec); +} + +LASpointReader0compressed::~LASpointReader0compressed() +{ + if (dec) + { + dec->done(); + + delete dec; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete m_changed_values; + delete ic_intensity; + delete m_bit_byte; + delete m_classification; + delete ic_scan_angle_rank; + delete m_user_data; + delete ic_point_source_ID; + } +} + +} \ No newline at end of file diff --git a/src/alternate_coder_src/laspointreader0compressed.h b/src/alternate_coder_src/laspointreader0compressed.h new file mode 100644 index 00000000..98512d14 --- /dev/null +++ b/src/alternate_coder_src/laspointreader0compressed.h @@ -0,0 +1,91 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader0compressed.h + + CONTENTS: + + Reads a point of type 0 (without gps_time) from our compressed LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 31 October 2009 -- updated to use the new Arithmetic Coder + 7 September 2008 -- updated to support LAS format 1.2 + 22 February 2007 -- created 45 minutes before henna's 32nd birthday + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_0COMPRESSED_H +#define LAS_POINT_READER_0COMPRESSED_H + +#include "laspointreader.h" + +#include "arithmeticmodel.h" +#include "arithmeticdecoder.h" +#include "integercompressor_newest.h" + +#include + +namespace laszipalternate { + +class LASpointReader0compressed : public LASpointReader +{ +public: + bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0); + LASpointReader0compressed(FILE* file); + ~LASpointReader0compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + void init_decoder(); + ArithmeticDecoder* dec; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + ArithmeticModel* m_changed_values; + IntegerCompressorContext* ic_intensity; + ArithmeticModel* m_bit_byte; + ArithmeticModel* m_classification; + IntegerCompressorContext* ic_scan_angle_rank; + ArithmeticModel* m_user_data; + IntegerCompressorContext* ic_point_source_ID; +}; + +} +#endif diff --git a/src/alternate_coder_src/laspointreader1compressed.cpp b/src/alternate_coder_src/laspointreader1compressed.cpp new file mode 100644 index 00000000..3171d896 --- /dev/null +++ b/src/alternate_coder_src/laspointreader1compressed.cpp @@ -0,0 +1,302 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader1compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointreader1compressed.h" + +#define MULTI_MAX 512 + +namespace laszipalternate { + +bool LASpointReader1compressed::read_point(LASpoint* point, double* gps_time, unsigned short* rgb) +{ + if (dec) + { + *point = last_point; + + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // decompress x y z coordinates + int x_diff = ic_dx->DecompressLast(median_x, last_dir); + point->x += x_diff; + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + int y_diff; + if (messy < 0 || messy > 6) + { + y_diff = ic_dy->DecompressNone(); + point->z = ic_z->DecompressNone(); + } + else + { + y_diff = ic_dy->DecompressLast(median_y, (last_dir?messy+7:messy)); + point->z = ic_z->DecompressLast(last_point.z, messy); + } + point->y += y_diff; + + // decompress which other values have changed + int changed_values = dec->decode(m_changed_values); + + // decompress the intensity if it has changed + if (changed_values & 32) + { + point->intensity = ic_intensity->DecompressLast(last_point.intensity); + } + + // decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + ((unsigned char*)point)[14] = dec->decode(m_bit_byte); + } + + // decompress the classification ... if it has changed + if (changed_values & 8) + { + point->classification = dec->decode(m_classification); + } + + // decompress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + point->scan_angle_rank = ic_scan_angle_rank->DecompressLast(last_point.scan_angle_rank, messy == 2); // this is the best messy + } + + // decompress the user_data ... if it has changed + if (changed_values & 2) + { + point->user_data = dec->decode(m_user_data); + } + + // decompress the point_source_ID ... if it has changed + if (changed_values & 1) + { + point->point_source_ID = ic_point_source_ID->DecompressLast(last_point.point_source_ID); + } + + // decompress the gps_time ... if it has changed + if (changed_values & 64) + { + int multi = dec->decode(m_gps_time_multi[messy==2]); + + if (multi < MULTI_MAX-1) + { + int gps_time_diff; + + if (multi) + if (multi == 1) + gps_time_diff = ic_gps_time->DecompressLast(last_gps_time_diff, 0); + else if (multi < 10) + gps_time_diff = ic_gps_time->DecompressLast(multi*last_gps_time_diff, 1); + else + gps_time_diff = ic_gps_time->DecompressLast(multi*last_gps_time_diff, 2); + else + gps_time_diff = ic_gps_time->DecompressNone(); + + ((I64*)gps_time)[0] = ((I64*)&(last_gps_time))[0] + gps_time_diff; + + if (multi == 1 || multi_extreme_counter > 3) + { + last_gps_time_diff = gps_time_diff; + multi_extreme_counter = 0; + } + else if (multi == 0 || multi == MULTI_MAX-2) + { + multi_extreme_counter++; + } + } + else + { + *gps_time = dec->readDouble(); + } + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fread(point, sizeof(LASpoint), 1, file); + fread(gps_time, sizeof(double), 1, file); + init_decoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_gps_time = *gps_time; + + return true; +} + +LASpointReader1compressed::LASpointReader1compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + last_gps_time = 0; + last_gps_time_diff = 0; + dec = 0; +} + +void LASpointReader1compressed::init_decoder() +{ + dec = new ArithmeticDecoder(file); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupDecompressor(dec, 2); + ic_dy->SetupDecompressor(dec, 14); + ic_z->SetupDecompressor(dec, 7); + + m_changed_values = new ArithmeticModel(128,0,0); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupDecompressor(dec); + + m_bit_byte = new ArithmeticModel(256,0,0); + m_classification = new ArithmeticModel(256,0,0); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupDecompressor(dec, 2); + + m_user_data = new ArithmeticModel(256,0,0); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupDecompressor(dec); + + m_gps_time_multi = new ArithmeticModel*[2]; + for (int i = 0; i < 2; i++) m_gps_time_multi[i] = new ArithmeticModel(MULTI_MAX,0,0); + + ic_gps_time = new IntegerCompressorContext(); + ic_gps_time->SetPrecision(32); + ic_gps_time->SetupDecompressor(dec, 3); + + multi_extreme_counter = 0; +} + +LASpointReader1compressed::~LASpointReader1compressed() +{ + if (dec) + { + dec->done(); + + delete dec; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete m_changed_values; + delete ic_intensity; + delete m_bit_byte; + delete m_classification; + delete ic_scan_angle_rank; + delete m_user_data; + delete ic_point_source_ID; + for (int i = 0; i < 2; i++) delete m_gps_time_multi[i]; + delete [] m_gps_time_multi; + delete ic_gps_time; + } +} + +} \ No newline at end of file diff --git a/src/alternate_coder_src/laspointreader1compressed.h b/src/alternate_coder_src/laspointreader1compressed.h new file mode 100644 index 00000000..a3a79bca --- /dev/null +++ b/src/alternate_coder_src/laspointreader1compressed.h @@ -0,0 +1,97 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader1compressed.h + + CONTENTS: + + Reads a point of type 1 (with gps_time) from our compressed LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 31 October 2009 -- updated to use the new Arithmetic Coder + 7 September 2008 -- updated to support LAS format 1.2 + 23 February 2007 -- created 12 hours into henna's 32nd birthday + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_1COMPRESSED_H +#define LAS_POINT_READER_1COMPRESSED_H + +#include "laspointreader.h" + + +#include "arithmeticmodel.h" +#include "arithmeticdecoder.h" +#include "integercompressor_newest.h" + +#include + +namespace laszipalternate { + +class LASpointReader1compressed : public LASpointReader +{ +public: + bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0); + LASpointReader1compressed(FILE* file); + ~LASpointReader1compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + double last_gps_time; + int last_gps_time_diff; + void init_decoder(); + ArithmeticDecoder* dec; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + ArithmeticModel* m_changed_values; + IntegerCompressorContext* ic_intensity; + ArithmeticModel* m_bit_byte; + ArithmeticModel* m_classification; + IntegerCompressorContext* ic_scan_angle_rank; + ArithmeticModel* m_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_gps_time; + ArithmeticModel** m_gps_time_multi; + int multi_extreme_counter; +}; + +} +#endif diff --git a/src/alternate_coder_src/laspointreader2compressed.cpp b/src/alternate_coder_src/laspointreader2compressed.cpp new file mode 100644 index 00000000..8d311f7b --- /dev/null +++ b/src/alternate_coder_src/laspointreader2compressed.cpp @@ -0,0 +1,274 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader2compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointreader2compressed.h" + +namespace laszipalternate { + +bool LASpointReader2compressed::read_point(LASpoint* point, double* gps_time, unsigned short* rgb) +{ + if (dec) + { + *point = last_point; + + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // decompress x y z coordinates + int x_diff = ic_dx->DecompressLast(median_x, last_dir); + point->x += x_diff; + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + int y_diff; + if (messy < 0 || messy > 6) + { + y_diff = ic_dy->DecompressNone(); + point->z = ic_z->DecompressNone(); + } + else + { + y_diff = ic_dy->DecompressLast(median_y, (last_dir?messy+7:messy)); + point->z = ic_z->DecompressLast(last_point.z, messy); + } + point->y += y_diff; + + // decompress which other values have changed + int changed_values = dec->decode(m_changed_values); + + // decompress the intensity if it has changed + if (changed_values & 32) + { + point->intensity = ic_intensity->DecompressLast(last_point.intensity); + } + + // decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + ((unsigned char*)point)[14] = dec->decode(m_bit_byte); + } + + // decompress the classification ... if it has changed + if (changed_values & 8) + { + point->classification = dec->decode(m_classification); + } + + // decompress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + point->scan_angle_rank = ic_scan_angle_rank->DecompressLast(last_point.scan_angle_rank, messy == 2); // this is the best messy + } + + // decompress the user_data ... if it has changed + if (changed_values & 2) + { + point->user_data = dec->decode(m_user_data); + } + + // decompress the point_source_ID ... if it has changed + if (changed_values & 1) + { + point->point_source_ID = ic_point_source_ID->DecompressLast(last_point.point_source_ID); + } + + // decompress the rgb color ... if it has changed + if (changed_values & 64) + { + rgb[0] = ic_r->DecompressLast(last_rgb[0]); + rgb[1] = ic_g->DecompressLast(last_rgb[1]); + rgb[2] = ic_b->DecompressLast(last_rgb[2]); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fread(point, sizeof(LASpoint), 1, file); + fread(rgb, sizeof(unsigned short), 3, file); + init_decoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_rgb[0] = rgb[0]; + last_rgb[1] = rgb[1]; + last_rgb[2] = rgb[2]; + + return true; +} + +LASpointReader2compressed::LASpointReader2compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + dec = 0; +} + +void LASpointReader2compressed::init_decoder() +{ + dec = new ArithmeticDecoder(file); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupDecompressor(dec, 2); + ic_dy->SetupDecompressor(dec, 14); + ic_z->SetupDecompressor(dec, 7); + + m_changed_values = new ArithmeticModel(128,0,0); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupDecompressor(dec); + + m_bit_byte = new ArithmeticModel(256,0,0); + m_classification = new ArithmeticModel(256,0,0); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupDecompressor(dec, 2); + + m_user_data = new ArithmeticModel(256,0,0); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupDecompressor(dec); + + ic_r = new IntegerCompressorContext(); + ic_g = new IntegerCompressorContext(); + ic_b = new IntegerCompressorContext(); + + ic_r->SetPrecision(16); + ic_g->SetPrecision(16); + ic_b->SetPrecision(16); + + ic_r->SetupDecompressor(dec); + ic_g->SetupDecompressor(dec); + ic_b->SetupDecompressor(dec); +} + +LASpointReader2compressed::~LASpointReader2compressed() +{ + if (dec) + { + dec->done(); + + delete dec; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete m_changed_values; + delete ic_intensity; + delete m_bit_byte; + delete m_classification; + delete ic_scan_angle_rank; + delete m_user_data; + delete ic_point_source_ID; + delete ic_r; + delete ic_g; + delete ic_b; + } +} + +} diff --git a/src/alternate_coder_src/laspointreader2compressed.h b/src/alternate_coder_src/laspointreader2compressed.h new file mode 100644 index 00000000..2acc3a47 --- /dev/null +++ b/src/alternate_coder_src/laspointreader2compressed.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader2compressed.h + + CONTENTS: + + Reads a point of type 2 (with rgb color) from our compressed LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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: + + 31 October 2009 -- updated to use the new Arithmetic Coder + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_2COMPRESSED_H +#define LAS_POINT_READER_2COMPRESSED_H + +#include "laspointreader.h" + +#include "arithmeticmodel.h" +#include "arithmeticdecoder.h" +#include "integercompressor_newest.h" + +#include + +namespace laszipalternate { + +class LASpointReader2compressed : public LASpointReader +{ +public: + bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0); + LASpointReader2compressed(FILE* file); + ~LASpointReader2compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + unsigned short last_rgb[3]; + void init_decoder(); + ArithmeticDecoder* dec; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + ArithmeticModel* m_changed_values; + IntegerCompressorContext* ic_intensity; + ArithmeticModel* m_bit_byte; + ArithmeticModel* m_classification; + IntegerCompressorContext* ic_scan_angle_rank; + ArithmeticModel* m_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_r; + IntegerCompressorContext* ic_g; + IntegerCompressorContext* ic_b; +}; + +} +#endif diff --git a/src/alternate_coder_src/laspointreader3compressed.cpp b/src/alternate_coder_src/laspointreader3compressed.cpp new file mode 100644 index 00000000..b4972a15 --- /dev/null +++ b/src/alternate_coder_src/laspointreader3compressed.cpp @@ -0,0 +1,329 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader3compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointreader3compressed.h" + +#define MULTI_MAX 512 + +namespace laszipalternate { + +bool LASpointReader3compressed::read_point(LASpoint* point, double* gps_time, unsigned short* rgb) +{ + if (dec) + { + *point = last_point; + + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // decompress x y z coordinates + int x_diff = ic_dx->DecompressLast(median_x, last_dir); + point->x += x_diff; + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + int y_diff; + if (messy < 0 || messy > 6) + { + y_diff = ic_dy->DecompressNone(); + point->z = ic_z->DecompressNone(); + } + else + { + y_diff = ic_dy->DecompressLast(median_y, (last_dir?messy+7:messy)); + point->z = ic_z->DecompressLast(last_point.z, messy); + } + point->y += y_diff; + + // decompress which other values have changed + int changed_values = dec->decode(m_changed_values); + + // decompress the intensity if it has changed + if (changed_values & 32) + { + point->intensity = ic_intensity->DecompressLast(last_point.intensity); + } + + // decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + ((unsigned char*)point)[14] = dec->decode(m_bit_byte); + } + + // decompress the classification ... if it has changed + if (changed_values & 8) + { + point->classification = dec->decode(m_classification); + } + + // decompress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + point->scan_angle_rank = ic_scan_angle_rank->DecompressLast(last_point.scan_angle_rank, messy == 2); // this is the best messy + } + + // decompress the user_data ... if it has changed + if (changed_values & 2) + { + point->user_data = dec->decode(m_user_data); + } + + // decompress the point_source_ID ... if it has changed + if (changed_values & 1) + { + point->point_source_ID = ic_point_source_ID->DecompressLast(last_point.point_source_ID); + } + + // decompress the gps_time ... if it has changed + if (changed_values & 64) + { + int multi = dec->decode(m_gps_time_multi[messy==2]); + + if (multi < MULTI_MAX-1) + { + int gps_time_diff; + + if (multi) + if (multi == 1) + gps_time_diff = ic_gps_time->DecompressLast(last_gps_time_diff, 0); + else if (multi < 10) + gps_time_diff = ic_gps_time->DecompressLast(multi*last_gps_time_diff, 1); + else + gps_time_diff = ic_gps_time->DecompressLast(multi*last_gps_time_diff, 2); + else + gps_time_diff = ic_gps_time->DecompressNone(); + + ((__int64*)gps_time)[0] = ((__int64*)&(last_gps_time))[0] + gps_time_diff; + + if (multi == 1 || multi_extreme_counter > 3) + { + last_gps_time_diff = gps_time_diff; + multi_extreme_counter = 0; + } + else if (multi == 0 || multi == MULTI_MAX-2) + { + multi_extreme_counter++; + } + } + else + { + *gps_time = dec->readDouble(); + } + } + + // decompress the rgb color ... if it has changed + if (changed_values & 128) + { + rgb[0] = ic_r->DecompressLast(last_rgb[0]); + rgb[1] = ic_r->DecompressLast(last_rgb[1]); + rgb[2] = ic_r->DecompressLast(last_rgb[2]); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fread(point, sizeof(LASpoint), 1, file); + fread(gps_time, sizeof(double), 1, file); + fread(rgb, sizeof(unsigned short), 3, file); + init_decoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_gps_time = *gps_time; + last_rgb[0] = rgb[0]; + last_rgb[1] = rgb[1]; + last_rgb[2] = rgb[2]; + + return true; +} + +LASpointReader3compressed::LASpointReader3compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + last_gps_time = 0; + last_gps_time_diff = 0; + dec = 0; +} + +void LASpointReader3compressed::init_decoder() +{ + dec = new ArithmeticDecoder(file); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupDecompressor(dec, 2); + ic_dy->SetupDecompressor(dec, 14); + ic_z->SetupDecompressor(dec, 7); + + m_changed_values = new ArithmeticModel(256,0,0); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupDecompressor(dec); + + m_bit_byte = new ArithmeticModel(256,0,0); + m_classification = new ArithmeticModel(256,0,0); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupDecompressor(dec, 2); + + m_user_data = new ArithmeticModel(256,0,0); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupDecompressor(dec); + + m_gps_time_multi = new ArithmeticModel*[2]; + for (int i = 0; i < 2; i++) m_gps_time_multi[i] = new ArithmeticModel(MULTI_MAX,0,0); + + ic_gps_time = new IntegerCompressorContext(); + ic_gps_time->SetPrecision(32); + ic_gps_time->SetupDecompressor(dec); + + multi_extreme_counter = 0; + + ic_r = new IntegerCompressorContext(); + ic_g = new IntegerCompressorContext(); + ic_b = new IntegerCompressorContext(); + + ic_r->SetPrecision(16); + ic_g->SetPrecision(16); + ic_b->SetPrecision(16); + + ic_r->SetupDecompressor(dec); + ic_g->SetupDecompressor(dec); + ic_b->SetupDecompressor(dec); +} + +LASpointReader3compressed::~LASpointReader3compressed() +{ + if (dec) + { + dec->done(); + + delete dec; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete m_changed_values; + delete ic_intensity; + delete m_bit_byte; + delete m_classification; + delete ic_scan_angle_rank; + delete m_user_data; + delete ic_point_source_ID; + delete ic_gps_time; + for (int i = 0; i < 2; i++) delete m_gps_time_multi[i]; + delete [] m_gps_time_multi; + delete ic_r; + delete ic_g; + delete ic_b; + } +} + +} \ No newline at end of file diff --git a/src/alternate_coder_src/laspointreader3compressed.h b/src/alternate_coder_src/laspointreader3compressed.h new file mode 100644 index 00000000..73bbc7b6 --- /dev/null +++ b/src/alternate_coder_src/laspointreader3compressed.h @@ -0,0 +1,100 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader3compressed.h + + CONTENTS: + + Reads a point of type 3 (with gps_time and rgb color) from our compressed LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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: + + 31 October 2009 -- updated to use the new Arithmetic Coder + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_READER_3COMPRESSED_H +#define LAS_POINT_READER_3COMPRESSED_H + +#include "laspointreader.h" + +#include "arithmeticmodel.h" +#include "arithmeticdecoder.h" +#include "integercompressor_newest.h" + +#include + +namespace laszipalternate { + + +class LASpointReader3compressed : public LASpointReader +{ +public: + bool read_point(LASpoint* point, double* gps_time = 0, unsigned short* rgb = 0); + LASpointReader3compressed(FILE* file); + ~LASpointReader3compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + double last_gps_time; + int last_gps_time_diff; + unsigned short last_rgb[3]; + void init_decoder(); + ArithmeticDecoder* dec; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + ArithmeticModel* m_changed_values; + IntegerCompressorContext* ic_intensity; + ArithmeticModel* m_bit_byte; + ArithmeticModel* m_classification; + IntegerCompressorContext* ic_scan_angle_rank; + ArithmeticModel* m_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_gps_time; + ArithmeticModel** m_gps_time_multi; + int multi_extreme_counter; + IntegerCompressorContext* ic_r; + IntegerCompressorContext* ic_g; + IntegerCompressorContext* ic_b; +}; + +} +#endif diff --git a/src/alternate_coder_src/laspointwriter0compressed.cpp b/src/alternate_coder_src/laspointwriter0compressed.cpp new file mode 100644 index 00000000..a711a481 --- /dev/null +++ b/src/alternate_coder_src/laspointwriter0compressed.cpp @@ -0,0 +1,253 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter0compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointwriter0compressed.h" + +namespace laszipalternate { + +bool LASpointWriter0compressed::write_point(LASpoint* point, double gps_time, unsigned short* rgb) +{ + if (enc) + { + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // compress x y z coordinates + int x_diff = point->x - last_point.x; + int y_diff = point->y - last_point.y; + + // if there is a direction flag we use it to encode the x and y differences with different contexts + ic_dx->CompressLast(median_x, x_diff, last_dir); + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + if (messy < 0 || messy > 6) + { + ic_dy->CompressNone(y_diff); + ic_z->CompressNone(point->z); + } + else + { + ic_dy->CompressLast(median_y, y_diff, (last_dir?messy+7:messy)); + ic_z->CompressLast(last_point.z, point->z, messy); + } + + // compress which other values have changed + int changed_values = ((last_point.intensity != point->intensity) << 5) | + ((((unsigned char*)&last_point)[14] != ((unsigned char*)point)[14]) << 4) | + ((last_point.classification != point->classification) << 3) | + ((last_point.scan_angle_rank != point->scan_angle_rank) << 2) | + ((last_point.user_data != point->user_data) << 1) | + ((last_point.point_source_ID != point->point_source_ID)); + + enc->encode(m_changed_values, changed_values); + + // compress the intensity if it has changed + if (changed_values & 32) + { + ic_intensity->CompressLast(last_point.intensity, point->intensity); + } + + // compress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + enc->encode(m_bit_byte, ((unsigned char*)point)[14]); + } + + // compress the classification ... if it has changed + if (changed_values & 8) + { + enc->encode(m_classification, point->classification); + } + + // compress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + ic_scan_angle_rank->CompressLast(last_point.scan_angle_rank, point->scan_angle_rank, messy == 2); // this is the best messy + } + + // compress the user_data ... if it has changed + if (changed_values & 2) + { + enc->encode(m_user_data, point->user_data); + } + + // compress the point_source_ID ... if it has changed + if (changed_values & 1) + { + ic_point_source_ID->CompressLast(last_point.point_source_ID, point->point_source_ID); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fwrite(point, sizeof(LASpoint), 1, file); + init_encoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + + return true; +} + +LASpointWriter0compressed::LASpointWriter0compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + enc = 0; +} + +void LASpointWriter0compressed::init_encoder() +{ + enc = new ArithmeticEncoder(file,false); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupCompressor(enc, 2); + ic_dy->SetupCompressor(enc, 14); + ic_z->SetupCompressor(enc, 7); + + m_changed_values = new ArithmeticModel(64,0,1); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupCompressor(enc); + + m_bit_byte = new ArithmeticModel(256,0,1); + m_classification = new ArithmeticModel(256,0,1); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupCompressor(enc, 2); + + m_user_data = new ArithmeticModel(256,0,1); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupCompressor(enc); +} + +LASpointWriter0compressed::~LASpointWriter0compressed() +{ + if (enc) + { + enc->done(); + + delete enc; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete m_changed_values; + delete ic_intensity; + delete m_bit_byte; + delete m_classification; + delete ic_scan_angle_rank; + delete m_user_data; + delete ic_point_source_ID; + } +} + +} diff --git a/src/alternate_coder_src/laspointwriter0compressed.h b/src/alternate_coder_src/laspointwriter0compressed.h new file mode 100644 index 00000000..67f2bdd3 --- /dev/null +++ b/src/alternate_coder_src/laspointwriter0compressed.h @@ -0,0 +1,92 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter0compressed.h + + CONTENTS: + + Writes a point of type 0 (without gps_time) in our compressed LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 31 October 2009 -- updated to use the new Arithmetic Coder + 7 September 2008 -- updated to support LAS format 1.2 + 21 February 2007 -- created after having the longest talk ever with my aunt + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_0COMPRESSED_H +#define LAS_POINT_WRITER_0COMPRESSED_H + +#include "laspointwriter.h" + +#include "arithmeticmodel.h" +#include "arithmeticencoder.h" +#include "integercompressor_newest.h" + +#include + +namespace laszipalternate { + + +class LASpointWriter0compressed : public LASpointWriter +{ +public: + bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0); + LASpointWriter0compressed(FILE* file); + ~LASpointWriter0compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + void init_encoder(); + ArithmeticEncoder* enc; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + ArithmeticModel* m_changed_values; + IntegerCompressorContext* ic_intensity; + ArithmeticModel* m_bit_byte; + ArithmeticModel* m_classification; + IntegerCompressorContext* ic_scan_angle_rank; + ArithmeticModel* m_user_data; + IntegerCompressorContext* ic_point_source_ID; +}; + +} +#endif diff --git a/src/alternate_coder_src/laspointwriter1compressed.cpp b/src/alternate_coder_src/laspointwriter1compressed.cpp new file mode 100644 index 00000000..38c9b045 --- /dev/null +++ b/src/alternate_coder_src/laspointwriter1compressed.cpp @@ -0,0 +1,321 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter1compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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 corresponding header file + +=============================================================================== +*/ + +#include +#include "laspointwriter1compressed.h" + +#define MULTI_MAX 512 + +namespace laszipalternate { + +bool LASpointWriter1compressed::write_point(LASpoint* point, double gps_time, unsigned short* rgb) +{ + if (enc) + { + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // compress x y z coordinates + int x_diff = point->x - last_point.x; + int y_diff = point->y - last_point.y; + + // if there is a direction flag we use it to encode the x and y differences with different contexts + ic_dx->CompressLast(median_x, x_diff, last_dir); + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + if (messy < 0 || messy > 6) + { + ic_dy->CompressNone(y_diff); + ic_z->CompressNone(point->z); + } + else + { + ic_dy->CompressLast(median_y, y_diff, (last_dir?messy+7:messy)); + ic_z->CompressLast(last_point.z, point->z, messy); + } + + // compress which other values have changed + int changed_values = ((last_gps_time != gps_time) << 6) | + ((last_point.intensity != point->intensity) << 5) | + ((((unsigned char*)&last_point)[14] != ((unsigned char*)point)[14]) << 4) | + ((last_point.classification != point->classification) << 3) | + ((last_point.scan_angle_rank != point->scan_angle_rank) << 2) | + ((last_point.user_data != point->user_data) << 1) | + ((last_point.point_source_ID != point->point_source_ID)); + + enc->encode(m_changed_values, changed_values); + + // compress the intensity if it has changed + if (changed_values & 32) + { + ic_intensity->CompressLast(last_point.intensity, point->intensity); + } + + // compress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + enc->encode(m_bit_byte, ((unsigned char*)point)[14]); + } + + // compress the classification ... if it has changed + if (changed_values & 8) + { + enc->encode(m_classification, point->classification); + } + + // compress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + ic_scan_angle_rank->CompressLast(last_point.scan_angle_rank, point->scan_angle_rank, messy == 2); // this is the best messy + } + + // compress the user_data ... if it has changed + if (changed_values & 2) + { + enc->encode(m_user_data, point->user_data); + } + + // compress the point_source_ID ... if it has changed + if (changed_values & 1) + { + ic_point_source_ID->CompressLast(last_point.point_source_ID, point->point_source_ID); + } + + // compress the gps_time ... if it has changed + if (changed_values & 64) + { + I64 gps_time_diff = ((I64*)&(gps_time))[0] - ((I64*)&(last_gps_time))[0]; + + if (-1<<30 < gps_time_diff && gps_time_diff < 1<<30) + { + int multi = 1; + if (last_gps_time_diff) + { + multi = (int)(((float)gps_time_diff / (float)last_gps_time_diff) + 0.5); + if (multi > MULTI_MAX-2) + { + multi = MULTI_MAX-2; + } + else if (multi < 0) + { + multi = 0; + } + } + enc->encode(m_gps_time_multi[messy==2], multi); + if (multi) + if (multi == 1) + ic_gps_time->CompressLast(last_gps_time_diff, (int)gps_time_diff, 0); + else if (multi < 10) + ic_gps_time->CompressLast(multi*last_gps_time_diff, (int)gps_time_diff, 1); + else + ic_gps_time->CompressLast(multi*last_gps_time_diff, (int)gps_time_diff, 2); + else + ic_gps_time->CompressNone((int)gps_time_diff); + + if (multi == 1 || multi_extreme_counter > 3) + { + last_gps_time_diff = (int)gps_time_diff; + multi_extreme_counter = 0; + } + else if (multi == 0 || multi == MULTI_MAX-2) + { + multi_extreme_counter++; + } + } + else + { + enc->encode(m_gps_time_multi[messy==2], MULTI_MAX-1); + enc->writeDouble(gps_time); + } + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fwrite(point, sizeof(LASpoint), 1, file); + fwrite(&(gps_time), sizeof(double), 1, file); + init_encoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_gps_time = gps_time; + + return true; +} + +LASpointWriter1compressed::LASpointWriter1compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + last_gps_time = 0; + last_gps_time_diff = 0; + enc = 0; +} + +void LASpointWriter1compressed::init_encoder() +{ + enc = new ArithmeticEncoder(file,false); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupCompressor(enc, 2); + ic_dy->SetupCompressor(enc, 14); + ic_z->SetupCompressor(enc, 7); + + m_changed_values = new ArithmeticModel(128,0,1); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupCompressor(enc); + + m_bit_byte = new ArithmeticModel(256,0,1); + m_classification = new ArithmeticModel(256,0,1); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupCompressor(enc, 2); + + m_user_data = new ArithmeticModel(256,0,1); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupCompressor(enc); + + m_gps_time_multi = new ArithmeticModel*[2]; + for (int i = 0; i < 2; i++) m_gps_time_multi[i] = new ArithmeticModel(MULTI_MAX,0,1); + + ic_gps_time = new IntegerCompressorContext(); + ic_gps_time->SetPrecision(32); + ic_gps_time->SetupCompressor(enc, 3); + + multi_extreme_counter = 0; +} + +LASpointWriter1compressed::~LASpointWriter1compressed() +{ + if (enc) + { + enc->done(); + + delete enc; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete m_changed_values; + delete ic_intensity; + delete m_bit_byte; + delete m_classification; + delete ic_scan_angle_rank; + delete m_user_data; + delete ic_point_source_ID; + for (int i = 0; i < 2; i++) delete m_gps_time_multi[i]; + delete [] m_gps_time_multi; + delete ic_gps_time; + } +} + +} \ No newline at end of file diff --git a/src/alternate_coder_src/laspointwriter1compressed.h b/src/alternate_coder_src/laspointwriter1compressed.h new file mode 100644 index 00000000..9e9649f2 --- /dev/null +++ b/src/alternate_coder_src/laspointwriter1compressed.h @@ -0,0 +1,96 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter1compressed.h + + CONTENTS: + + Writes a point of type 1 (with gps_time) in our compressed LAS format 1.1 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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: + + 31 October 2009 -- updated to use the new Arithmetic Coder + 7 September 2008 -- updated to support LAS format 1.2 + 21 February 2007 -- created after having the longest talk ever with my aunt + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_1COMPRESSED_H +#define LAS_POINT_WRITER_1COMPRESSED_H + +#include "laspointwriter.h" + +#include "arithmeticmodel.h" +#include "arithmeticencoder.h" +#include "integercompressor_newest.h" + +#include + +namespace laszipalternate { + +class LASpointWriter1compressed : public LASpointWriter +{ +public: + bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0); + LASpointWriter1compressed(FILE* file); + ~LASpointWriter1compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + double last_gps_time; + int last_gps_time_diff; + void init_encoder(); + ArithmeticEncoder* enc; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + ArithmeticModel* m_changed_values; + IntegerCompressorContext* ic_intensity; + ArithmeticModel* m_bit_byte; + ArithmeticModel* m_classification; + IntegerCompressorContext* ic_scan_angle_rank; + ArithmeticModel* m_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_gps_time; + ArithmeticModel** m_gps_time_multi; + int multi_extreme_counter; +}; + +} +#endif diff --git a/src/alternate_coder_src/laspointwriter2compressed.cpp b/src/alternate_coder_src/laspointwriter2compressed.cpp new file mode 100644 index 00000000..ee6afdfc --- /dev/null +++ b/src/alternate_coder_src/laspointwriter2compressed.cpp @@ -0,0 +1,281 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter2compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointwriter2compressed.h" + +namespace laszipalternate { + +bool LASpointWriter2compressed::write_point(LASpoint* point, double gps_time, unsigned short* rgb) +{ + if (enc) + { + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // compress x y z coordinates + int x_diff = point->x - last_point.x; + int y_diff = point->y - last_point.y; + + // if there is a direction flag we use it to encode the x and y differences with different contexts + ic_dx->CompressLast(median_x, x_diff, last_dir); + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + if (messy < 0 || messy > 6) + { + ic_dy->CompressNone(y_diff); + ic_z->CompressNone(point->z); + } + else + { + ic_dy->CompressLast(median_y, y_diff, (last_dir?messy+7:messy)); + ic_z->CompressLast(last_point.z, point->z, messy); + } + + // compress which other values have changed + int changed_values = ((last_rgb[0] != rgb[0] || last_rgb[1] != rgb[1] || last_rgb[2] != rgb[2]) << 6) | + ((last_point.intensity != point->intensity) << 5) | + ((((unsigned char*)&last_point)[14] != ((unsigned char*)point)[14]) << 4) | + ((last_point.classification != point->classification) << 3) | + ((last_point.scan_angle_rank != point->scan_angle_rank) << 2) | + ((last_point.user_data != point->user_data) << 1) | + ((last_point.point_source_ID != point->point_source_ID)); + + enc->encode(m_changed_values, changed_values); + + // compress the intensity if it has changed + if (changed_values & 32) + { + ic_intensity->CompressLast(last_point.intensity, point->intensity); + } + + // compress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + enc->encode(m_bit_byte, ((unsigned char*)point)[14]); + } + + // compress the classification ... if it has changed + if (changed_values & 8) + { + enc->encode(m_classification, point->classification); + } + + // compress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + ic_scan_angle_rank->CompressLast(last_point.scan_angle_rank, point->scan_angle_rank, messy == 2); // this is the best messy + } + + // compress the user_data ... if it has changed + if (changed_values & 2) + { + enc->encode(m_user_data, point->user_data); + } + + // compress the point_source_ID ... if it has changed + if (changed_values & 1) + { + ic_point_source_ID->CompressLast(last_point.point_source_ID, point->point_source_ID); + } + + // compress the rgb color ... if it has changed + if (changed_values & 64) + { + ic_r->CompressLast(last_rgb[0], rgb[0]); + ic_g->CompressLast(last_rgb[1], rgb[1]); + ic_b->CompressLast(last_rgb[2], rgb[2]); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fwrite(point, sizeof(LASpoint), 1, file); + fwrite(rgb, sizeof(unsigned short), 3, file); + init_encoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_rgb[0] = rgb[0]; + last_rgb[1] = rgb[1]; + last_rgb[2] = rgb[2]; + + return true; +} + +LASpointWriter2compressed::LASpointWriter2compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + enc = 0; +} + +void LASpointWriter2compressed::init_encoder() +{ + enc = new ArithmeticEncoder(file,false); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupCompressor(enc, 2); + ic_dy->SetupCompressor(enc, 14); + ic_z->SetupCompressor(enc, 7); + + m_changed_values = new ArithmeticModel(128,0,1); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupCompressor(enc); + + m_bit_byte = new ArithmeticModel(256,0,1); + m_classification = new ArithmeticModel(256,0,1); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupCompressor(enc, 2); + + m_user_data = new ArithmeticModel(256,0,1); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupCompressor(enc); + + ic_r = new IntegerCompressorContext(); + ic_g = new IntegerCompressorContext(); + ic_b = new IntegerCompressorContext(); + + ic_r->SetPrecision(16); + ic_g->SetPrecision(16); + ic_b->SetPrecision(16); + + ic_r->SetupCompressor(enc); + ic_g->SetupCompressor(enc); + ic_b->SetupCompressor(enc); +} + +LASpointWriter2compressed::~LASpointWriter2compressed() +{ + if (enc) + { + enc->done(); + + delete enc; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete m_changed_values; + delete ic_intensity; + delete m_bit_byte; + delete m_classification; + delete ic_scan_angle_rank; + delete m_user_data; + delete ic_point_source_ID; + delete ic_r; + delete ic_g; + delete ic_b; + } +} + +} \ No newline at end of file diff --git a/src/alternate_coder_src/laspointwriter2compressed.h b/src/alternate_coder_src/laspointwriter2compressed.h new file mode 100644 index 00000000..1f5097a6 --- /dev/null +++ b/src/alternate_coder_src/laspointwriter2compressed.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter2compressed.h + + CONTENTS: + + Writes a point of type 2 (with rgb color) in our compressed LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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: + + 31 October 2009 -- updated to use the new Arithmetic Coder + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_2COMPRESSED_H +#define LAS_POINT_WRITER_2COMPRESSED_H + +#include "laspointwriter.h" + +#include "Arithmeticmodel.h" +#include "Arithmeticencoder.h" +#include "integercompressor_newest.h" + +#include + +namespace laszipalternate { + +class LASpointWriter2compressed : public LASpointWriter +{ +public: + bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0); + LASpointWriter2compressed(FILE* file); + ~LASpointWriter2compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + unsigned short last_rgb[3]; + void init_encoder(); + ArithmeticEncoder* enc; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + ArithmeticModel* m_changed_values; + IntegerCompressorContext* ic_intensity; + ArithmeticModel* m_bit_byte; + ArithmeticModel* m_classification; + IntegerCompressorContext* ic_scan_angle_rank; + ArithmeticModel* m_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_r; + IntegerCompressorContext* ic_g; + IntegerCompressorContext* ic_b; +}; + +} +#endif diff --git a/src/alternate_coder_src/laspointwriter3compressed.cpp b/src/alternate_coder_src/laspointwriter3compressed.cpp new file mode 100644 index 00000000..3c98f27a --- /dev/null +++ b/src/alternate_coder_src/laspointwriter3compressed.cpp @@ -0,0 +1,348 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter3compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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 corresponding header file + +=============================================================================== +*/ + +#include +#include "laspointwriter3compressed.h" + +#define MULTI_MAX 512 + +namespace laszipalternate { + +bool LASpointWriter3compressed::write_point(LASpoint* point, double gps_time, unsigned short* rgb) +{ + if (enc) + { + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // compress x y z coordinates + int x_diff = point->x - last_point.x; + int y_diff = point->y - last_point.y; + + // if there is a direction flag we use it to encode the x and y differences with different contexts + ic_dx->CompressLast(median_x, x_diff, last_dir); + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + if (messy < 0 || messy > 6) + { + ic_dy->CompressNone(y_diff); + ic_z->CompressNone(point->z); + } + else + { + ic_dy->CompressLast(median_y, y_diff, (last_dir?messy+7:messy)); + ic_z->CompressLast(last_point.z, point->z, messy); + } + + // compress which other values have changed + int changed_values = ((last_rgb[0] != rgb[0] || last_rgb[1] != rgb[1] || last_rgb[2] != rgb[2]) << 7) | + ((last_gps_time != gps_time) << 6) | + ((last_point.intensity != point->intensity) << 5) | + ((((unsigned char*)&last_point)[14] != ((unsigned char*)point)[14]) << 4) | + ((last_point.classification != point->classification) << 3) | + ((last_point.scan_angle_rank != point->scan_angle_rank) << 2) | + ((last_point.user_data != point->user_data) << 1) | + ((last_point.point_source_ID != point->point_source_ID)); + + enc->encode(m_changed_values, changed_values); + + // compress the intensity if it has changed + if (changed_values & 32) + { + ic_intensity->CompressLast(last_point.intensity, point->intensity); + } + + // compress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + enc->encode(m_bit_byte, ((unsigned char*)point)[14]); + } + + // compress the classification ... if it has changed + if (changed_values & 8) + { + enc->encode(m_classification, point->classification); + } + + // compress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + ic_scan_angle_rank->CompressLast(last_point.scan_angle_rank, point->scan_angle_rank, messy == 2); // this is the best messy + } + + // compress the user_data ... if it has changed + if (changed_values & 2) + { + enc->encode(m_user_data, point->user_data); + } + + // compress the point_source_ID ... if it has changed + if (changed_values & 1) + { + ic_point_source_ID->CompressLast(last_point.point_source_ID, point->point_source_ID); + } + + if (changed_values & 64) + { + __int64 gps_time_diff = ((__int64*)&(gps_time))[0] - ((__int64*)&(last_gps_time))[0]; + + if (-1<<30 < gps_time_diff && gps_time_diff < 1<<30) + { + int multi = 1; + if (last_gps_time_diff) + { + multi = (int)(((float)gps_time_diff / (float)last_gps_time_diff) + 0.5); + if (multi > MULTI_MAX-2) + { + multi = MULTI_MAX-2; + } + else if (multi < 0) + { + multi = 0; + } + } + enc->encode(m_gps_time_multi[messy==2], multi); + if (multi) + if (multi == 1) + ic_gps_time->CompressLast(last_gps_time_diff, (int)gps_time_diff, 0); + else if (multi < 10) + ic_gps_time->CompressLast(multi*last_gps_time_diff, (int)gps_time_diff, 1); + else + ic_gps_time->CompressLast(multi*last_gps_time_diff, (int)gps_time_diff, 2); + else + ic_gps_time->CompressNone((int)gps_time_diff); + + if (multi == 1 || multi_extreme_counter > 3) + { + last_gps_time_diff = (int)gps_time_diff; + multi_extreme_counter = 0; + } + else if (multi == 0 || multi == MULTI_MAX-2) + { + multi_extreme_counter++; + } + } + else + { + enc->encode(m_gps_time_multi[messy==2], MULTI_MAX-1); + enc->writeDouble(gps_time); + } + } + + // compress the rgb color ... if it has changed + if (changed_values & 64) + { + ic_r->CompressLast(last_rgb[0], rgb[0]); + ic_g->CompressLast(last_rgb[1], rgb[1]); + ic_b->CompressLast(last_rgb[2], rgb[2]); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fwrite(point, sizeof(LASpoint), 1, file); + fwrite(&(gps_time), sizeof(double), 1, file); + fwrite(rgb, sizeof(unsigned short), 3, file); + init_encoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_gps_time = gps_time; + last_rgb[0] = rgb[0]; + last_rgb[1] = rgb[1]; + last_rgb[2] = rgb[2]; + + return true; +} + +LASpointWriter3compressed::LASpointWriter3compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + last_gps_time = 0; + last_gps_time_diff = 0; + enc = 0; +} + +void LASpointWriter3compressed::init_encoder() +{ + enc = new ArithmeticEncoder(file,false); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupCompressor(enc, 2); + ic_dy->SetupCompressor(enc, 14); + ic_z->SetupCompressor(enc, 7); + + m_changed_values = new ArithmeticModel(256,0,1); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupCompressor(enc); + + m_bit_byte = new ArithmeticModel(256,0,1); + m_classification = new ArithmeticModel(256,0,1); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupCompressor(enc, 2); + + m_user_data = new ArithmeticModel(256,0,1); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupCompressor(enc); + + m_gps_time_multi = new ArithmeticModel*[2]; + for (int i = 0; i < 2; i++) m_gps_time_multi[i] = new ArithmeticModel(MULTI_MAX,0,1); + + ic_gps_time = new IntegerCompressorContext(); + ic_gps_time->SetPrecision(32); + ic_gps_time->SetupCompressor(enc, 3); + + multi_extreme_counter = 0; + + ic_r = new IntegerCompressorContext(); + ic_g = new IntegerCompressorContext(); + ic_b = new IntegerCompressorContext(); + + ic_r->SetPrecision(16); + ic_g->SetPrecision(16); + ic_b->SetPrecision(16); + + ic_r->SetupCompressor(enc); + ic_g->SetupCompressor(enc); + ic_b->SetupCompressor(enc); +} + +LASpointWriter3compressed::~LASpointWriter3compressed() +{ + if (enc) + { + enc->done(); + + delete enc; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete m_changed_values; + delete ic_intensity; + delete m_bit_byte; + delete m_classification; + delete ic_scan_angle_rank; + delete m_user_data; + delete ic_point_source_ID; + for (int i = 0; i < 2; i++) delete m_gps_time_multi[i]; + delete [] m_gps_time_multi; + delete ic_gps_time; + delete ic_r; + delete ic_g; + delete ic_b; + } +} + +} \ No newline at end of file diff --git a/src/alternate_coder_src/laspointwriter3compressed.h b/src/alternate_coder_src/laspointwriter3compressed.h new file mode 100644 index 00000000..42129510 --- /dev/null +++ b/src/alternate_coder_src/laspointwriter3compressed.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter3compressed.h + + CONTENTS: + + Writes a point of type 3 (with gps_time and rgb color) in our compressed LAS format 1.2 + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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: + + 31 October 2009 -- updated to use the new Arithmetic Coder + 7 September 2008 -- created after baking three apple pies with Kaoru + +=============================================================================== +*/ +#ifndef LAS_POINT_WRITER_3COMPRESSED_H +#define LAS_POINT_WRITER_3COMPRESSED_H + +#include "laspointwriter.h" + +#include "arithmeticmodel.h" +#include "arithmeticencoder.h" +#include "integercompressor_newest.h" + +#include + +namespace laszipalternate { + +class LASpointWriter3compressed : public LASpointWriter +{ +public: + bool write_point(LASpoint* point, double gps_time = 0, unsigned short* rgb = 0); + LASpointWriter3compressed(FILE* file); + ~LASpointWriter3compressed(); + +private: + FILE* file; + LASpoint last_point; + int last_dir; + int last_x_diff[2][3]; + int last_y_diff[2][3]; + int last_incr[2]; + double last_gps_time; + int last_gps_time_diff; + unsigned short last_rgb[3]; + void init_encoder(); + ArithmeticEncoder* enc; + IntegerCompressorContext* ic_dx; + IntegerCompressorContext* ic_dy; + IntegerCompressorContext* ic_z; + ArithmeticModel* m_changed_values; + IntegerCompressorContext* ic_intensity; + ArithmeticModel* m_bit_byte; + ArithmeticModel* m_classification; + IntegerCompressorContext* ic_scan_angle_rank; + ArithmeticModel* m_user_data; + IntegerCompressorContext* ic_point_source_ID; + IntegerCompressorContext* ic_gps_time; + ArithmeticModel** m_gps_time_multi; + int multi_extreme_counter; + IntegerCompressorContext* ic_r; + IntegerCompressorContext* ic_g; + IntegerCompressorContext* ic_b; +}; + +} +#endif diff --git a/src/integercompressor_newer.cpp b/src/integercompressor_newer.cpp new file mode 100644 index 00000000..395b14f8 --- /dev/null +++ b/src/integercompressor_newer.cpp @@ -0,0 +1,596 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: integercompressor_context.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2005 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "integercompressor_newer.h" + +#define COMPRESS_ONLY_K +#undef COMPRESS_ONLY_K + +#define CREATE_HISTOGRAMS +#undef CREATE_HISTOGRAMS + +#include +#include + +#ifdef CREATE_HISTOGRAMS +#include +#endif + +IntegerCompressorContext::IntegerCompressorContext() +{ + bits = 16; + range = 0; + + last = 0; + + re = 0; + rd = 0; + + rmBitsNone = 0; + rmBitsLast = 0; + + rmCorrector = 0; +} + +IntegerCompressorContext::~IntegerCompressorContext() +{ + int i; + if (rmBitsNone) delete rmBitsNone; + if (rmBitsLast) + { + for (i = 0; i < contexts; i++) + { + delete rmBitsLast[i]; + } + free(rmBitsLast); + } + if (rmCorrector) + { + for (i = 0; i <= corr_bits; i++) + { + if (rmCorrector[i]) + { + delete rmCorrector[i]; + } + } + free(rmCorrector); + } +} + +void IntegerCompressorContext::SetupCompressor(RangeEncoder* re, int contexts, int bits_high) +{ + int i; + + this->re = re; + this->contexts = contexts; + this->bits_high = bits_high; + + // the corrector's significant bits and range + + if (range) + { + corr_bits = 0; + corr_range = range; + while (range) + { + range = range >> 1; + corr_bits++; + } + if (corr_range == (1 << (corr_bits-1))) + { + corr_bits--; + } + // the corrector must fall into this interval + corr_min = -(corr_range/2); + } + else if (bits && bits < 32) + { + corr_bits = bits; + corr_range = 1 << bits; + // the corrector must fall into this interval + corr_min = -(corr_range/2); + } + else + { + corr_bits = 32; + corr_range = 0; + // the corrector must fall into this interval + corr_min = -(1 << 31); + } + corr_max = corr_min + corr_range - 1; + + // allocate the arithmetic range tables + + rmBitsNone = new RangeModel(corr_bits+1,0,1,512,16); + rmBitsLast = (RangeModel**)malloc(sizeof(RangeModel*) * (contexts)); + for (i = 0; i < contexts; i++) + { + rmBitsLast[i] = new RangeModel(corr_bits+1,0,1,512,16); + } + +#if defined(COMPRESS_ONLY_K) + rmCorrector = 0; +#else + rmCorrector = (RangeModel**)malloc(sizeof(RangeModel*) * (corr_bits+1)); + for (i = 0; i <= corr_bits; i++) + { + rmCorrector[i] = 0; + } +#endif + +#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<rd = rd; + this->contexts = contexts; + this->bits_high = bits_high; + + // the corrector's significant bits and range + + if (range) + { + corr_bits = 0; + corr_range = range; + while (range) + { + range = range >> 1; + corr_bits++; + } + if (corr_range == (1 << (corr_bits-1))) + { + corr_bits--; + } + // the corrector must fall into this interval + corr_min = -(corr_range/2); + } + else if (bits && bits < 32) + { + corr_bits = bits; + corr_range = 1 << bits; + // the corrector must fall into this interval + corr_min = -(corr_range/2); + } + else + { + corr_bits = 32; + corr_range = 0; + // the corrector must fall into this interval + corr_min = -(1 << 31); + } + corr_max = corr_min + corr_range - 1; + + // allocate the arithmetic range tables + + rmBitsNone = new RangeModel(corr_bits+1,0,0,512,16); + rmBitsLast = (RangeModel**)malloc(sizeof(RangeModel*) * (contexts)); + for (i = 0; i < contexts; i++) + { + rmBitsLast[i] = new RangeModel(corr_bits+1,0,0,512,16); + } + +#if defined(COMPRESS_ONLY_K) + rmCorrector = 0; +#else + rmCorrector = (RangeModel**)malloc(sizeof(RangeModel*) * (corr_bits+1)); + for (i = 0; i <= corr_bits; i++) + { + rmCorrector[i] = 0; + } +#endif +} + +void IntegerCompressorContext::FinishDecompressor() +{ + int i; + if (rmBitsNone) {delete rmBitsNone; rmBitsNone = 0;} + if (rmBitsLast) + { + for (i = 0; i < contexts; i++) + { + delete rmBitsLast[i]; + } + free(rmBitsLast); + rmBitsLast = 0; + } + + if (rmCorrector) + { + for (i = 0; i <= corr_bits; i++) + { + if (rmCorrector[i]) + { + delete rmCorrector[i]; + } + } + free(rmCorrector); + rmCorrector = 0; + } +} + +//----------------------------------------------------------------------------- +// SetPrecision: +//----------------------------------------------------------------------------- +void IntegerCompressorContext::SetPrecision(I32 iBits) +{ + bits = iBits; +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// SetRange: +//----------------------------------------------------------------------------- +void IntegerCompressorContext::SetRange(I32 iRange) +{ + range = iRange; +} + +//----------------------------------------------------------------------------- +// writeCorrector: +//----------------------------------------------------------------------------- +I32 IntegerCompressorContext::writeCorrector(I32 c, RangeModel* rmBits) +{ + I32 c1, k; + + // 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 + + re->encode(rmBits, k); + +// printf("k%d ", k); + +#ifdef COMPRESS_ONLY_K + if (k) // then c is either smaller than 0 or bigger than 1 + { + assert((c != 0) && (c != 1)); + // 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) + re->encode((1<encode((1<encode(2,c); +#ifdef CREATE_HISTOGRAMS + corr_histogram[0][c]++; +#endif +// printf("cn%d ",c); + } +#else // COMPRESS_ONLY_K + if (k) // then c is either smaller than 0 or bigger than 1 + { + assert((c != 0) && (c != 1)); + // 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<encode(rmCorrector[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; + // allocate a new range table if necessary + if (rmCorrector[k] == 0) + { + rmCorrector[k] = new RangeModel(1<encode(rmCorrector[k], c); + // store the lower k1 bits raw + re->writeBits(k1, c1); + } + } + else // then c is 0 or 1 + { + assert((c == 0) || (c == 1)); + // allocate a new range table if necessary + if (rmCorrector[0] == 0) + { + rmCorrector[0] = new RangeModel(2,0,1,2048,16); + } + re->encode(rmCorrector[0],c); + } +#endif // COMPRESS_ONLY_K + return k; +} + +I32 IntegerCompressorContext::CompressNone(I32 real) +{ + // the corrector will be within the interval [ - (corr_range - 1) ... + (corr_range - 1) ] + int corr = real - last; + // 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; + last = real; + return writeCorrector(corr, rmBitsNone); +} + +I32 IntegerCompressorContext::CompressLast(I32 pred, I32 real, int context) +{ + // the corrector will be within the interval [ - (corr_range - 1) ... + (corr_range - 1) ] + int corr = real - pred; + // we fold the corrector into the interval [ corr_min ... corr_max ] + if (corr < corr_min) corr += corr_range; + else if (corr > corr_max) corr -= corr_range; + last = real; + return writeCorrector(corr, rmBitsLast[context]); +} + +I32 IntegerCompressorContext::readCorrector(RangeModel* rmBits) +{ + I32 c; + + // decode within which interval the corrector is falling + + int k = rd->decode(rmBits); + +// printf("k%d ", k); + + // 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 + { + c = rd->decode(1<= (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<decode(2); +// printf("cn%d ", c); + } +#else // COMPRESS_ONLY_K + if (k) // then c is either smaller than 0 or bigger than 1 + { + if (k <= bits_high) + { + // for small k we can do this in one step + + // allocate a new range table if necessary + if (rmCorrector[k] == 0) + { + rmCorrector[k] = new RangeModel((1<decode(rmCorrector[k]); + } + else + { + // for larger k we need to do this in two steps + int k1 = k-bits_high; + + // allocate a new range table if necessary + if (rmCorrector[k] == 0) + { + rmCorrector[k] = new RangeModel(1<decode(rmCorrector[k]); + // read lower bits raw + int c1 = rd->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<decode(rmCorrector[0]); + } +#endif // COMPRESS_ONLY_K + + return c; +} + +I32 IntegerCompressorContext::DecompressNone() +{ + I32 real = last + readCorrector(rmBitsNone); + if (real < 0) real += corr_range; + else if (real >= corr_range) real -= corr_range; + last = real; + return real; +} + +I32 IntegerCompressorContext::DecompressLast(I32 pred, int context) +{ + I32 real = pred + readCorrector(rmBitsLast[context]); + if (real < 0) real += corr_range; + else if (real >= corr_range) real -= corr_range; + last = real; + return real; +} diff --git a/src/integercompressor_newer.h b/src/integercompressor_newer.h new file mode 100644 index 00000000..a08576d9 --- /dev/null +++ b/src/integercompressor_newer.h @@ -0,0 +1,136 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: integercompressor_newer.h + + 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. Two of the encoding functions + take a integer prediction as input. The other will predict the integer + simply using the last integer that was encoded. + + 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@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2005 martin 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: + + 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_NEWER_H +#define INTEGER_COMPRESSOR_NEWER_H + +#include "mydefs.h" + +#include "rangeencoder.h" +#include "rangedecoder.h" +#include "rangemodel.h" + +class IntegerCompressorContext +{ +public: + + // SetPrecision: + void SetPrecision(I32 iBits); + // GetPrecision: + I32 GetPrecision(); + + // SetRange: + void SetRange(I32 iRange); + // GetRange: + I32 GetRange(); + + // SetupCompressor: + void SetupCompressor(RangeEncoder* re, int contexts=1, int BITS_HIGH=8); + void FinishCompressor(); + + // Compress: + I32 CompressNone(I32 iReal); + I32 CompressLast(I32 iPred, I32 iReal, int context=0); + + // SetupDecompressor: + void SetupDecompressor(RangeDecoder* rd, int contexts=1, int BITS_HIGH=8); + void FinishDecompressor(); + + // Deompress: + I32 DecompressNone(); + I32 DecompressLast(I32 iPred, int context=0); + + // Constructor: + IntegerCompressorContext(); + // Destructor: + ~IntegerCompressorContext(); + +private: + // Private Functions + I32 writeCorrector(I32 c, RangeModel* rmBits); + I32 readCorrector(RangeModel* amBits); + + int contexts; + int bits_high; + + // Private Variables + int bits; + int range; + + int corr_bits; + int corr_range; + int corr_max; + int corr_min; + + int last; + + RangeEncoder* re; + RangeDecoder* rd; + + RangeModel* rmBitsNone; + RangeModel** rmBitsLast; + + RangeModel** rmCorrector; + + int** corr_histogram; +}; + +#endif diff --git a/src/laspointreader0compressed.cpp b/src/laspointreader0compressed.cpp new file mode 100644 index 00000000..e043a2e9 --- /dev/null +++ b/src/laspointreader0compressed.cpp @@ -0,0 +1,242 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader0compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointreader0compressed.h" + +bool LASpointReader0compressed::read_point(LASpoint* point, double* gps_time, unsigned short* rgb) +{ + if (rd) + { + *point = last_point; + + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // decompress x y z coordinates + int x_diff = ic_dx->DecompressLast(median_x, last_dir); + point->x += x_diff; + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + int y_diff; + if (messy < 0 || messy > 6) + { + y_diff = ic_dy->DecompressNone(); + point->z = ic_z->DecompressNone(); + } + else + { + y_diff = ic_dy->DecompressLast(median_y, (last_dir?messy+7:messy)); + point->z = ic_z->DecompressLast(last_point.z, messy); + } + point->y += y_diff; + + // decompress which other values have changed + int changed_values = rd->decode(rm_changed_values); + + // decompress the intensity if it has changed + if (changed_values & 32) + { + point->intensity = ic_intensity->DecompressLast(last_point.intensity); + } + + // decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + ((unsigned char*)point)[14] = rd->decode(rm_bit_byte); + } + + // decompress the classification ... if it has changed + if (changed_values & 8) + { + point->classification = rd->decode(rm_classification); + } + + // decompress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + point->scan_angle_rank = ic_scan_angle_rank->DecompressLast(last_point.scan_angle_rank, messy == 2); // this is the best messy + } + + // decompress the user_data ... if it has changed + if (changed_values & 2) + { + point->user_data = rd->decode(rm_user_data); + } + + // decompress the point_source_ID ... if it has changed + if (changed_values & 1) + { + point->point_source_ID = ic_point_source_ID->DecompressLast(last_point.point_source_ID); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fread(point, sizeof(LASpoint), 1, file); + init_decoder(); + } + last_dir = point->scan_direction_flag; + last_point = *point; + + return true; +} + +LASpointReader0compressed::LASpointReader0compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + rd = 0; +} + +void LASpointReader0compressed::init_decoder() +{ + rd = new RangeDecoder(file); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupDecompressor(rd, 2); + ic_dy->SetupDecompressor(rd, 14); + ic_z->SetupDecompressor(rd, 7); + + rm_changed_values = new RangeModel(64,0,0); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupDecompressor(rd); + + rm_bit_byte = new RangeModel(256,0,0); + rm_classification = new RangeModel(256,0,0); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupDecompressor(rd, 2); + + rm_user_data = new RangeModel(256,0,0); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupDecompressor(rd); +} + +LASpointReader0compressed::~LASpointReader0compressed() +{ + if (rd) + { + rd->done(); + + delete rd; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete rm_changed_values; + delete ic_intensity; + delete rm_bit_byte; + delete rm_classification; + delete ic_scan_angle_rank; + delete rm_user_data; + delete ic_point_source_ID; + } +} diff --git a/src/laspointreader1compressed.cpp b/src/laspointreader1compressed.cpp new file mode 100644 index 00000000..af9315a0 --- /dev/null +++ b/src/laspointreader1compressed.cpp @@ -0,0 +1,298 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader1compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointreader1compressed.h" + +#define MULTI_MAX 512 + +bool LASpointReader1compressed::read_point(LASpoint* point, double* gps_time, unsigned short* rgb) +{ + if (rd) + { + *point = last_point; + + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // decompress x y z coordinates + int x_diff = ic_dx->DecompressLast(median_x, last_dir); + point->x += x_diff; + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + int y_diff; + if (messy < 0 || messy > 6) + { + y_diff = ic_dy->DecompressNone(); + point->z = ic_z->DecompressNone(); + } + else + { + y_diff = ic_dy->DecompressLast(median_y, (last_dir?messy+7:messy)); + point->z = ic_z->DecompressLast(last_point.z, messy); + } + point->y += y_diff; + + // decompress which other values have changed + int changed_values = rd->decode(rm_changed_values); + + // decompress the intensity if it has changed + if (changed_values & 32) + { + point->intensity = ic_intensity->DecompressLast(last_point.intensity); + } + + // decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + ((unsigned char*)point)[14] = rd->decode(rm_bit_byte); + } + + // decompress the classification ... if it has changed + if (changed_values & 8) + { + point->classification = rd->decode(rm_classification); + } + + // decompress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + point->scan_angle_rank = ic_scan_angle_rank->DecompressLast(last_point.scan_angle_rank, messy == 2); // this is the best messy + } + + // decompress the user_data ... if it has changed + if (changed_values & 2) + { + point->user_data = rd->decode(rm_user_data); + } + + // decompress the point_source_ID ... if it has changed + if (changed_values & 1) + { + point->point_source_ID = ic_point_source_ID->DecompressLast(last_point.point_source_ID); + } + + // decompress the gps_time ... if it has changed + if (changed_values & 64) + { + int multi = rd->decode(rm_gps_time_multi[messy==2]); + + if (multi < MULTI_MAX-1) + { + int gps_time_diff; + + if (multi) + if (multi == 1) + gps_time_diff = ic_gps_time->DecompressLast(last_gps_time_diff, 0); + else if (multi < 10) + gps_time_diff = ic_gps_time->DecompressLast(multi*last_gps_time_diff, 1); + else + gps_time_diff = ic_gps_time->DecompressLast(multi*last_gps_time_diff, 2); + else + gps_time_diff = ic_gps_time->DecompressNone(); + + ((I64*)gps_time)[0] = ((I64*)&(last_gps_time))[0] + gps_time_diff; + + if (multi == 1 || multi_extreme_counter > 3) + { + last_gps_time_diff = gps_time_diff; + multi_extreme_counter = 0; + } + else if (multi == 0 || multi == MULTI_MAX-2) + { + multi_extreme_counter++; + } + } + else + { + *gps_time = rd->readDouble(); + } + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fread(point, sizeof(LASpoint), 1, file); + fread(gps_time, sizeof(double), 1, file); + init_decoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_gps_time = *gps_time; + + return true; +} + +LASpointReader1compressed::LASpointReader1compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + last_gps_time = 0; + last_gps_time_diff = 0; + rd = 0; +} + +void LASpointReader1compressed::init_decoder() +{ + rd = new RangeDecoder(file); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupDecompressor(rd, 2); + ic_dy->SetupDecompressor(rd, 14); + ic_z->SetupDecompressor(rd, 7); + + rm_changed_values = new RangeModel(128,0,0); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupDecompressor(rd); + + rm_bit_byte = new RangeModel(256,0,0); + rm_classification = new RangeModel(256,0,0); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupDecompressor(rd, 2); + + rm_user_data = new RangeModel(256,0,0); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupDecompressor(rd); + + rm_gps_time_multi = new RangeModel*[2]; + for (int i = 0; i < 2; i++) rm_gps_time_multi[i] = new RangeModel(MULTI_MAX,0,0); + + ic_gps_time = new IntegerCompressorContext(); + ic_gps_time->SetPrecision(32); + ic_gps_time->SetupDecompressor(rd, 3); + + multi_extreme_counter = 0; +} + +LASpointReader1compressed::~LASpointReader1compressed() +{ + if (rd) + { + rd->done(); + + delete rd; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete rm_changed_values; + delete ic_intensity; + delete rm_bit_byte; + delete rm_classification; + delete ic_scan_angle_rank; + delete rm_user_data; + delete ic_point_source_ID; + for (int i = 0; i < 2; i++) delete rm_gps_time_multi[i]; + delete [] rm_gps_time_multi; + delete ic_gps_time; + } +} diff --git a/src/laspointreader2compressed.cpp b/src/laspointreader2compressed.cpp new file mode 100644 index 00000000..58a5ff69 --- /dev/null +++ b/src/laspointreader2compressed.cpp @@ -0,0 +1,270 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader2compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointreader2compressed.h" + +bool LASpointReader2compressed::read_point(LASpoint* point, double* gps_time, unsigned short* rgb) +{ + if (rd) + { + *point = last_point; + + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // decompress x y z coordinates + int x_diff = ic_dx->DecompressLast(median_x, last_dir); + point->x += x_diff; + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + int y_diff; + if (messy < 0 || messy > 6) + { + y_diff = ic_dy->DecompressNone(); + point->z = ic_z->DecompressNone(); + } + else + { + y_diff = ic_dy->DecompressLast(median_y, (last_dir?messy+7:messy)); + point->z = ic_z->DecompressLast(last_point.z, messy); + } + point->y += y_diff; + + // decompress which other values have changed + int changed_values = rd->decode(rm_changed_values); + + // decompress the intensity if it has changed + if (changed_values & 32) + { + point->intensity = ic_intensity->DecompressLast(last_point.intensity); + } + + // decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + ((unsigned char*)point)[14] = rd->decode(rm_bit_byte); + } + + // decompress the classification ... if it has changed + if (changed_values & 8) + { + point->classification = rd->decode(rm_classification); + } + + // decompress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + point->scan_angle_rank = ic_scan_angle_rank->DecompressLast(last_point.scan_angle_rank, messy == 2); // this is the best messy + } + + // decompress the user_data ... if it has changed + if (changed_values & 2) + { + point->user_data = rd->decode(rm_user_data); + } + + // decompress the point_source_ID ... if it has changed + if (changed_values & 1) + { + point->point_source_ID = ic_point_source_ID->DecompressLast(last_point.point_source_ID); + } + + // decompress the rgb color ... if it has changed + if (changed_values & 64) + { + rgb[0] = ic_r->DecompressLast(last_rgb[0]); + rgb[1] = ic_g->DecompressLast(last_rgb[1]); + rgb[2] = ic_b->DecompressLast(last_rgb[2]); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fread(point, sizeof(LASpoint), 1, file); + fread(rgb, sizeof(unsigned short), 3, file); + init_decoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_rgb[0] = rgb[0]; + last_rgb[1] = rgb[1]; + last_rgb[2] = rgb[2]; + + return true; +} + +LASpointReader2compressed::LASpointReader2compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + rd = 0; +} + +void LASpointReader2compressed::init_decoder() +{ + rd = new RangeDecoder(file); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupDecompressor(rd, 2); + ic_dy->SetupDecompressor(rd, 14); + ic_z->SetupDecompressor(rd, 7); + + rm_changed_values = new RangeModel(128,0,0); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupDecompressor(rd); + + rm_bit_byte = new RangeModel(256,0,0); + rm_classification = new RangeModel(256,0,0); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupDecompressor(rd, 2); + + rm_user_data = new RangeModel(256,0,0); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupDecompressor(rd); + + ic_r = new IntegerCompressorContext(); + ic_g = new IntegerCompressorContext(); + ic_b = new IntegerCompressorContext(); + + ic_r->SetPrecision(16); + ic_g->SetPrecision(16); + ic_b->SetPrecision(16); + + ic_r->SetupDecompressor(rd); + ic_g->SetupDecompressor(rd); + ic_b->SetupDecompressor(rd); +} + +LASpointReader2compressed::~LASpointReader2compressed() +{ + if (rd) + { + rd->done(); + + delete rd; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete rm_changed_values; + delete ic_intensity; + delete rm_bit_byte; + delete rm_classification; + delete ic_scan_angle_rank; + delete rm_user_data; + delete ic_point_source_ID; + delete ic_r; + delete ic_g; + delete ic_b; + } +} diff --git a/src/laspointreader3compressed.cpp b/src/laspointreader3compressed.cpp new file mode 100644 index 00000000..b36abf24 --- /dev/null +++ b/src/laspointreader3compressed.cpp @@ -0,0 +1,325 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointreader3compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointreader3compressed.h" + +#define MULTI_MAX 512 + +bool LASpointReader3compressed::read_point(LASpoint* point, double* gps_time, unsigned short* rgb) +{ + if (rd) + { + *point = last_point; + + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // decompress x y z coordinates + int x_diff = ic_dx->DecompressLast(median_x, last_dir); + point->x += x_diff; + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + int y_diff; + if (messy < 0 || messy > 6) + { + y_diff = ic_dy->DecompressNone(); + point->z = ic_z->DecompressNone(); + } + else + { + y_diff = ic_dy->DecompressLast(median_y, (last_dir?messy+7:messy)); + point->z = ic_z->DecompressLast(last_point.z, messy); + } + point->y += y_diff; + + // decompress which other values have changed + int changed_values = rd->decode(rm_changed_values); + + // decompress the intensity if it has changed + if (changed_values & 32) + { + point->intensity = ic_intensity->DecompressLast(last_point.intensity); + } + + // decompress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + ((unsigned char*)point)[14] = rd->decode(rm_bit_byte); + } + + // decompress the classification ... if it has changed + if (changed_values & 8) + { + point->classification = rd->decode(rm_classification); + } + + // decompress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + point->scan_angle_rank = ic_scan_angle_rank->DecompressLast(last_point.scan_angle_rank, messy == 2); // this is the best messy + } + + // decompress the user_data ... if it has changed + if (changed_values & 2) + { + point->user_data = rd->decode(rm_user_data); + } + + // decompress the point_source_ID ... if it has changed + if (changed_values & 1) + { + point->point_source_ID = ic_point_source_ID->DecompressLast(last_point.point_source_ID); + } + + // decompress the gps_time ... if it has changed + if (changed_values & 64) + { + int multi = rd->decode(rm_gps_time_multi[messy==2]); + + if (multi < MULTI_MAX-1) + { + int gps_time_diff; + + if (multi) + if (multi == 1) + gps_time_diff = ic_gps_time->DecompressLast(last_gps_time_diff, 0); + else if (multi < 10) + gps_time_diff = ic_gps_time->DecompressLast(multi*last_gps_time_diff, 1); + else + gps_time_diff = ic_gps_time->DecompressLast(multi*last_gps_time_diff, 2); + else + gps_time_diff = ic_gps_time->DecompressNone(); + + ((__int64*)gps_time)[0] = ((__int64*)&(last_gps_time))[0] + gps_time_diff; + + if (multi == 1 || multi_extreme_counter > 3) + { + last_gps_time_diff = gps_time_diff; + multi_extreme_counter = 0; + } + else if (multi == 0 || multi == MULTI_MAX-2) + { + multi_extreme_counter++; + } + } + else + { + *gps_time = rd->readDouble(); + } + } + + // decompress the rgb color ... if it has changed + if (changed_values & 128) + { + rgb[0] = ic_r->DecompressLast(last_rgb[0]); + rgb[1] = ic_r->DecompressLast(last_rgb[1]); + rgb[2] = ic_r->DecompressLast(last_rgb[2]); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fread(point, sizeof(LASpoint), 1, file); + fread(gps_time, sizeof(double), 1, file); + fread(rgb, sizeof(unsigned short), 3, file); + init_decoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_gps_time = *gps_time; + last_rgb[0] = rgb[0]; + last_rgb[1] = rgb[1]; + last_rgb[2] = rgb[2]; + + return true; +} + +LASpointReader3compressed::LASpointReader3compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + last_gps_time = 0; + last_gps_time_diff = 0; + rd = 0; +} + +void LASpointReader3compressed::init_decoder() +{ + rd = new RangeDecoder(file); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupDecompressor(rd, 2); + ic_dy->SetupDecompressor(rd, 14); + ic_z->SetupDecompressor(rd, 7); + + rm_changed_values = new RangeModel(256,0,0); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupDecompressor(rd); + + rm_bit_byte = new RangeModel(256,0,0); + rm_classification = new RangeModel(256,0,0); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupDecompressor(rd, 2); + + rm_user_data = new RangeModel(256,0,0); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupDecompressor(rd); + + rm_gps_time_multi = new RangeModel*[2]; + for (int i = 0; i < 2; i++) rm_gps_time_multi[i] = new RangeModel(MULTI_MAX,0,0); + + ic_gps_time = new IntegerCompressorContext(); + ic_gps_time->SetPrecision(32); + ic_gps_time->SetupDecompressor(rd); + + multi_extreme_counter = 0; + + ic_r = new IntegerCompressorContext(); + ic_g = new IntegerCompressorContext(); + ic_b = new IntegerCompressorContext(); + + ic_r->SetPrecision(16); + ic_g->SetPrecision(16); + ic_b->SetPrecision(16); + + ic_r->SetupDecompressor(rd); + ic_g->SetupDecompressor(rd); + ic_b->SetupDecompressor(rd); +} + +LASpointReader3compressed::~LASpointReader3compressed() +{ + if (rd) + { + rd->done(); + + delete rd; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete rm_changed_values; + delete ic_intensity; + delete rm_bit_byte; + delete rm_classification; + delete ic_scan_angle_rank; + delete rm_user_data; + delete ic_point_source_ID; + delete ic_gps_time; + for (int i = 0; i < 2; i++) delete rm_gps_time_multi[i]; + delete [] rm_gps_time_multi; + delete ic_r; + delete ic_g; + delete ic_b; + } +} diff --git a/src/laspointwriter0compressed.cpp b/src/laspointwriter0compressed.cpp new file mode 100644 index 00000000..cd72a8ea --- /dev/null +++ b/src/laspointwriter0compressed.cpp @@ -0,0 +1,249 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter0compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointwriter0compressed.h" + +bool LASpointWriter0compressed::write_point(LASpoint* point, double gps_time, unsigned short* rgb) +{ + if (re) + { + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // compress x y z coordinates + int x_diff = point->x - last_point.x; + int y_diff = point->y - last_point.y; + + // if there is a direction flag we use it to encode the x and y differences with different contexts + ic_dx->CompressLast(median_x, x_diff, last_dir); + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + if (messy < 0 || messy > 6) + { + ic_dy->CompressNone(y_diff); + ic_z->CompressNone(point->z); + } + else + { + ic_dy->CompressLast(median_y, y_diff, (last_dir?messy+7:messy)); + ic_z->CompressLast(last_point.z, point->z, messy); + } + + // compress which other values have changed + int changed_values = ((last_point.intensity != point->intensity) << 5) | + ((((unsigned char*)&last_point)[14] != ((unsigned char*)point)[14]) << 4) | + ((last_point.classification != point->classification) << 3) | + ((last_point.scan_angle_rank != point->scan_angle_rank) << 2) | + ((last_point.user_data != point->user_data) << 1) | + ((last_point.point_source_ID != point->point_source_ID)); + + re->encode(rm_changed_values, changed_values); + + // compress the intensity if it has changed + if (changed_values & 32) + { + ic_intensity->CompressLast(last_point.intensity, point->intensity); + } + + // compress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + re->encode(rm_bit_byte, ((unsigned char*)point)[14]); + } + + // compress the classification ... if it has changed + if (changed_values & 8) + { + re->encode(rm_classification, point->classification); + } + + // compress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + ic_scan_angle_rank->CompressLast(last_point.scan_angle_rank, point->scan_angle_rank, messy == 2); // this is the best messy + } + + // compress the user_data ... if it has changed + if (changed_values & 2) + { + re->encode(rm_user_data, point->user_data); + } + + // compress the point_source_ID ... if it has changed + if (changed_values & 1) + { + ic_point_source_ID->CompressLast(last_point.point_source_ID, point->point_source_ID); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fwrite(point, sizeof(LASpoint), 1, file); + init_encoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + + return true; +} + +LASpointWriter0compressed::LASpointWriter0compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + re = 0; +} + +void LASpointWriter0compressed::init_encoder() +{ + re = new RangeEncoder(file,false); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupCompressor(re, 2); + ic_dy->SetupCompressor(re, 14); + ic_z->SetupCompressor(re, 7); + + rm_changed_values = new RangeModel(64,0,1); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupCompressor(re); + + rm_bit_byte = new RangeModel(256,0,1); + rm_classification = new RangeModel(256,0,1); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupCompressor(re, 2); + + rm_user_data = new RangeModel(256,0,1); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupCompressor(re); +} + +LASpointWriter0compressed::~LASpointWriter0compressed() +{ + if (re) + { + re->done(); + + delete re; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete rm_changed_values; + delete ic_intensity; + delete rm_bit_byte; + delete rm_classification; + delete ic_scan_angle_rank; + delete rm_user_data; + delete ic_point_source_ID; + } +} diff --git a/src/laspointwriter1compressed.cpp b/src/laspointwriter1compressed.cpp new file mode 100644 index 00000000..dc18a732 --- /dev/null +++ b/src/laspointwriter1compressed.cpp @@ -0,0 +1,317 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter1compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007 martin 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 corresponding header file + +=============================================================================== +*/ + +#include +#include "laspointwriter1compressed.h" + +#define MULTI_MAX 512 + +bool LASpointWriter1compressed::write_point(LASpoint* point, double gps_time, unsigned short* rgb) +{ + if (re) + { + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // compress x y z coordinates + int x_diff = point->x - last_point.x; + int y_diff = point->y - last_point.y; + + // if there is a direction flag we use it to encode the x and y differences with different contexts + ic_dx->CompressLast(median_x, x_diff, last_dir); + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + if (messy < 0 || messy > 6) + { + ic_dy->CompressNone(y_diff); + ic_z->CompressNone(point->z); + } + else + { + ic_dy->CompressLast(median_y, y_diff, (last_dir?messy+7:messy)); + ic_z->CompressLast(last_point.z, point->z, messy); + } + + // compress which other values have changed + int changed_values = ((last_gps_time != gps_time) << 6) | + ((last_point.intensity != point->intensity) << 5) | + ((((unsigned char*)&last_point)[14] != ((unsigned char*)point)[14]) << 4) | + ((last_point.classification != point->classification) << 3) | + ((last_point.scan_angle_rank != point->scan_angle_rank) << 2) | + ((last_point.user_data != point->user_data) << 1) | + ((last_point.point_source_ID != point->point_source_ID)); + + re->encode(rm_changed_values, changed_values); + + // compress the intensity if it has changed + if (changed_values & 32) + { + ic_intensity->CompressLast(last_point.intensity, point->intensity); + } + + // compress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + re->encode(rm_bit_byte, ((unsigned char*)point)[14]); + } + + // compress the classification ... if it has changed + if (changed_values & 8) + { + re->encode(rm_classification, point->classification); + } + + // compress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + ic_scan_angle_rank->CompressLast(last_point.scan_angle_rank, point->scan_angle_rank, messy == 2); // this is the best messy + } + + // compress the user_data ... if it has changed + if (changed_values & 2) + { + re->encode(rm_user_data, point->user_data); + } + + // compress the point_source_ID ... if it has changed + if (changed_values & 1) + { + ic_point_source_ID->CompressLast(last_point.point_source_ID, point->point_source_ID); + } + + // compress the gps_time ... if it has changed + if (changed_values & 64) + { + I64 gps_time_diff = ((I64*)&(gps_time))[0] - ((I64*)&(last_gps_time))[0]; + + if (-1<<30 < gps_time_diff && gps_time_diff < 1<<30) + { + int multi = 1; + if (last_gps_time_diff) + { + multi = (int)(((float)gps_time_diff / (float)last_gps_time_diff) + 0.5); + if (multi > MULTI_MAX-2) + { + multi = MULTI_MAX-2; + } + else if (multi < 0) + { + multi = 0; + } + } + re->encode(rm_gps_time_multi[messy==2], multi); + if (multi) + if (multi == 1) + ic_gps_time->CompressLast(last_gps_time_diff, (int)gps_time_diff, 0); + else if (multi < 10) + ic_gps_time->CompressLast(multi*last_gps_time_diff, (int)gps_time_diff, 1); + else + ic_gps_time->CompressLast(multi*last_gps_time_diff, (int)gps_time_diff, 2); + else + ic_gps_time->CompressNone((int)gps_time_diff); + + if (multi == 1 || multi_extreme_counter > 3) + { + last_gps_time_diff = (int)gps_time_diff; + multi_extreme_counter = 0; + } + else if (multi == 0 || multi == MULTI_MAX-2) + { + multi_extreme_counter++; + } + } + else + { + re->encode(rm_gps_time_multi[messy==2], MULTI_MAX-1); + re->writeDouble(gps_time); + } + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fwrite(point, sizeof(LASpoint), 1, file); + fwrite(&(gps_time), sizeof(double), 1, file); + init_encoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_gps_time = gps_time; + + return true; +} + +LASpointWriter1compressed::LASpointWriter1compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + last_gps_time = 0; + last_gps_time_diff = 0; + re = 0; +} + +void LASpointWriter1compressed::init_encoder() +{ + re = new RangeEncoder(file,false); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupCompressor(re, 2); + ic_dy->SetupCompressor(re, 14); + ic_z->SetupCompressor(re, 7); + + rm_changed_values = new RangeModel(128,0,1); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupCompressor(re); + + rm_bit_byte = new RangeModel(256,0,1); + rm_classification = new RangeModel(256,0,1); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupCompressor(re, 2); + + rm_user_data = new RangeModel(256,0,1); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupCompressor(re); + + rm_gps_time_multi = new RangeModel*[2]; + for (int i = 0; i < 2; i++) rm_gps_time_multi[i] = new RangeModel(MULTI_MAX,0,1); + + ic_gps_time = new IntegerCompressorContext(); + ic_gps_time->SetPrecision(32); + ic_gps_time->SetupCompressor(re, 3); + + multi_extreme_counter = 0; +} + +LASpointWriter1compressed::~LASpointWriter1compressed() +{ + if (re) + { + re->done(); + + delete re; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete rm_changed_values; + delete ic_intensity; + delete rm_bit_byte; + delete rm_classification; + delete ic_scan_angle_rank; + delete rm_user_data; + delete ic_point_source_ID; + for (int i = 0; i < 2; i++) delete rm_gps_time_multi[i]; + delete [] rm_gps_time_multi; + delete ic_gps_time; + } +} diff --git a/src/laspointwriter2compressed.cpp b/src/laspointwriter2compressed.cpp new file mode 100644 index 00000000..0debaa37 --- /dev/null +++ b/src/laspointwriter2compressed.cpp @@ -0,0 +1,277 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter2compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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 corresponding header file + +=============================================================================== +*/ + +#include "laspointwriter2compressed.h" + +bool LASpointWriter2compressed::write_point(LASpoint* point, double gps_time, unsigned short* rgb) +{ + if (re) + { + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // compress x y z coordinates + int x_diff = point->x - last_point.x; + int y_diff = point->y - last_point.y; + + // if there is a direction flag we use it to encode the x and y differences with different contexts + ic_dx->CompressLast(median_x, x_diff, last_dir); + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + if (messy < 0 || messy > 6) + { + ic_dy->CompressNone(y_diff); + ic_z->CompressNone(point->z); + } + else + { + ic_dy->CompressLast(median_y, y_diff, (last_dir?messy+7:messy)); + ic_z->CompressLast(last_point.z, point->z, messy); + } + + // compress which other values have changed + int changed_values = ((last_rgb[0] != rgb[0] || last_rgb[1] != rgb[1] || last_rgb[2] != rgb[2]) << 6) | + ((last_point.intensity != point->intensity) << 5) | + ((((unsigned char*)&last_point)[14] != ((unsigned char*)point)[14]) << 4) | + ((last_point.classification != point->classification) << 3) | + ((last_point.scan_angle_rank != point->scan_angle_rank) << 2) | + ((last_point.user_data != point->user_data) << 1) | + ((last_point.point_source_ID != point->point_source_ID)); + + re->encode(rm_changed_values, changed_values); + + // compress the intensity if it has changed + if (changed_values & 32) + { + ic_intensity->CompressLast(last_point.intensity, point->intensity); + } + + // compress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + re->encode(rm_bit_byte, ((unsigned char*)point)[14]); + } + + // compress the classification ... if it has changed + if (changed_values & 8) + { + re->encode(rm_classification, point->classification); + } + + // compress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + ic_scan_angle_rank->CompressLast(last_point.scan_angle_rank, point->scan_angle_rank, messy == 2); // this is the best messy + } + + // compress the user_data ... if it has changed + if (changed_values & 2) + { + re->encode(rm_user_data, point->user_data); + } + + // compress the point_source_ID ... if it has changed + if (changed_values & 1) + { + ic_point_source_ID->CompressLast(last_point.point_source_ID, point->point_source_ID); + } + + // compress the rgb color ... if it has changed + if (changed_values & 64) + { + ic_r->CompressLast(last_rgb[0], rgb[0]); + ic_g->CompressLast(last_rgb[1], rgb[1]); + ic_b->CompressLast(last_rgb[2], rgb[2]); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fwrite(point, sizeof(LASpoint), 1, file); + fwrite(rgb, sizeof(unsigned short), 3, file); + init_encoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_rgb[0] = rgb[0]; + last_rgb[1] = rgb[1]; + last_rgb[2] = rgb[2]; + + return true; +} + +LASpointWriter2compressed::LASpointWriter2compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + re = 0; +} + +void LASpointWriter2compressed::init_encoder() +{ + re = new RangeEncoder(file,false); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupCompressor(re, 2); + ic_dy->SetupCompressor(re, 14); + ic_z->SetupCompressor(re, 7); + + rm_changed_values = new RangeModel(128,0,1); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupCompressor(re); + + rm_bit_byte = new RangeModel(256,0,1); + rm_classification = new RangeModel(256,0,1); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupCompressor(re, 2); + + rm_user_data = new RangeModel(256,0,1); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupCompressor(re); + + ic_r = new IntegerCompressorContext(); + ic_g = new IntegerCompressorContext(); + ic_b = new IntegerCompressorContext(); + + ic_r->SetPrecision(16); + ic_g->SetPrecision(16); + ic_b->SetPrecision(16); + + ic_r->SetupCompressor(re); + ic_g->SetupCompressor(re); + ic_b->SetupCompressor(re); +} + +LASpointWriter2compressed::~LASpointWriter2compressed() +{ + if (re) + { + re->done(); + + delete re; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete rm_changed_values; + delete ic_intensity; + delete rm_bit_byte; + delete rm_classification; + delete ic_scan_angle_rank; + delete rm_user_data; + delete ic_point_source_ID; + delete ic_r; + delete ic_g; + delete ic_b; + } +} diff --git a/src/laspointwriter3compressed.cpp b/src/laspointwriter3compressed.cpp new file mode 100644 index 00000000..9f18fda3 --- /dev/null +++ b/src/laspointwriter3compressed.cpp @@ -0,0 +1,344 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laspointwriter3compressed.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2008 martin 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 corresponding header file + +=============================================================================== +*/ + +#include +#include "laspointwriter3compressed.h" + +#define MULTI_MAX 512 + +bool LASpointWriter3compressed::write_point(LASpoint* point, double gps_time, unsigned short* rgb) +{ + if (re) + { + // find the median difference among the three preceding differences + int median_x; + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][1]) + { + if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][1]; + else if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][0]; + } + else + { + if (last_x_diff[last_dir][0] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][0]; + else if (last_x_diff[last_dir][1] < last_x_diff[last_dir][2]) + median_x = last_x_diff[last_dir][2]; + else + median_x = last_x_diff[last_dir][1]; + } + + int median_y; + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][1]) + { + if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][1]; + else if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][0]; + } + else + { + if (last_y_diff[last_dir][0] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][0]; + else if (last_y_diff[last_dir][1] < last_y_diff[last_dir][2]) + median_y = last_y_diff[last_dir][2]; + else + median_y = last_y_diff[last_dir][1]; + } + + // compress x y z coordinates + int x_diff = point->x - last_point.x; + int y_diff = point->y - last_point.y; + + // if there is a direction flag we use it to encode the x and y differences with different contexts + ic_dx->CompressLast(median_x, x_diff, last_dir); + + // we use the difference between the x diff prediction and the acual value to switch contexts + float messy_measure = (float)x_diff/(float)median_x; + int messy = (int)((messy_measure-0.5f)/0.2f); + + if (messy < 0 || messy > 6) + { + ic_dy->CompressNone(y_diff); + ic_z->CompressNone(point->z); + } + else + { + ic_dy->CompressLast(median_y, y_diff, (last_dir?messy+7:messy)); + ic_z->CompressLast(last_point.z, point->z, messy); + } + + // compress which other values have changed + int changed_values = ((last_rgb[0] != rgb[0] || last_rgb[1] != rgb[1] || last_rgb[2] != rgb[2]) << 7) | + ((last_gps_time != gps_time) << 6) | + ((last_point.intensity != point->intensity) << 5) | + ((((unsigned char*)&last_point)[14] != ((unsigned char*)point)[14]) << 4) | + ((last_point.classification != point->classification) << 3) | + ((last_point.scan_angle_rank != point->scan_angle_rank) << 2) | + ((last_point.user_data != point->user_data) << 1) | + ((last_point.point_source_ID != point->point_source_ID)); + + re->encode(rm_changed_values, changed_values); + + // compress the intensity if it has changed + if (changed_values & 32) + { + ic_intensity->CompressLast(last_point.intensity, point->intensity); + } + + // compress the edge_of_flight_line, scan_direction_flag, ... if it has changed + if (changed_values & 16) + { + re->encode(rm_bit_byte, ((unsigned char*)point)[14]); + } + + // compress the classification ... if it has changed + if (changed_values & 8) + { + re->encode(rm_classification, point->classification); + } + + // compress the scan_angle_rank ... if it has changed + if (changed_values & 4) + { + ic_scan_angle_rank->CompressLast(last_point.scan_angle_rank, point->scan_angle_rank, messy == 2); // this is the best messy + } + + // compress the user_data ... if it has changed + if (changed_values & 2) + { + re->encode(rm_user_data, point->user_data); + } + + // compress the point_source_ID ... if it has changed + if (changed_values & 1) + { + ic_point_source_ID->CompressLast(last_point.point_source_ID, point->point_source_ID); + } + + if (changed_values & 64) + { + __int64 gps_time_diff = ((__int64*)&(gps_time))[0] - ((__int64*)&(last_gps_time))[0]; + + if (-1<<30 < gps_time_diff && gps_time_diff < 1<<30) + { + int multi = 1; + if (last_gps_time_diff) + { + multi = (int)(((float)gps_time_diff / (float)last_gps_time_diff) + 0.5); + if (multi > MULTI_MAX-2) + { + multi = MULTI_MAX-2; + } + else if (multi < 0) + { + multi = 0; + } + } + re->encode(rm_gps_time_multi[messy==2], multi); + if (multi) + if (multi == 1) + ic_gps_time->CompressLast(last_gps_time_diff, (int)gps_time_diff, 0); + else if (multi < 10) + ic_gps_time->CompressLast(multi*last_gps_time_diff, (int)gps_time_diff, 1); + else + ic_gps_time->CompressLast(multi*last_gps_time_diff, (int)gps_time_diff, 2); + else + ic_gps_time->CompressNone((int)gps_time_diff); + + if (multi == 1 || multi_extreme_counter > 3) + { + last_gps_time_diff = (int)gps_time_diff; + multi_extreme_counter = 0; + } + else if (multi == 0 || multi == MULTI_MAX-2) + { + multi_extreme_counter++; + } + } + else + { + re->encode(rm_gps_time_multi[messy==2], MULTI_MAX-1); + re->writeDouble(gps_time); + } + } + + // compress the rgb color ... if it has changed + if (changed_values & 64) + { + ic_r->CompressLast(last_rgb[0], rgb[0]); + ic_g->CompressLast(last_rgb[1], rgb[1]); + ic_b->CompressLast(last_rgb[2], rgb[2]); + } + + // only record the difference if the scan direction has not changed + if (last_dir == point->scan_direction_flag) + { + last_x_diff[last_dir][last_incr[last_dir]] = x_diff; + last_y_diff[last_dir][last_incr[last_dir]] = y_diff; + + last_incr[last_dir]++; + if (last_incr[last_dir] > 2) last_incr[last_dir] = 0; + } + } + else + { + fwrite(point, sizeof(LASpoint), 1, file); + fwrite(&(gps_time), sizeof(double), 1, file); + fwrite(rgb, sizeof(unsigned short), 3, file); + init_encoder(); + } + + last_dir = point->scan_direction_flag; + last_point = *point; + last_gps_time = gps_time; + last_rgb[0] = rgb[0]; + last_rgb[1] = rgb[1]; + last_rgb[2] = rgb[2]; + + return true; +} + +LASpointWriter3compressed::LASpointWriter3compressed(FILE* file) +{ + this->file = file; + last_dir = 0; + last_x_diff[0][0] = last_x_diff[0][1] = last_x_diff[0][2] = last_x_diff[1][0] = last_x_diff[1][1] = last_x_diff[1][2] = 0; + last_y_diff[0][0] = last_y_diff[0][1] = last_y_diff[0][2] = last_y_diff[1][0] = last_y_diff[1][1] = last_y_diff[1][2] = 0; + last_incr[0] = last_incr[1] = 0; + last_gps_time = 0; + last_gps_time_diff = 0; + re = 0; +} + +void LASpointWriter3compressed::init_encoder() +{ + re = new RangeEncoder(file,false); + + ic_dx = new IntegerCompressorContext(); + ic_dy = new IntegerCompressorContext(); + ic_z = new IntegerCompressorContext(); + + ic_dx->SetPrecision(32); + ic_dy->SetPrecision(32); + ic_z->SetPrecision(32); + + ic_dx->SetupCompressor(re, 2); + ic_dy->SetupCompressor(re, 14); + ic_z->SetupCompressor(re, 7); + + rm_changed_values = new RangeModel(256,0,1); + + ic_intensity = new IntegerCompressorContext(); + ic_intensity->SetPrecision(16); + ic_intensity->SetupCompressor(re); + + rm_bit_byte = new RangeModel(256,0,1); + rm_classification = new RangeModel(256,0,1); + + ic_scan_angle_rank = new IntegerCompressorContext(); + ic_scan_angle_rank->SetPrecision(8); + ic_scan_angle_rank->SetupCompressor(re, 2); + + rm_user_data = new RangeModel(256,0,1); + + ic_point_source_ID = new IntegerCompressorContext(); + ic_point_source_ID->SetPrecision(16); + ic_point_source_ID->SetupCompressor(re); + + rm_gps_time_multi = new RangeModel*[2]; + for (int i = 0; i < 2; i++) rm_gps_time_multi[i] = new RangeModel(MULTI_MAX,0,1); + + ic_gps_time = new IntegerCompressorContext(); + ic_gps_time->SetPrecision(32); + ic_gps_time->SetupCompressor(re, 3); + + multi_extreme_counter = 0; + + ic_r = new IntegerCompressorContext(); + ic_g = new IntegerCompressorContext(); + ic_b = new IntegerCompressorContext(); + + ic_r->SetPrecision(16); + ic_g->SetPrecision(16); + ic_b->SetPrecision(16); + + ic_r->SetupCompressor(re); + ic_g->SetupCompressor(re); + ic_b->SetupCompressor(re); +} + +LASpointWriter3compressed::~LASpointWriter3compressed() +{ + if (re) + { + re->done(); + + delete re; + delete ic_dx; + delete ic_dy; + delete ic_z; + delete rm_changed_values; + delete ic_intensity; + delete rm_bit_byte; + delete rm_classification; + delete ic_scan_angle_rank; + delete rm_user_data; + delete ic_point_source_ID; + for (int i = 0; i < 2; i++) delete rm_gps_time_multi[i]; + delete [] rm_gps_time_multi; + delete ic_gps_time; + delete ic_r; + delete ic_g; + delete ic_b; + } +} diff --git a/src/lasreader.cpp b/src/lasreader.cpp new file mode 100644 index 00000000..f8923706 --- /dev/null +++ b/src/lasreader.cpp @@ -0,0 +1,681 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: lasreader.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007-2008 martin 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 corresponding header file + +=============================================================================== +*/ +#include "lasreader.h" + +#define ENABLE_LAS_COMPRESSION_SUPPORT +//#undef ENABLE_LAS_COMPRESSION_SUPPORT + +#include "laspointreader0raw.h" +#include "laspointreader1raw.h" +#include "laspointreader2raw.h" +#include "laspointreader3raw.h" + +#ifdef ENABLE_LAS_COMPRESSION_SUPPORT +#include "laspointreader0compressed.h" +#include "laspointreader1compressed.h" +#include "laspointreader2compressed.h" +#include "laspointreader3compressed.h" +#endif // ENABLE_LAS_COMPRESSION_SUPPORT + +#ifdef _WIN32 +#include +#include +#endif + +#include +#include + +bool LASreader::open(FILE* file, bool skip_all_headers) +{ + int i; + + if (file == 0) + { + fprintf(stderr,"ERROR: file pointer is zero\n"); + return false; + } + +#ifdef _WIN32 + if (file == stdin) + { + if(_setmode( _fileno( stdin ), _O_BINARY ) == -1 ) + { + fprintf(stderr, "ERROR: cannot set stdin to binary (untranslated) mode\n"); + } + } +#endif + + this->file = file; + + // clean the header + header.clean(); + + // read the header variable after variable (to avoid alignment issues) + + if (fread(&(header.file_signature), sizeof(char), 4, file) != 4) + { + fprintf(stderr,"ERROR: reading header.file_signature\n"); + return false; + } + if (fread(&(header.file_source_id), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.file_source_id\n"); + return false; + } + if (fread(&(header.global_encoding), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.global_encoding\n"); + return false; + } + if (fread(&(header.project_ID_GUID_data_1), sizeof(unsigned int), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.project_ID_GUID_data_1\n"); + return false; + } + if (fread(&(header.project_ID_GUID_data_2), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.project_ID_GUID_data_2\n"); + return false; + } + if (fread(&(header.project_ID_GUID_data_3), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.project_ID_GUID_data_3\n"); + return false; + } + if (fread(&(header.project_ID_GUID_data_4), sizeof(char), 8, file) != 8) + { + fprintf(stderr,"ERROR: reading header.project_ID_GUID_data_4\n"); + return false; + } + if (fread(&(header.version_major), sizeof(char), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.version_major\n"); + return false; + } + if (fread(&(header.version_minor), sizeof(char), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.version_minor\n"); + return false; + } + if (fread(&(header.system_identifier), sizeof(char), 32, file) != 32) + { + fprintf(stderr,"ERROR: reading header.system_identifier\n"); + return false; + } + if (fread(&(header.generating_software), sizeof(char), 32, file) != 32) + { + fprintf(stderr,"ERROR: reading header.generating_software\n"); + return false; + } + if (fread(&(header.file_creation_day), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.file_creation_day\n"); + return false; + } + if (fread(&(header.file_creation_year), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.file_creation_year\n"); + return false; + } + if (fread(&(header.header_size), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.header_size\n"); + return false; + } + if (fread(&(header.offset_to_point_data), sizeof(unsigned int), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.offset_to_point_data\n"); + return false; + } + if (fread(&(header.number_of_variable_length_records), sizeof(unsigned int), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.number_of_variable_length_records\n"); + return false; + } + if (fread(&(header.point_data_format), sizeof(unsigned char), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.point_data_format\n"); + return false; + } + if (fread(&(header.point_data_record_length), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.point_data_record_length\n"); + return false; + } + if (fread(&(header.number_of_point_records), sizeof(unsigned int), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.number_of_point_records\n"); + return false; + } + if (fread(&(header.number_of_points_by_return), sizeof(unsigned int), 5, file) != 5) + { + fprintf(stderr,"ERROR: reading header.number_of_points_by_return\n"); + return false; + } + if (fread(&(header.x_scale_factor), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.x_scale_factor\n"); + return false; + } + if (fread(&(header.y_scale_factor), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.y_scale_factor\n"); + return false; + } + if (fread(&(header.z_scale_factor), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.z_scale_factor\n"); + return false; + } + if (fread(&(header.x_offset), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.x_offset\n"); + return false; + } + if (fread(&(header.y_offset), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.y_offset\n"); + return false; + } + if (fread(&(header.z_offset), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.z_offset\n"); + return false; + } + if (fread(&(header.max_x), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.max_x\n"); + return false; + } + if (fread(&(header.min_x), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.min_x\n"); + return false; + } + if (fread(&(header.max_y), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.max_y\n"); + return false; + } + if (fread(&(header.min_y), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.min_y\n"); + return false; + } + if (fread(&(header.max_z), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.max_z\n"); + return false; + } + if (fread(&(header.min_z), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.min_z\n"); + return false; + } + + // check header contents + + if (strncmp(header.file_signature, "LASF", 4) != 0) + { + fprintf(stderr,"ERROR: wrong file signature '%s'\n", header.file_signature); + return false; + } + if ((header.version_major != 1) || ((header.version_minor != 0) && (header.version_minor != 1) && (header.version_minor != 2))) + { + fprintf(stderr,"WARNING: unknown version %d.%d (should be 1.0 or 1.1 or 1.2)\n", header.version_major, header.version_minor); + } + if (header.header_size < 227) + { + fprintf(stderr,"WARNING: header size is %d but should be at least 227\n", header.header_size); + } + if (header.offset_to_point_data < header.header_size) + { + fprintf(stderr,"ERROR: offset to point data %d is smaller than header size %d\n", header.offset_to_point_data, header.header_size); + return false; + } + if (header.number_of_point_records <= 0) + { + fprintf(stderr,"WARNING: number of point records is %d\n", header.number_of_point_records); + } + if ((header.point_data_format & 127) == 0) + { + if (header.point_data_record_length != 20) + { + fprintf(stderr,"WARNING: wrong point data record length of %d instead of 20 for format 0\n", header.point_data_record_length); + if (header.point_data_record_length > 20) + { + additional_bytes_per_point = header.point_data_record_length - 20; + fprintf(stderr,"WARNING: skipping the %d additional bytes per point\n", additional_bytes_per_point); + } + header.point_data_record_length = 20; + } + } + else if ((header.point_data_format & 127) == 1) + { + if (header.point_data_record_length != 28) + { + fprintf(stderr,"WARNING: wrong point data record length of %d instead of 28 for format 1\n", header.point_data_record_length); + if (header.point_data_record_length > 28) + { + additional_bytes_per_point = header.point_data_record_length - 28; + fprintf(stderr,"WARNING: skipping the %d additional bytes per point\n", additional_bytes_per_point); + } + header.point_data_record_length = 28; + } + } + else if ((header.point_data_format & 127) == 2) + { + if (header.point_data_record_length != 26) + { + fprintf(stderr,"WARNING: wrong point data record length of %d instead of 26 for format 2\n", header.point_data_record_length); + if (header.point_data_record_length > 26) + { + additional_bytes_per_point = header.point_data_record_length - 26; + fprintf(stderr,"WARNING: skipping the %d additional bytes per point\n", additional_bytes_per_point); + } + header.point_data_record_length = 26; + } + } + else if ((header.point_data_format & 127) == 3) + { + if (header.point_data_record_length != 34) + { + fprintf(stderr,"WARNING: wrong point data record length of %d instead of 34 for format 3\n", header.point_data_record_length); + if (header.point_data_record_length > 34) + { + additional_bytes_per_point = header.point_data_record_length - 34; + fprintf(stderr,"WARNING: skipping the %d additional bytes per point\n", additional_bytes_per_point); + } + header.point_data_record_length = 34; + } + } + else + { + fprintf(stderr,"WARNING: unknown point data format %d ... assuming format 0\n", header.point_data_format); + if (header.point_data_record_length != 20) + { + fprintf(stderr,"WARNING: wrong point data record length of %d instead of 20 for format 0\n", header.point_data_record_length); + if (header.point_data_record_length > 20) + { + additional_bytes_per_point = header.point_data_record_length - 20; + fprintf(stderr,"WARNING: skipping the %d additional bytes per point\n", additional_bytes_per_point); + } + header.point_data_record_length = 20; + } + header.point_data_format = 0; + } + if (header.x_scale_factor == 0 || header.y_scale_factor == 0 || header.z_scale_factor == 0) + { + fprintf(stderr,"WARNING: some scale factors are zero %g %g %g. will set them to 0.01.\n", header.x_scale_factor, header.y_scale_factor, header.z_scale_factor); + if (header.x_scale_factor == 0) header.x_scale_factor = 0.01; + if (header.y_scale_factor == 0) header.y_scale_factor = 0.01; + if (header.z_scale_factor == 0) header.z_scale_factor = 0.01; + } + if (header.max_x < header.min_x || header.max_y < header.min_y || header.max_z < header.min_z) + { + fprintf(stderr,"WARNING: invalid bounding box [ %g %g %g / %g %g %g ]\n", header.min_x, header.min_y, header.min_z, header.max_x, header.max_y, header.max_z); + } + + // load any number of user-defined bytes that might have been added to the header + header.user_data_in_header_size = header.header_size - 227; + if (header.user_data_in_header_size) + { + header.user_data_in_header = new char[header.user_data_in_header_size]; + + if (fread(header.user_data_in_header, sizeof(char), header.user_data_in_header_size, file) != (unsigned int)header.user_data_in_header_size) + { + fprintf(stderr,"ERROR: reading %d bytes of data into header.user_data_in_header\n", header.user_data_in_header_size); + return false; + } + } + + // create the right point reader in dependance on compression and point data format + + if (header.point_data_format & 128) + { +#ifdef ENABLE_LAS_COMPRESSION_SUPPORT + // change the format to uncompressed + header.point_data_format &= 127; + switch (header.point_data_format) + { + case 0: + pointReader = new LASpointReader0compressed(file); + points_have_gps_time = false; + points_have_rgb = false; + break; + case 1: + pointReader = new LASpointReader1compressed(file); + points_have_gps_time = true; + points_have_rgb = false; + break; + case 2: + pointReader = new LASpointReader2compressed(file); + points_have_gps_time = false; + points_have_rgb = true; + break; + case 3: + pointReader = new LASpointReader3compressed(file); + points_have_gps_time = true; + points_have_rgb = true; + break; + } +#else // ENABLE_LAS_COMPRESSION_SUPPORT + fprintf(stderr,"ERROR: this version of the lasreader does not support compression\n"); + return false; +#endif // ENABLE_LAS_COMPRESSION_SUPPORT + } + else + { + switch (header.point_data_format) + { + case 0: + pointReader = new LASpointReader0raw(file); + points_have_gps_time = false; + points_have_rgb = false; + break; + case 1: + pointReader = new LASpointReader1raw(file); + points_have_gps_time = true; + points_have_rgb = false; + break; + case 2: + pointReader = new LASpointReader2raw(file); + points_have_gps_time = false; + points_have_rgb = true; + break; + case 3: + pointReader = new LASpointReader3raw(file); + points_have_gps_time = true; + points_have_rgb = true; + break; + } + } + + if (skip_all_headers) + { + + for (i = header.header_size; i < (int)header.offset_to_point_data; i++) fgetc(file); + } + else + { + int vlrs_size = 0; + + // read the variable length records into the header + + if (header.number_of_variable_length_records) + { + header.vlrs = new LASvlr[header.number_of_variable_length_records]; + + for (i = 0; i < (int)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)header.offset_to_point_data - vlrs_size - header.header_size) < 54) + { + fprintf(stderr,"WARNING: only %d bytes until point block after reading %d of %d vlrs. skipping remaining vlrs ...\n", (int)header.offset_to_point_data - vlrs_size - header.header_size, i, header.number_of_variable_length_records); + header.number_of_variable_length_records = i; + break; + } + + // read variable length records variable after variable (to avoid alignment issues) + + if (fread(&(header.vlrs[i].reserved), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.vlrs[%d].reserved\n", i); + return false; + } + if (fread(header.vlrs[i].user_id, sizeof(char), 16, file) != 16) + { + fprintf(stderr,"ERROR: reading header.vlrs[%d].user_id\n", i); + return false; + } + if (fread(&(header.vlrs[i].record_id), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.vlrs[%d].record_id\n", i); + return false; + } + if (fread(&(header.vlrs[i].record_length_after_header), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: reading header.vlrs[%d].record_length_after_header\n", i); + return false; + } + if (fread(header.vlrs[i].description, sizeof(char), 32, file) != 32) + { + fprintf(stderr,"ERROR: reading header.vlrs[%d].description\n", i); + return false; + } + + // keep track on the number of bytes we have read so far + + vlrs_size += 54; + + // check variable length record contents + + if (header.vlrs[i].reserved != 0xAABB) + { + fprintf(stderr,"WARNING: wrong header.vlrs[%d].reserved: %d != 0xAABB\n", i, 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)header.offset_to_point_data - vlrs_size - header.header_size) < header.vlrs[i].record_length_after_header) + { + fprintf(stderr,"WARNING: only %d bytes until point block when trying to read %d bytes into header.vlrs[%d].data\n", (int)header.offset_to_point_data - vlrs_size - header.header_size, header.vlrs[i].record_length_after_header, i); + header.vlrs[i].record_length_after_header = (int)header.offset_to_point_data - vlrs_size - header.header_size; + } + + // load data following the header of the variable length record + + if (header.vlrs[i].record_length_after_header) + { + header.vlrs[i].data = new char[header.vlrs[i].record_length_after_header]; + + if (fread(header.vlrs[i].data, sizeof(char), header.vlrs[i].record_length_after_header, file) != header.vlrs[i].record_length_after_header) + { + fprintf(stderr,"ERROR: reading %d bytes of data into header.vlrs[%d].data\n", header.vlrs[i].record_length_after_header, i); + return false; + } + } + else + { + header.vlrs[i].data = 0; + } + + // keep track on the number of bytes we have read so far + + vlrs_size += header.vlrs[i].record_length_after_header; + + // special handling for known variable header tags + + if (strcmp(header.vlrs[i].user_id, "LASF_Projection") == 0) + { + if (header.vlrs[i].record_id == 34735) // GeoKeyDirectoryTag + { + if (header.vlr_geo_keys) + { + fprintf(stderr,"WARNING: variable length records contain more than one GeoKeyDirectoryTag\n"); + } + header.vlr_geo_keys = (LASvlr_geo_keys*)header.vlrs[i].data; + + // check variable header geo keys contents + + if (header.vlr_geo_keys->key_directory_version != 1) + { + fprintf(stderr,"WARNING: wrong vlr_geo_keys->key_directory_version: %d != 1\n",header.vlr_geo_keys->key_directory_version); + } + if (header.vlr_geo_keys->key_revision != 1) + { + fprintf(stderr,"WARNING: wrong vlr_geo_keys->key_revision: %d != 1\n",header.vlr_geo_keys->key_revision); + } + if (header.vlr_geo_keys->minor_revision != 0) + { + fprintf(stderr,"WARNING: wrong vlr_geo_keys->minor_revision: %d != 0\n",header.vlr_geo_keys->minor_revision); + } + header.vlr_geo_key_entries = (LASvlr_key_entry*)&header.vlr_geo_keys[1]; + } + else if (header.vlrs[i].record_id == 34736) // GeoDoubleParamsTag + { + if (header.vlr_geo_double_params) + { + fprintf(stderr,"WARNING: variable length records contain more than one GeoDoubleParamsTag\n"); + } + header.vlr_geo_double_params = (double*)header.vlrs[i].data; + } + else if (header.vlrs[i].record_id == 34737) // GeoAsciiParamsTag + { + if (header.vlr_geo_ascii_params) + { + fprintf(stderr,"WARNING: variable length records contain more than one GeoAsciiParamsTag\n"); + } + header.vlr_geo_ascii_params = (char*)header.vlrs[i].data; + } + } + } + } + + // load any number of user-defined bytes that might have been added after the header + + header.user_data_after_header_size = (int)header.offset_to_point_data - vlrs_size - header.header_size; + if (header.user_data_after_header_size) + { + header.user_data_after_header = new char[header.user_data_after_header_size]; + + if (fread(header.user_data_after_header, sizeof(char), header.user_data_after_header_size, file) != (unsigned int)header.user_data_after_header_size) + { + fprintf(stderr,"ERROR: reading %d bytes of data into header.user_data_after_header\n", header.user_data_after_header_size); + return false; + } + } + } + + gps_time = 0.0; + rgb[0] = rgb[1] = rgb[2] = 0; + npoints = header.number_of_point_records; + p_count = 0; + + return true; +} + +bool LASreader::read_point() +{ + if (p_count < npoints) + { + if (pointReader->read_point(&point, &gps_time, rgb) == false) + { + fprintf(stderr,"WARNING: end-of-file after %d of %d points\n", p_count, npoints); + return false; + } + if (additional_bytes_per_point) + { + for (int i = 0; i < additional_bytes_per_point; i++) fgetc(file); + } + p_count++; + return true; + } + return false; +} + +bool LASreader::read_point(float* coordinates) +{ + if (read_point()) + { + get_coordinates(coordinates); + return true; + } + return false; +} + +bool LASreader::read_point(double* coordinates) +{ + if (read_point()) + { + get_coordinates(coordinates); + return true; + } + return false; +} + +void LASreader::get_coordinates(float* coordinates) +{ + coordinates[0] = (float)(point.x*header.x_scale_factor+header.x_offset); + coordinates[1] = (float)(point.y*header.y_scale_factor+header.y_offset); + coordinates[2] = (float)(point.z*header.z_scale_factor+header.z_offset); +} + +void LASreader::get_coordinates(double* coordinates) +{ + coordinates[0] = point.x*header.x_scale_factor+header.x_offset; + coordinates[1] = point.y*header.y_scale_factor+header.y_offset; + coordinates[2] = point.z*header.z_scale_factor+header.z_offset; +} + +void LASreader::close() +{ + file = 0; + + if (pointReader) + { + delete pointReader; + pointReader = 0; + } +} + +LASreader::LASreader() +{ + gps_time = 0.0; + rgb[0] = rgb[1] = rgb[2] = 0; + points_have_gps_time = false; + points_have_rgb = false; + npoints = -1; + p_count = -1; + additional_bytes_per_point = 0; + file = 0; + pointReader = 0; +} + +LASreader::~LASreader() +{ +} diff --git a/src/laswriter.cpp b/src/laswriter.cpp new file mode 100644 index 00000000..6c578da8 --- /dev/null +++ b/src/laswriter.cpp @@ -0,0 +1,594 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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: laswriter.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + martin isenburg@cs.unc.edu + + COPYRIGHT: + + copyright (C) 2007-2008 martin 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 corresponding header file + +=============================================================================== +*/ +#include "laswriter.h" + +#define ENABLE_LAS_COMPRESSION_SUPPORT +//#undef ENABLE_LAS_COMPRESSION_SUPPORT + +#include "laspointwriter0raw.h" +#include "laspointwriter1raw.h" +#include "laspointwriter2raw.h" +#include "laspointwriter3raw.h" + +#ifdef ENABLE_LAS_COMPRESSION_SUPPORT +#include "laspointwriter0compressed.h" +#include "laspointwriter1compressed.h" +#include "laspointwriter2compressed.h" +#include "laspointwriter3compressed.h" +#endif // ENABLE_LAS_COMPRESSION_SUPPORT + +#ifdef _WIN32 +#include +#include +#endif + +#include +#include + +bool LASwriter::open(FILE* file, LASheader* header, int compression) +{ + int i; + + if (file == 0) + { + fprintf(stderr,"ERROR: file pointer is zero\n"); + return false; + } + this->file = file; + +#ifdef _WIN32 + if (file == stdout) + { + if(_setmode( _fileno( stdout ), _O_BINARY ) == -1 ) + { + fprintf(stderr, "ERROR: cannot set stdout to binary (untranslated) mode\n"); + } + } +#endif + + if (header == 0) + { + if (file == stdout) + { + fprintf(stderr,"ERROR: cannot use stdout without header\n"); + return false; + } + header = new LASheader(); + created_header = true; + } + this->header = header; + + // check header contents + + if (strncmp(header->file_signature, "LASF", 4) != 0) + { + fprintf(stderr,"ERROR: wrong file signature '%s'\n", header->file_signature); + return false; + } + if ((header->version_major != 1) || ((header->version_minor != 0) && (header->version_minor != 1) && (header->version_minor != 2))) + { + fprintf(stderr,"WARNING: unknown version %d.%d (should be 1.0 or 1.1 or 1.2)\n", header->version_major, header->version_minor); + } + if (header->header_size != 227) + { + fprintf(stderr,"WARNING: header size is %d but should be 227\n", header->header_size); + } + if (header->offset_to_point_data < header->header_size) + { + fprintf(stderr,"ERROR: offset to point data %d is smaller than header size %d\n", header->offset_to_point_data, header->header_size); + return false; + } + if (header->point_data_format == 0) + { + if (header->point_data_record_length != 20) + { + fprintf(stderr,"WARNING: wrong point data record length of %d instead of 20 for format 0\n", header->point_data_record_length); + } + } + else if (header->point_data_format == 1) + { + if (header->point_data_record_length != 28) + { + fprintf(stderr,"WARNING: wrong point data record length of %d instead of 28 for format 1\n", header->point_data_record_length); + } + } + else if (header->point_data_format == 2) + { + if (header->point_data_record_length != 26) + { + fprintf(stderr,"WARNING: wrong point data record length of %d instead of 26 for format 2\n", header->point_data_record_length); + } + } + else if (header->point_data_format == 3) + { + if (header->point_data_record_length != 34) + { + fprintf(stderr,"WARNING: wrong point data record length of %d instead of 34 for format 3\n", header->point_data_record_length); + } + } + else + { + fprintf(stderr,"WARNING: unknown point data format %d ... assuming format 0\n", header->point_data_format); + header->point_data_format = 0; + } + if (header->x_scale_factor == 0 || header->y_scale_factor == 0 || header->z_scale_factor == 0) + { + fprintf(stderr,"WARNING: some scale factors are zero %g %g %g. those are set to 0.01.\n", header->x_scale_factor, header->y_scale_factor, header->z_scale_factor); + if (header->x_scale_factor == 0) header->x_scale_factor = 0.01; + if (header->y_scale_factor == 0) header->y_scale_factor = 0.01; + if (header->z_scale_factor == 0) header->z_scale_factor = 0.01; + } + if (header->max_x < header->min_x || header->max_y < header->min_y || header->max_z < header->min_z) + { + fprintf(stderr,"WARNING: invalid bounding box [ %g %g %g / %g %g %g ]\n", header->min_x, header->min_y, header->min_z, header->max_x, header->max_y, header->max_z); + } + + // create the right point writer in dependance on compression and point data format + + if (compression) + { +#ifdef ENABLE_LAS_COMPRESSION_SUPPORT + switch (header->point_data_format) + { + case 0: + pointWriter = new LASpointWriter0compressed(file); + break; + case 1: + pointWriter = new LASpointWriter1compressed(file); + break; + case 2: + pointWriter = new LASpointWriter2compressed(file); + break; + case 3: + pointWriter = new LASpointWriter3compressed(file); + break; + } + // change the format to compressed + header->point_data_format |= 128; +#else // ENABLE_LAS_COMPRESSION_SUPPORT + fprintf(stderr,"ERROR: this version of the laswriter does not support compression\n"); + return false; +#endif // ENABLE_LAS_COMPRESSION_SUPPORT + } + else + { + switch (header->point_data_format) + { + case 0: + pointWriter = new LASpointWriter0raw(file); + break; + case 1: + pointWriter = new LASpointWriter1raw(file); + break; + case 2: + pointWriter = new LASpointWriter2raw(file); + break; + case 3: + pointWriter = new LASpointWriter3raw(file); + break; + } + } + + // write header variable after variable (to avoid alignment issues) + + if (fwrite(&(header->file_signature), sizeof(char), 4, file) != 4) + { + fprintf(stderr,"ERROR: writing header->file_signature\n"); + return false; + } + if (fwrite(&(header->file_source_id), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->file_source_id\n"); + return false; + } + if (fwrite(&(header->global_encoding), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->global_encoding\n"); + return false; + } + if (fwrite(&(header->project_ID_GUID_data_1), sizeof(unsigned int), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->project_ID_GUID_data_1\n"); + return false; + } + if (fwrite(&(header->project_ID_GUID_data_2), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->project_ID_GUID_data_2\n"); + return false; + } + if (fwrite(&(header->project_ID_GUID_data_3), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->project_ID_GUID_data_3\n"); + return false; + } + if (fwrite(&(header->project_ID_GUID_data_4), sizeof(char), 8, file) != 8) + { + fprintf(stderr,"ERROR: writing header->project_ID_GUID_data_4\n"); + return false; + } + if (fwrite(&(header->version_major), sizeof(char), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->version_major\n"); + return false; + } + if (fwrite(&(header->version_minor), sizeof(char), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->version_minor\n"); + return false; + } + if (fwrite(&(header->system_identifier), sizeof(char), 32, file) != 32) + { + fprintf(stderr,"ERROR: writing header->system_identifier\n"); + return false; + } + if (fwrite(&(header->generating_software), sizeof(char), 32, file) != 32) + { + fprintf(stderr,"ERROR: writing header->generating_software\n"); + return false; + } + if (fwrite(&(header->file_creation_day), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->file_creation_day\n"); + return false; + } + if (fwrite(&(header->file_creation_year), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->file_creation_year\n"); + return false; + } + if (fwrite(&(header->header_size), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->header_size\n"); + return false; + } + if (fwrite(&(header->offset_to_point_data), sizeof(unsigned int), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->offset_to_point_data\n"); + return false; + } + if (fwrite(&(header->number_of_variable_length_records), sizeof(unsigned int), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->number_of_variable_length_records\n"); + return false; + } + if (fwrite(&(header->point_data_format), sizeof(unsigned char), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->point_data_format\n"); + return false; + } + if (fwrite(&(header->point_data_record_length), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->point_data_record_length\n"); + return false; + } + if (fwrite(&(header->number_of_point_records), sizeof(unsigned int), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->number_of_point_records\n"); + return false; + } + if (fwrite(&(header->number_of_points_by_return), sizeof(unsigned int), 5, file) != 5) + { + fprintf(stderr,"ERROR: writing header->number_of_points_by_return\n"); + return false; + } + if (fwrite(&(header->x_scale_factor), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->x_scale_factor\n"); + return false; + } + if (fwrite(&(header->y_scale_factor), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->y_scale_factor\n"); + return false; + } + if (fwrite(&(header->z_scale_factor), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->z_scale_factor\n"); + return false; + } + if (fwrite(&(header->x_offset), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->x_offset\n"); + return false; + } + if (fwrite(&(header->y_offset), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->y_offset\n"); + return false; + } + if (fwrite(&(header->z_offset), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->z_offset\n"); + return false; + } + if (fwrite(&(header->max_x), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->max_x\n"); + return false; + } + if (fwrite(&(header->min_x), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->min_x\n"); + return false; + } + if (fwrite(&(header->max_y), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->max_y\n"); + return false; + } + if (fwrite(&(header->min_y), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->min_y\n"); + return false; + } + if (fwrite(&(header->max_z), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->max_z\n"); + return false; + } + if (fwrite(&(header->min_z), sizeof(double), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->min_z\n"); + return false; + } + +#ifdef ENABLE_LAS_COMPRESSION_SUPPORT + // change the format to compressed back to what it was + header->point_data_format &= 127; +#endif // ENABLE_LAS_COMPRESSION_SUPPORT + + // write any number of user-defined bytes that might have been added into the header + + if (header->user_data_in_header_size) + { + if (header->user_data_in_header == 0) + { + fprintf(stderr,"ERROR: there should be %d bytes of data in header->user_data_in_header\n", header->user_data_in_header_size); + return false; + } + + if (fwrite(header->user_data_in_header, sizeof(char), header->user_data_in_header_size, file) != (unsigned int)header->user_data_in_header_size) + { + fprintf(stderr,"ERROR: writing %d bytes of data from header->user_data_in_header\n", header->user_data_in_header_size); + return false; + } + } + + // write variable length records variable after variable (to avoid alignment issues) + + for (i = 0; i < (int)header->number_of_variable_length_records; i++) + { + // check variable length records contents + + if (header->vlrs[i].reserved != 0xAABB) + { + fprintf(stderr,"WARNING: wrong header->vlrs[%d].reserved: %d != 0xAABB\n", i, header->vlrs[i].reserved); + } + + // write variable length records variable after variable (to avoid alignment issues) + + if (fwrite(&(header->vlrs[i].reserved), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->vlrs[%d].reserved\n", i); + return false; + } + if (fwrite(header->vlrs[i].user_id, sizeof(char), 16, file) != 16) + { + fprintf(stderr,"ERROR: writing header->vlrs[%d].user_id\n", i); + return false; + } + if (fwrite(&(header->vlrs[i].record_id), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->vlrs[%d].record_id\n", i); + return false; + } + if (fwrite(&(header->vlrs[i].record_length_after_header), sizeof(unsigned short), 1, file) != 1) + { + fprintf(stderr,"ERROR: writing header->vlrs[%d].record_length_after_header\n", i); + return false; + } + if (fwrite(header->vlrs[i].description, sizeof(char), 32, file) != 32) + { + fprintf(stderr,"ERROR: writing header->vlrs[%d].description\n", i); + return false; + } + + // write the data following the header of the variable length record + + if (fwrite(header->vlrs[i].data, sizeof(char), header->vlrs[i].record_length_after_header, file) != header->vlrs[i].record_length_after_header) + { + fprintf(stderr,"ERROR: writing %d bytes of data from header->vlrs[%d].data\n", header->vlrs[i].record_length_after_header, i); + return false; + } + } + + // write any number of user-defined bytes that might have been added after the header + + if (header->user_data_after_header_size) + { + if (header->user_data_after_header == 0) + { + fprintf(stderr,"ERROR: there should be %d bytes of data in header->user_data_after_header\n", header->user_data_after_header_size); + return false; + } + + if (fwrite(header->user_data_after_header, sizeof(char), header->user_data_after_header_size, file) != (unsigned int)header->user_data_after_header_size) + { + fprintf(stderr,"ERROR: writing %d bytes of data from header->user_data_after_header\n", header->user_data_after_header_size); + return false; + } + } + + npoints = header->number_of_point_records; + p_count = 0; + + return true; +} + +bool LASwriter::write_point(LASpoint* point, double gps_time, unsigned short* rgb) +{ + p_count++; + return pointWriter->write_point(point, gps_time, rgb); +} + +bool LASwriter::write_point(double* coordinates) +{ + return write_point(coordinates[0], coordinates[1], coordinates[2]); +} + +bool LASwriter::write_point(double x, double y, double z) +{ + LASpoint point; + if (created_header) + { + if (p_count == 0) // then no header was provided + { + header->x_offset = 1000*((int)(x/1000)); + header->y_offset = 1000*((int)(y/1000)); + header->z_offset = 1000*((int)(z/1000)); + header->min_x = header->max_x = x; + header->min_y = header->max_y = y; + header->min_z = header->max_z = z; + } + else + { + if (x < header->min_x) header->min_x = x; + else if (x > header->max_x) header->max_x = x; + if (y < header->min_y) header->min_y = y; + else if (y > header->max_y) header->max_y = y; + if (z < header->min_z) header->min_z = z; + else if (z > header->max_z) header->max_z = z; + } + } + point.return_number = 1; + point.number_of_returns_of_given_pulse = 1; + if (x > header->x_offset) + point.x = (int)((x-header->x_offset)/header->x_scale_factor + 0.5); + else + point.x = (int)((x-header->x_offset)/header->x_scale_factor - 0.5); + if (y > header->y_offset) + point.y = (int)((y-header->y_offset)/header->y_scale_factor + 0.5); + else + point.y = (int)((y-header->y_offset)/header->y_scale_factor - 0.5); + if (z > header->z_offset) + point.z = (int)((z-header->z_offset)/header->z_scale_factor + 0.5); + else + point.z = (int)((z-header->z_offset)/header->z_scale_factor - 0.5); + return write_point(&point); +} + +void LASwriter::close() +{ + if (created_header) + { + unsigned int number_of_point_records = (unsigned int)p_count; + fseek(file, 107, SEEK_SET); + fwrite(&number_of_point_records, sizeof(unsigned int), 1, file); + fwrite(&number_of_point_records, sizeof(unsigned int), 1, file); + fseek(file, 155, SEEK_SET); + fwrite(&(header->x_offset), sizeof(double), 1, file); + fwrite(&(header->y_offset), sizeof(double), 1, file); + fwrite(&(header->z_offset), sizeof(double), 1, file); + // enquantize and dequantize bounding box before writing it + if (header->max_x > header->x_offset) + header->max_x = header->x_offset + ((int)((header->max_x-header->x_offset)/header->x_scale_factor + 0.5)) * header->x_scale_factor; + else + header->max_x = header->x_offset + ((int)((header->max_x-header->x_offset)/header->x_scale_factor - 0.5)) * header->x_scale_factor; + if (header->min_x > header->x_offset) + header->min_x = header->x_offset + ((int)((header->min_x-header->x_offset)/header->x_scale_factor + 0.5)) * header->x_scale_factor; + else + header->min_x = header->x_offset + ((int)((header->min_x-header->x_offset)/header->x_scale_factor - 0.5)) * header->x_scale_factor; + if (header->max_y > header->y_offset) + header->max_y = header->y_offset + ((int)((header->max_y-header->y_offset)/header->y_scale_factor + 0.5)) * header->y_scale_factor; + else + header->max_y = header->y_offset + ((int)((header->max_y-header->y_offset)/header->y_scale_factor - 0.5)) * header->y_scale_factor; + if (header->min_y > header->y_offset) + header->min_y = header->y_offset + ((int)((header->min_y-header->y_offset)/header->y_scale_factor + 0.5)) * header->y_scale_factor; + else + header->min_y = header->y_offset + ((int)((header->min_y-header->y_offset)/header->y_scale_factor - 0.5)) * header->y_scale_factor; + if (header->max_z > header->z_offset) + header->max_z = header->z_offset + ((int)((header->max_z-header->z_offset)/header->z_scale_factor + 0.5)) * header->z_scale_factor; + else + header->max_z = header->z_offset + ((int)((header->max_z-header->z_offset)/header->z_scale_factor - 0.5)) * header->z_scale_factor; + if (header->min_z > header->z_offset) + header->min_z = header->z_offset + ((int)((header->min_z-header->z_offset)/header->z_scale_factor + 0.5)) * header->z_scale_factor; + else + header->min_z = header->z_offset + ((int)((header->min_z-header->z_offset)/header->z_scale_factor - 0.5)) * header->z_scale_factor; + fwrite(&(header->max_x), sizeof(double), 1, file); + fwrite(&(header->min_x), sizeof(double), 1, file); + fwrite(&(header->max_y), sizeof(double), 1, file); + fwrite(&(header->min_y), sizeof(double), 1, file); + fwrite(&(header->max_z), sizeof(double), 1, file); + fwrite(&(header->min_z), sizeof(double), 1, file); + fseek(file, 0, SEEK_END); + delete header; + header = 0; + npoints = p_count; + } + else if (npoints && p_count != npoints) fprintf(stderr,"WARNING: written %d points but expected %d points\n", p_count, npoints); + p_count = -1; + file = 0; + if (pointWriter) + { + delete pointWriter; + pointWriter = 0; + } +} + +LASwriter::LASwriter() +{ + npoints = -1; + p_count = -1; + file = 0; + pointWriter = 0; + header = 0; + created_header = false; +} + +LASwriter::~LASwriter() +{ +} diff --git a/src/mydefs.h b/src/mydefs.h new file mode 100644 index 00000000..a829eb27 --- /dev/null +++ b/src/mydefs.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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. + * + ****************************************************************************/ + + +#ifndef MYDEFS_H +#define MYDEFS_H + +typedef unsigned int U32; +typedef unsigned short U16; +typedef unsigned char U8; + +#if defined(WIN32) // 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 int I32; +typedef short I16; +typedef signed char I8; + +typedef double F64; +typedef float F32; + +typedef int BOOL; +typedef char CHAR; + +#define F32_MAX +1.0e+30f +#define F32_MIN -1.0e+30f + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#endif diff --git a/src/rangedecoder.cpp b/src/rangedecoder.cpp new file mode 100644 index 00000000..52275be6 --- /dev/null +++ b/src/rangedecoder.cpp @@ -0,0 +1,327 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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.h" + +inline void RangeDecoder::normalize() +{ + while (range <= BOTTOM_VALUE) + { + low = (low<<8) | ((buffer<> (8-EXTRA_BITS); + range <<= 8; + } +} + +unsigned int RangeDecoder::decode(RangeModel* rm) +{ + unsigned int sym; + unsigned int ltfreq; + unsigned int syfreq; + unsigned int tmp; + unsigned int lg_totf = rm->lg_totf; + + normalize(); + help = this->range>>lg_totf; + ltfreq = low/help; +#ifdef EXTRAFAST + ltfreq = ltfreq; +#else + ltfreq = ((ltfreq>>lg_totf) ? (1<getsym(ltfreq); + rm->getfreq(sym,&syfreq,<freq); + + tmp = help * ltfreq; + low -= tmp; +#ifdef EXTRAFAST + this->range = help * syfreq; +#else + if ((ltfreq + syfreq) < (unsigned int)(1<range = help * syfreq; + } + else + { + this->range -= tmp; + } +#endif + + rm->update(sym); + + return sym; +} + +unsigned int RangeDecoder::readBits(unsigned int bits) +{ + unsigned int tmp; + if (bits > 21) // 22 bits + { + tmp = readShort(); + unsigned int tmp1 = readBits(bits - 16) << 16; + return (tmp1|tmp); + } + tmp = culshift(bits); + update(1, tmp, (unsigned int)1< 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; +} + +/* Decode a range without modelling */ +U64 RangeDecoder::readRange64(U64 range) +{ + if (range > 4294967295) // 32 bits + { + U64 tmp; + U64 tmp1; + tmp = readInt(); + range = range >> 32; + range++; + tmp1 = readRange((unsigned int)(range)) << 32; + return (tmp1|tmp); + } + else + { + return readRange((unsigned int)(range)); + } +} + +/* Decode a byte without modelling */ +unsigned char RangeDecoder::readByte() +{ + unsigned char tmp = culshift(8); + update(1, tmp, (unsigned int)1<<8); + return tmp; +} + +/* Decode a short without modelling */ +unsigned short RangeDecoder::readShort() +{ + unsigned short tmp = culshift(16); + update(1, tmp, (unsigned int)1<<16); + return tmp; +} + +/* Decode an unsigned int without modelling */ +unsigned int RangeDecoder::readInt() +{ + unsigned int lowerInt = readShort(); + unsigned int upperInt = readShort(); + return upperInt*65536+lowerInt; +} + +/* Decode a float without modelling */ +float RangeDecoder::readFloat() +{ + float f; + *((unsigned int*)(&f)) = readInt(); + return f; +} + +/* Decode an unsigned int64 without modelling */ +U64 RangeDecoder::readInt64() +{ + U64 lowerInt = readInt(); + U64 upperInt = readInt(); + return upperInt*4294967296+lowerInt; +} + +/* Decode a double without modelling */ +double RangeDecoder::readDouble() +{ + double d; + *((U64*)(&d)) = readInt64(); + return d; +} + +/* Finish decoding */ +void RangeDecoder::done() +{ + normalize(); /* normalize to use up all bytes */ +} + +unsigned int RangeDecoder::culshift(unsigned int shift) +{ + unsigned int tmp; + normalize(); + help = range>>shift; + tmp = low/help; +#ifdef EXTRAFAST + return tmp; +#else + return (tmp>>shift ? ((unsigned int)1<range = help * sy_f; +#else + if (lt_f + sy_f < tot_f) + { + this->range = help * sy_f; + } + else + { + this->range -= tmp; + } +#endif +} + +RangeDecoder::RangeDecoder(unsigned char* chars, int number_chars) +{ + this->chars = chars; + this->number_chars = number_chars; + current_char = 0; + fp = 0; + + buffer = inbyte(); + if (buffer != HEADERBYTE) + { + fprintf(stderr, "RangeDecoder: wrong HEADERBYTE of %d. is should be %d\n", buffer, HEADERBYTE); + return; + } + buffer = inbyte(); + low = buffer >> (8-EXTRA_BITS); + range = (unsigned int)1 << EXTRA_BITS; +} + +RangeDecoder::RangeDecoder(FILE* fp) +{ + chars = 0; + number_chars = 0; + current_char = 0; + this->fp = fp; + + buffer = inbyte(); + if (buffer != HEADERBYTE) + { + fprintf(stderr, "RangeDecoder: wrong HEADERBYTE of %d. is should be %d\n", buffer, HEADERBYTE); + return; + } + buffer = inbyte(); + low = buffer >> (8-EXTRA_BITS); + range = (unsigned int)1 << EXTRA_BITS; +} + +RangeDecoder::~RangeDecoder() +{ + if (fp) + { + fclose(fp); + } +} + +inline unsigned int RangeDecoder::inbyte() +{ + int c; + if (fp) + { + c = getc(fp); + } + else + { + if (current_char < number_chars) + { + c = chars[current_char++]; + } + else + { + c = EOF; + } + } + return c; +} diff --git a/src/rangedecoder.h b/src/rangedecoder.h new file mode 100644 index 00000000..e6ef914f --- /dev/null +++ b/src/rangedecoder.h @@ -0,0 +1,124 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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.h + + 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: + + 14 January 2003 -- adapted from michael schindler's code before SIGGRAPH + +=============================================================================== +*/ +#ifndef RANGEDECODER_H +#define RANGEDECODER_H + +#include + +#include "rangemodel.h" +#include "mydefs.h" + +class RangeDecoder +{ +public: + +/* Start the decoder */ + RangeDecoder(unsigned char* chars, int number_chars); + RangeDecoder(FILE* fp); + + ~RangeDecoder(); + +/* Decode with modelling */ + unsigned int decode(RangeModel* rm); + +/* Decode bits without modelling */ + unsigned int readBits(unsigned int bits); + +/* Decode a range without modelling */ + unsigned int readRange(unsigned int range); + +/* Decode a range without modelling */ + U64 readRange64(U64 range); + +/* Decode an unsigned char without modelling */ + unsigned char readByte(); + +/* Decode an unsigned short without modelling */ + unsigned short readShort(); + +/* Decode an unsigned int without modelling */ + unsigned int readInt(); + +/* Decode a float without modelling (endian-ness dependent) */ + float readFloat(); + +/* Decode an unsigned int64 without modelling */ + U64 readInt64(); + +/* Decode a double without modelling */ + double readDouble(); + +/* Finish decoding */ + void done(); + +private: +/* Calculate culmulative frequency for next symbol. Does NO update!*/ +/* tot_f is the total frequency */ +/* or: totf is 1< +#include +#include + +RangeEncoder::RangeEncoder(FILE* fp, bool store_chars) +{ + if (fp) + { + this->fp = fp; + chars = 0; + number_chars = 0; + } + else + { + this->fp = 0; + if (store_chars) + { + chars = (unsigned char*)malloc(sizeof(unsigned char)*1000); + number_chars = 0; + allocated_chars = 1000; + } + else + { + chars = 0; + number_chars = 0; + } + } + 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 */ + bytecount = 0; +} + +void RangeEncoder::encode(RangeModel* rm, unsigned int sym) +{ + unsigned int syfreq; + unsigned int ltfreq; + unsigned int r, tmp; + unsigned int lg_totf = rm->lg_totf; + + assert(sym >= 0 && sym < (unsigned int)rm->n); + + rm->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 + + rm->update(sym); +} + +void RangeEncoder::writeBits(unsigned int bits, unsigned int sym) +{ + assert(bits && (sym < (1u< 21) // 22 bits + { + writeShort(sym&65535); + sym = sym >> 16; + bits = bits - 16; + } + + unsigned int 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::writeRange(unsigned int range, unsigned int sym) +{ + assert(range && (sym < range)); + + if (range > 4194303) // 22 bits + { + writeShort(sym&65535); + sym = sym >> 16; + range = range >> 16; + range++; + } + unsigned int 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 > 4294967295) // 32 bits + { + writeInt((unsigned int)(sym&4294967295)); + sym = sym >> 32; + range = range >> 32; + range++; + } + writeRange((unsigned int)range, (unsigned int)sym); +} + +void RangeEncoder::writeByte(unsigned char c) +{ + unsigned int r, tmp; + normalize(); + r = range >> 8; + tmp = r * (unsigned int)(c); + low += tmp; +#ifdef EXTRAFAST + range = r; +#else + if (((unsigned int)(c)+1) >> 8) + { + range -= tmp; + } + else + { + range = r; + } +#endif +} + +void RangeEncoder::writeShort(unsigned short s) +{ + unsigned int r, tmp; + normalize(); + r = range >> 16; + tmp = r * (unsigned int)(s); + low += tmp; +#ifdef EXTRAFAST + range = r; +#else + if (((unsigned int)(s)+1) >> 16) + { + range -= tmp; + } + else + { + range = r; + } +#endif +} + +void RangeEncoder::writeInt(unsigned int i) +{ + writeShort((unsigned short)(i % 65536)); // lower 16 bits + writeShort((unsigned short)(i / 65536)); // UPPER 16 bits +} + +void RangeEncoder::writeInt64(U64 l) +{ + writeInt((unsigned int)(l % 4294967296)); // lower 32 bits + writeInt((unsigned int)(l / 4294967296)); // UPPER 32 bits +} + +void RangeEncoder::writeFloat(float f) +{ + writeInt(*((unsigned int*)(&f))); +} + +void RangeEncoder::writeDouble(double d) +{ + writeInt64(*((U64*)(&d))); +} + +/* 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 < (unsigned int)0xff< output */ + { + outbyte(buffer); + for(; help; help--) + { + outbyte(0xff); + } + buffer = (unsigned char)(low >> SHIFT_BITS); + } + else if (low & TOP_VALUE) /* carry now, no future carry */ + { + outbyte(buffer+1); + for(; help; help--) + { + outbyte(0); + } + buffer = (unsigned char)(low >> SHIFT_BITS); + } + else /* passes on a potential carry */ + { + help++; + } + range <<= 8; + low = (low<<8) & (TOP_VALUE-1); + bytecount++; + } +} + +/* 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 */ +unsigned int RangeEncoder::done() +{ + unsigned int 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 */ + { + outbyte(buffer+1); + for(; help; help--) + { + outbyte(0); + } + } + else /* no carry */ + { + outbyte(buffer); + for(; help; help--) + { + outbyte(0xff); + } + } + outbyte(tmp & 0xff); + outbyte((bytecount>>16) & 0xff); + outbyte((bytecount>>8) & 0xff); + outbyte(bytecount & 0xff); + return bytecount; +} + +RangeEncoder::~RangeEncoder() +{ + if (chars) + { + free(chars); + } +} + +unsigned char* RangeEncoder::getChars() +{ + return chars; +} + +int RangeEncoder::getNumberChars() +{ + return number_chars; +} + +long RangeEncoder::getNumberBits() +{ + return bytecount*8; +} + +int RangeEncoder::getNumberBytes() +{ + return bytecount; +} + +inline void RangeEncoder::outbyte(unsigned int c) +{ + if (fp) + { + fputc(c, fp); + } + else + { + if (chars) + { + if (number_chars == allocated_chars) + { + unsigned char* newchars = (unsigned char*) malloc(sizeof(unsigned char)*allocated_chars*2); + memcpy(newchars,chars,sizeof(unsigned char)*allocated_chars); + free(chars); + chars = newchars; + allocated_chars = allocated_chars*2; + } + chars[number_chars++] = c; + } + } +} diff --git a/src/rangeencoder.h b/src/rangeencoder.h new file mode 100644 index 00000000..6154a8a6 --- /dev/null +++ b/src/rangeencoder.h @@ -0,0 +1,119 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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.h + + 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: + + 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_H +#define RANGEENCODER_H + +#include + +#include "rangemodel.h" +#include "mydefs.h" + +class RangeEncoder +{ +public: + +/* Start the encoder */ + RangeEncoder(FILE* fp, bool store_chars = true); + ~RangeEncoder(); + +/* Encode with modelling */ + void encode(RangeModel* rm, unsigned int sym); + +/* Encode bits without modelling */ + void writeBits(unsigned int bits, unsigned int sym); + +/* Encode a range without modelling */ + void writeRange(unsigned int range, unsigned int sym); + +/* Encode a range without modelling */ + void writeRange64( U64 range, U64 sym); + +/* Encode an unsigned char without modelling */ + void writeByte(unsigned char b); + +/* Encode an unsigned short without modelling */ + void writeShort(unsigned short s); + +/* Encode an unsigned int without modelling */ + void writeInt(unsigned int i); + +/* Encode a float without modelling */ + void writeFloat(float f); + +/* Encode an unsigned int64 without modelling */ + void writeInt64( U64 l); + +/* Encode a double without modelling */ + void writeDouble(double d); + +/* Finish encoding, returns number of bytes written */ + unsigned int done(); + + unsigned char* getChars(); + int getNumberChars(); + + long getNumberBits(); + int getNumberBytes(); + +private: + inline void normalize(); + inline void outbyte(unsigned int byte); + + FILE* fp; + + unsigned char* chars; + int number_chars; + int allocated_chars; + + unsigned int low; /* low end of interval */ + unsigned int range; /* length of interval */ + unsigned int help; /* bytes_to_follow resp. intermediate value */ + unsigned char buffer; /* buffer for input/output */ + /* the following is used only when encoding */ + unsigned int bytecount; /* counter for outputed bytes */ +}; + +#endif diff --git a/src/rangemodel.cpp b/src/rangemodel.cpp new file mode 100644 index 00000000..d8869a7b --- /dev/null +++ b/src/rangemodel.cpp @@ -0,0 +1,254 @@ +/****************************************************************************** + * + * Project: laszip - http://liblas.org - + * Purpose: + * Author: Martin Isenburg + * martin.isenburg at gmail.com + * + ****************************************************************************** + * Copyright (c) 2009, 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.h" + +#include +#include + +/* 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::RangeModel(unsigned int n, unsigned int *init, int compress, int targetrescale, int lg_totf) +{ + this->n = n; + this->targetrescale = targetrescale; + this->lg_totf = lg_totf; + cf = (unsigned short*)malloc((n+1)*sizeof(unsigned short)); + newf = (unsigned short*)malloc((n+1)*sizeof(unsigned short)); + 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--) + { + int 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); + } + 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) + { + int start, end; + end = (cf[i]-1) >> searchshift; + i--; + start = cf[i] >> searchshift; + while (start<=end) + { + search[start] = i; + start++; + } + } + } +} + +/* reinitialisation of qsmodel */ +/* init array of int's to be used for initialisation (NULL ok) */ +void RangeModel::reset(unsigned int *init) +{ + int i, end, initval; + rescale = n >> 4 | 2; + nextleft = 0; + if (init == NULL) + { + initval = cf[n] / n; + end = cf[n] % n; + for (i=0; i>searchshift); + lo = *tmp; + hi = *(tmp+1) + 1; + while (lo+1 < hi ) + { + int 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(unsigned int n, unsigned int *init, int compress, int targetrescale=2000, int lg_totf=14); + +/* deletion of qsmodel */ + ~RangeModel(); + +/* reinitialisation of qsmodel */ +/* init array to be used for initialisation (NULL ok) */ + + void reset(unsigned int *init); + +/* retrieval of estimated frequencies for a symbol */ +/* sym symbol for which data is desired; must be