1 /******************************************************************************
2 * $Id$
3 *
4 * Project: libLAS - http://liblas.org - A BSD library for LAS format data.
5 * Purpose: LAS index class
6 * Author: Gary Huber, gary@garyhuberart.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2010, Gary Huber, gary@garyhuberart.com
10 *
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following
15 * conditions are met:
16 *
17 * * Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * * Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in
21 * the documentation and/or other materials provided
22 * with the distribution.
23 * * Neither the name of the Martin Isenburg or Iowa Department
24 * of Natural Resources nor the names of its contributors may be
25 * used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
34 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
35 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
36 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
39 * OF SUCH DAMAGE.
40 ****************************************************************************/
41
42 #ifndef LIBLAS_LASINDEX_HPP_INCLUDED
43 #define LIBLAS_LASINDEX_HPP_INCLUDED
44
45 #include <liblas/reader.hpp>
46 #include <liblas/header.hpp>
47 #include <liblas/bounds.hpp>
48 #include <liblas/variablerecord.hpp>
49 #include <liblas/detail/index/indexcell.hpp>
50 #include <liblas/export.hpp>
51
52 // std
53 #include <stdexcept> // std::out_of_range
54 #include <cstdio> // file io
55 #include <iostream> // file io
56 #include <cstdlib> // std::size_t
57 #include <vector> // std::vector
58
59 namespace liblas {
60
61 #define LIBLAS_INDEX_MAXMEMDEFAULT 10000000 // 10 megs default
62 #define LIBLAS_INDEX_MINMEMDEFAULT 1000000 // 1 meg at least has to be allowed
63 #define LIBLAS_INDEX_VERSIONMAJOR 1
64 #define LIBLAS_INDEX_VERSIONMINOR 2 // minor version 2 begins 11/15/10
65 #define LIBLAS_INDEX_MAXSTRLEN 512
66 #define LIBLAS_INDEX_MAXCELLS 250000
67 #define LIBLAS_INDEX_OPTPTSPERCELL 100
68 #define LIBLAS_INDEX_MAXPTSPERCELL 1000
69 #define LIBLAS_INDEX_RESERVEFILTERDEFAULT 1000000 // 1 million points will be reserved on large files for filter result
70
71 // define this in order to fix problem with last bytes of last VLR getting corrupted
72 // when saved and reloaded from index or las file.
73 #define LIBLAS_INDEX_PADLASTVLR
74
75 typedef std::vector<uint8_t> IndexVLRData;
76 typedef std::vector<liblas::detail::IndexCell> IndexCellRow;
77 typedef std::vector<IndexCellRow> IndexCellDataBlock;
78
79 class LAS_DLL IndexData;
80 class LAS_DLL IndexIterator;
81
82 // Index class is the fundamental object for building and filtering a spatial index of points in an LAS file.
83 // An Index class doesn't do anything until it is configured with an IndexData object (see below).
84 // You instantiate an Index object first and then pass it an IndexData or you can construct the Index with an
85 // IndexData. Nothing happens until the Index is told what to do via the configuration with IndexData.
86 // For details on configuration options see IndexData below.
87
88 // Once an index exists and is configured, it can be used to filter the point set in the LAS file for which it
89 // was built. The points have to be what they were when the index was built. The index is not automatically
90 // updated if the point set is changed. The index becomes invalid if either the number of points is changed,
91 // the order of points is changed or the location of any points is changed. The Validate function is run to
92 // determine as best it can the validity of the stored index but it isn't perfect. It can only determine if
93 // the number of points has changed or the spatial extents of the file have changed.
94
95 // The user can constrain the memory used in building an index if that is believed to be an issue.
96 // The results will be the same but some efficiency may be lost in the index building process.
97
98 // Data stored in index header can be examined for determining suitability of index for desired purpose.
99 // 1) presence of z-dimensional cell structure is indicated by GetCellsZ() called on the Index.
100 // 2) Index author GetIndexAuthorStr() - provided by author at time of creation
101 // 3) Index comment GetIndexCommentStr() - provided by author at time of creation
102 // 4) Index creation date GetIndexDateStr() - provided by author at time of creation
103 // The latter fields are not validated in any way by the index building code and are just three fields
104 // which can be used as the user sees fit. Maximum length is LIBLAS_INDEX_MAXSTRLEN - 1.
105
106 // Obtaining a filtered set of points requires that a valid index exist (see above).
107 // The IndexData class is used again to pass the extents of the filter to the Index. By making any high/low
108 // bounds coordinate pair equal, that dimension is ignored for the purposes of filtering. Note that Z dimension
109 // discrimination is still available even if z-binning was not invoked during index creation. Filtering with
110 // the z dimension may be slower in that event but no less successful.
111
112 // A filter operation is invoked with the command:
113 // const std::vector<uint32_t>& Filter(IndexData const& ParamSrc);
114 // The return value is a vector of point ID's. The points can be accessed from the LAS file in the standard way
115 // as the index in no way modifies them or their sequential order.
116 // Currently only one, two or three dimensional spatial window filters are supported. See IndexData below for
117 // more info on filtering.
118
119 class LAS_DLL Index
120 {
121 public:
122 Index();
123 Index(IndexData const& ParamSrc);
124 ~Index();
125
126 // Blocked copying operations, declared but not defined.
127 /// Copy constructor.
128 Index(Index const& other);
129 /// Assignment operator.
130 Index& operator=(Index const& rhs);
131
132 private:
133
134 Reader *m_reader;
135 Reader *m_idxreader;
136 Header m_pointheader;
137 Header m_idxheader;
138 Bounds<double> m_bounds;
139 bool m_indexBuilt, m_tempFileStarted, m_readerCreated, m_readOnly, m_writestandaloneindex, m_forceNewIndex;
140 int m_debugOutputLevel;
141 uint8_t m_versionMajor, m_versionMinor;
142 uint32_t m_pointRecordsCount, m_maxMemoryUsage, m_cellsX, m_cellsY, m_cellsZ, m_totalCells,
143 m_DataVLR_ID;
144 liblas::detail::TempFileOffsetType m_tempFileWrittenBytes;
145 double m_rangeX, m_rangeY, m_rangeZ, m_cellSizeZ, m_cellSizeX, m_cellSizeY;
146 std::string m_tempFileName;
147 std::string m_indexAuthor;
148 std::string m_indexComment;
149 std::string m_indexDate;
150 std::vector<uint32_t> m_filterResult;
151 std::ostream *m_ofs;
152 FILE *m_tempFile, *m_outputFile;
153 FILE *m_debugger;
154
155 void SetValues(void);
156 bool IndexInit(void);
157 void ClearOldIndex(void);
158 bool BuildIndex(void);
159 bool Validate(void);
160 uint32_t GetDefaultReserve(void);
161 bool LoadIndexVLR(VariableRecord const& vlr);
162 void SetCellFilterBounds(IndexData & ParamSrc);
163 bool FilterOneVLR(VariableRecord const& vlr, uint32_t& i, IndexData & ParamSrc, bool & VLRDone);
164 bool FilterPointSeries(uint32_t & PointID, uint32_t & PointsScanned,
165 uint32_t const PointsToIgnore, uint32_t const x, uint32_t const y, uint32_t const z,
166 liblas::detail::ConsecPtAccumulator const ConsecutivePts, IndexIterator *Iterator,
167 IndexData const& ParamSrc);
168 bool VLRInteresting(int32_t MinCellX, int32_t MinCellY, int32_t MaxCellX, int32_t MaxCellY,
169 IndexData const& ParamSrc);
170 bool CellInteresting(int32_t x, int32_t y, IndexData const& ParamSrc);
171 bool SubCellInteresting(int32_t SubCellID, int32_t XCellID, int32_t YCellID, IndexData const& ParamSrc);
172 bool ZCellInteresting(int32_t ZCellID, IndexData const& ParamSrc);
173 bool FilterOnePoint(int32_t x, int32_t y, int32_t z, int32_t PointID, int32_t LastPointID, bool &LastPtRead,
174 IndexData const& ParamSrc);
175 // Determines what X/Y cell in the basic cell matrix a point falls in
176 bool IdentifyCell(Point const& CurPt, uint32_t& CurCellX, uint32_t& CurCellY) const;
177 // determines what Z cell a point falls in
178 bool IdentifyCellZ(Point const& CurPt, uint32_t& CurCellZ) const;
179 // Determines what quadrant sub-cell a point falls in
180 bool IdentifySubCell(Point const& CurPt, uint32_t x, uint32_t y, uint32_t& CurSubCell) const;
181 // Offloads binned cell data while building Index when cell data in memory exceeds maximum set by user
182 bool PurgePointsToTempFile(IndexCellDataBlock& CellBlock);
183 // Reloads and examines one cell of data from temp file
184 bool LoadCellFromTempFile(liblas::detail::IndexCell *CellBlock,
185 uint32_t CurCellX, uint32_t CurCellY);
186 // temp file is used to store sorted data while building index
187 FILE *OpenTempFile(void);
188 // closes and removes the temp file
189 void CloseTempFile(void);
190 // Creates a Writer from m_ofs and re-saves entire LAS input file with new index
191 // Current version does not save any data following the points
192 bool SaveIndexInLASFile(void);
193 // Creates a Writer from m_ofs and re-saves LAS header with new index, but not with data point records
194 bool SaveIndexInStandAloneFile(void);
195 // Calculate index bounds dimensions
CalcRangeX(void)196 void CalcRangeX(void) {m_rangeX = (m_bounds.max)(0) - (m_bounds.min)(0);}
CalcRangeY(void)197 void CalcRangeY(void) {m_rangeY = (m_bounds.max)(1) - (m_bounds.min)(1);}
CalcRangeZ(void)198 void CalcRangeZ(void) {m_rangeZ = (m_bounds.max)(2) - (m_bounds.min)(2);}
199
200 // error messages
201 bool FileError(const char *Reporter);
202 bool InputFileError(const char *Reporter) const;
203 bool OutputFileError(const char *Reporter) const;
204 bool DebugOutputError(const char *Reporter) const;
205 bool PointCountError(const char *Reporter) const;
206 bool PointBoundsError(const char *Reporter) const;
207 bool MemoryError(const char *Reporter) const;
208 bool InitError(const char *Reporter) const;
209 bool InputBoundsError(const char *Reporter) const;
210
211 // debugging
212 bool OutputCellStats(IndexCellDataBlock& CellBlock) const;
213 bool OutputCellGraph(std::vector<uint32_t> CellPopulation, uint32_t MaxPointsPerCell) const;
214
215 public:
216 // IndexFailed and IndexReady can be used to tell if an Index is ready for a filter operation
IndexFailed(void) const217 bool IndexFailed(void) const {return (! m_indexBuilt);}
IndexReady(void) const218 bool IndexReady(void) const {return (m_indexBuilt);}
219 // Prep takes the input data and initializes Index values and then either builds or examines the Index
220 bool Prep(IndexData const& ParamSrc);
221 // Filter performs a point filter using the bounds in ParamSrc
222 const std::vector<uint32_t>& Filter(IndexData & ParamSrc);
223 IndexIterator* Filter(IndexData const& ParamSrc, uint32_t ChunkSize);
224 IndexIterator* Filter(double LowFilterX, double HighFilterX, double LowFilterY, double HighFilterY,
225 double LowFilterZ, double HighFilterZ, uint32_t ChunkSize);
226 IndexIterator* Filter(Bounds<double> const& BoundsSrc, uint32_t ChunkSize);
227
228 // Return the bounds of the current Index
GetMinX(void) const229 double GetMinX(void) const {return (m_bounds.min)(0);}
GetMaxX(void) const230 double GetMaxX(void) const {return (m_bounds.max)(0);}
GetMinY(void) const231 double GetMinY(void) const {return (m_bounds.min)(1);}
GetMaxY(void) const232 double GetMaxY(void) const {return (m_bounds.max)(1);}
GetMinZ(void) const233 double GetMinZ(void) const {return (m_bounds.min)(2);}
GetMaxZ(void) const234 double GetMaxZ(void) const {return (m_bounds.max)(2);}
235 // Ranges are updated when an index is built or the index header VLR read
GetRangeX(void) const236 double GetRangeX(void) const {return m_rangeX;}
GetRangeY(void) const237 double GetRangeY(void) const {return m_rangeY;}
GetRangeZ(void) const238 double GetRangeZ(void) const {return m_rangeZ;}
GetBounds(void) const239 Bounds<double> const& GetBounds(void) const {return m_bounds;}
240 // Return the number of points used to build the Index
GetPointRecordsCount(void) const241 uint32_t GetPointRecordsCount(void) const {return m_pointRecordsCount;}
242 // Return the number of cells in the Index
GetCellsX(void) const243 uint32_t GetCellsX(void) const {return m_cellsX;}
GetCellsY(void) const244 uint32_t GetCellsY(void) const {return m_cellsY;}
245 // Return the number of Z-dimension cells in the Index. Value is 1 if no Z-cells were created during Index building
GetCellsZ(void) const246 uint32_t GetCellsZ(void) const {return m_cellsZ;}
247 // 42 is the ID for the Index header VLR and 43 is the normal ID for the Index data VLR's
248 // For future expansion, multiple indexes could assign data VLR ID's of their own choosing
GetDataVLR_ID(void) const249 uint32_t GetDataVLR_ID(void) const {return m_DataVLR_ID;}
250 // Since the user can define a Z cell size it is useful to examine that for an existing index
GetCellSizeZ(void) const251 double GetCellSizeZ(void) const {return m_cellSizeZ;}
252 // Return values used in building or examining index
GetDebugger(void) const253 FILE *GetDebugger(void) const {return m_debugger;}
GetReadOnly(void) const254 bool GetReadOnly(void) const {return m_readOnly;}
GetStandaloneIndex(void) const255 bool GetStandaloneIndex(void) const {return m_writestandaloneindex;}
GetForceNewIndex(void) const256 bool GetForceNewIndex(void) const {return m_forceNewIndex;}
GetMaxMemoryUsage(void) const257 uint32_t GetMaxMemoryUsage(void) const {return m_maxMemoryUsage;}
GetDebugOutputLevel(void) const258 int GetDebugOutputLevel(void) const {return m_debugOutputLevel;}
259 // Not sure if these are more useful than dangerous
GetPointHeader(void)260 Header *GetPointHeader(void) {return &m_pointheader;}
GetIndexHeader(void)261 Header *GetIndexHeader(void) {return &m_idxheader;}
GetReader(void) const262 Reader *GetReader(void) const {return m_reader;}
GetIndexReader(void) const263 Reader *GetIndexReader(void) const {return m_idxreader;}
GetTempFileName(void) const264 const char *GetTempFileName(void) const {return m_tempFileName.c_str();}
265 // Returns the strings set in the index when built
266 const char *GetIndexAuthorStr(void) const;
267 const char *GetIndexCommentStr(void) const;
268 const char *GetIndexDateStr(void) const;
GetVersionMajor(void) const269 uint8_t GetVersionMajor(void) const {return m_versionMajor;}
GetVersionMinor(void) const270 uint8_t GetVersionMinor(void) const {return m_versionMinor;}
271 // Methods for setting values used when reading index from file to facilitate moving reading function into
272 // separate IndexInput object at a future time to provide symmetry with IndexOutput
SetDataVLR_ID(uint32_t DataVLR_ID)273 void SetDataVLR_ID(uint32_t DataVLR_ID) {m_DataVLR_ID = DataVLR_ID;}
SetIndexAuthorStr(const char * ias)274 void SetIndexAuthorStr(const char *ias) {m_indexAuthor = ias;}
SetIndexCommentStr(const char * ics)275 void SetIndexCommentStr(const char *ics) {m_indexComment = ics;}
SetIndexDateStr(const char * ids)276 void SetIndexDateStr(const char *ids) {m_indexDate = ids;}
SetMinX(double minX)277 void SetMinX(double minX) {(m_bounds.min)(0, minX);}
SetMaxX(double maxX)278 void SetMaxX(double maxX) {(m_bounds.max)(0, maxX);}
SetMinY(double minY)279 void SetMinY(double minY) {(m_bounds.min)(1, minY);}
SetMaxY(double maxY)280 void SetMaxY(double maxY) {(m_bounds.max)(1, maxY);}
SetMinZ(double minZ)281 void SetMinZ(double minZ) {(m_bounds.min)(2, minZ);}
SetMaxZ(double maxZ)282 void SetMaxZ(double maxZ) {(m_bounds.max)(2, maxZ);}
SetPointRecordsCount(uint32_t prc)283 void SetPointRecordsCount(uint32_t prc) {m_pointRecordsCount = prc;}
SetCellsX(uint32_t cellsX)284 void SetCellsX(uint32_t cellsX) {m_cellsX = cellsX;}
SetCellsY(uint32_t cellsY)285 void SetCellsY(uint32_t cellsY) {m_cellsY = cellsY;}
SetCellsZ(uint32_t cellsZ)286 void SetCellsZ(uint32_t cellsZ) {m_cellsZ = cellsZ;}
287
288 };
289
290 // IndexData is used to pass attributes to and from the Index itself.
291 // How it is initialized determines what action is taken when an Index object is instantiated with the IndexData.
292 // The choices are:
293 // a) Build an index for an las file
294 // 1) std::ostream *ofs must be supplied as well as std::istream *ifs or Reader *reader and a full file path
295 // for writing a temp file, const char *tmpfilenme.
296 // b) Examine an index for an las file
297 // 1) std::istream *ifs or Reader *reader must be supplied for the LAS file containing the point data
298 // 2) if the index to be read is in a standalone file then Reader *idxreader must also be supplied
299 // Options for building are
300 // a) build a new index even if an old one exists, overwriting the old one
301 // 1) forcenewindex must be true
302 // 2) std::ostream *ofs must be a valid ostream where there is storage space for the desired output
303 // b) only build an index if none exists
304 // 1) forcenewindex must be false
305 // 2) std::ostream *ofs must be a valid ostream where there is storage space for the desired output
306 // c) do not build a new index under any circumstances
307 // 1) readonly must be true
308 // Location of the index can be specified
309 // a) build the index within the las file VLR structure
310 // 1) writestandaloneindex must be false
311 // 2) std::ostream *ofs must be a valid ostream where there is storage space for a full copy
312 // of the LAS file plus the new index which is typically less than 5% of the original file size
313 // b) build a stand-alone index outside the las file
314 // 1) writestandaloneindex must be true
315 // 2) std::ostream *ofs must be a valid ostream where there is storage space for the new index
316 // which is typically less than 5% of the original file size
317
318 // How the index is built is determined also by members of the IndexData class object.
319 // Options include:
320 // a) control the maximum memory used during the build process
321 // 1) pass a value for maxmem in bytes greater than 0. 0 resolves to default LIBLAS_INDEX_MAXMEMDEFAULT.
322 // b) debug messages generated during index creation or filtering. The higher the number, the more messages.
323 // 0) no debug reports
324 // 1) general info messages
325 // 2) status messages
326 // 3) cell statistics
327 // 4) progress status
328 // c) where debug messages are sent
329 // 1) default is stderr
330 // d) control the creation of z-dimensional cells and what z cell size to use
331 // 1) to turn on z-dimensional binning, use a value larger than 0 for zbinht
332 // e) data can be stored in index header for later use in recognizing the index.
333 // 1) Index author indexauthor - provided by author at time of creation
334 // 2) Index comment indexcomment - provided by author at time of creation
335 // 3) Index creation date indexdate - provided by author at time of creation
336 // The fields are not validated in any way by the index building code and are just three fields
337 // which can be used as the user sees fit. Maximum length is LIBLAS_INDEX_MAXSTRLEN - 1.
338
339 // Once an index is built, or if an index already exists, the IndexData can be configured
340 // to define the bounds of a filter operation. Any dimension whose bounds pair are equal will
341 // be disregarded for the purpose of filtering. Filtering on the Z axis can still be performed even if the
342 // index was not built with Z cell sorting. Bounds must be defined in the same units and coordinate
343 // system that a liblas::Header returns with the commands GetMin{X|Y|Z} and a liblas::Point returns with
344 // Get{X|Y|Z}
345
346 class LAS_DLL IndexData
347 {
348 friend class Index;
349 friend class IndexIterator;
350
351 public:
352 IndexData(void);
353 IndexData(Index const& index);
354
355 // use one of these methods to configure the IndexData with the values needed for specific tasks
356
357 // one comprehensive method to set all the values used in index initialization
358 bool SetInitialValues(std::istream *ifs = 0, Reader *reader = 0, std::ostream *ofs = 0, Reader *idxreader = 0,
359 const char *tmpfilenme = 0, const char *indexauthor = 0,
360 const char *indexcomment = 0, const char *indexdate = 0, double zbinht = 0.0,
361 uint32_t maxmem = LIBLAS_INDEX_MAXMEMDEFAULT, int debugoutputlevel = 0, bool readonly = 0,
362 bool writestandaloneindex = 0, bool forcenewindex = 0, FILE *debugger = 0);
363
364 // set the values needed for building an index embedded in existing las file, overriding any existing index
365 bool SetBuildEmbedValues(Reader *reader, std::ostream *ofs, const char *tmpfilenme, const char *indexauthor = 0,
366 const char *indexcomment = 0, const char *indexdate = 0, double zbinht = 0.0,
367 uint32_t maxmem = LIBLAS_INDEX_MAXMEMDEFAULT, int debugoutputlevel = 0, FILE *debugger = 0);
368
369 // set the values needed for building an index in a standalone file, overriding any existing index
370 bool SetBuildAloneValues(Reader *reader, std::ostream *ofs, const char *tmpfilenme, const char *indexauthor = 0,
371 const char *indexcomment = 0, const char *indexdate = 0, double zbinht = 0.0,
372 uint32_t maxmem = LIBLAS_INDEX_MAXMEMDEFAULT, int debugoutputlevel = 0, FILE *debugger = 0);
373
374 // set the values needed for filtering with an existing index in an las file
375 bool SetReadEmbedValues(Reader *reader, int debugoutputlevel = 0, FILE *debugger = 0);
376
377 // set the values needed for filtering with an existing index in a standalone file
378 bool SetReadAloneValues(Reader *reader, Reader *idxreader, int debugoutputlevel = 0, FILE *debugger = 0);
379
380 // set the values needed for building an index embedded in existing las file only if no index already exists
381 // otherwise, prepare the existing index for filtering
382 bool SetReadOrBuildEmbedValues(Reader *reader, std::ostream *ofs, const char *tmpfilenme, const char *indexauthor = 0,
383 const char *indexcomment = 0, const char *indexdate = 0, double zbinht = 0.0,
384 uint32_t maxmem = LIBLAS_INDEX_MAXMEMDEFAULT, int debugoutputlevel = 0, FILE *debugger = 0);
385
386 // set the values needed for building an index in a standalone file only if no index already exists in the las file
387 // otherwise, prepare the existing index for filtering
388 bool SetReadOrBuildAloneValues(Reader *reader, std::ostream *ofs, const char *tmpfilenme, const char *indexauthor = 0,
389 const char *indexcomment = 0, const char *indexdate = 0, double zbinht = 0.0,
390 uint32_t maxmem = LIBLAS_INDEX_MAXMEMDEFAULT, int debugoutputlevel = 0, FILE *debugger = 0);
391
392 // set the bounds for use in filtering
393 bool SetFilterValues(double LowFilterX, double HighFilterX, double LowFilterY, double HighFilterY, double LowFilterZ, double HighFilterZ,
394 Index const& index);
395 bool SetFilterValues(Bounds<double> const& src, Index const& index);
396
397 /// Copy constructor.
398 IndexData(IndexData const& other);
399 /// Assignment operator.
400 IndexData& operator=(IndexData const& rhs);
401
402 private:
403 void SetValues(void);
404 bool CalcFilterEnablers(void);
405 void Copy(IndexData const& other);
406
407 protected:
408 Reader *m_reader;
409 Reader *m_idxreader;
410 IndexIterator *m_iterator;
411 Bounds<double> m_filter;
412 std::istream *m_ifs;
413 std::ostream *m_ofs;
414 const char *m_tempFileName;
415 const char *m_indexAuthor;
416 const char *m_indexComment;
417 const char *m_indexDate;
418 double m_cellSizeZ;
419 double m_LowXBorderPartCell, m_HighXBorderPartCell, m_LowYBorderPartCell, m_HighYBorderPartCell;
420 int32_t m_LowXCellCompletelyIn, m_HighXCellCompletelyIn, m_LowYCellCompletelyIn, m_HighYCellCompletelyIn,
421 m_LowZCellCompletelyIn, m_HighZCellCompletelyIn;
422 int32_t m_LowXBorderCell, m_HighXBorderCell, m_LowYBorderCell, m_HighYBorderCell,
423 m_LowZBorderCell, m_HighZBorderCell;
424 uint32_t m_maxMemoryUsage;
425 int m_debugOutputLevel;
426 bool m_noFilterX, m_noFilterY, m_noFilterZ, m_readOnly, m_writestandaloneindex, m_forceNewIndex, m_indexValid;
427 FILE *m_debugger;
428
SetIterator(IndexIterator * setIt)429 void SetIterator(IndexIterator *setIt) {m_iterator = setIt;}
GetIterator(void)430 IndexIterator *GetIterator(void) {return(m_iterator);}
431
432 public:
GetCellSizeZ(void) const433 double GetCellSizeZ(void) const {return m_cellSizeZ;}
GetDebugger(void) const434 FILE *GetDebugger(void) const {return m_debugger;}
GetReadOnly(void) const435 bool GetReadOnly(void) const {return m_readOnly;}
GetStandaloneIndex(void) const436 bool GetStandaloneIndex(void) const {return m_writestandaloneindex;}
GetForceNewIndex(void) const437 bool GetForceNewIndex(void) const {return m_forceNewIndex;}
GetMaxMemoryUsage(void) const438 uint32_t GetMaxMemoryUsage(void) const {return m_maxMemoryUsage;}
GetReader(void) const439 Reader *GetReader(void) const {return m_reader;}
GetDebugOutputLevel(void) const440 int GetDebugOutputLevel(void) const {return m_debugOutputLevel;}
GetTempFileName(void) const441 const char *GetTempFileName(void) const {return m_tempFileName;}
442 const char *GetIndexAuthorStr(void) const;
443 const char *GetIndexCommentStr(void) const;
444 const char *GetIndexDateStr(void) const;
GetMinFilterX(void) const445 double GetMinFilterX(void) const {return (m_filter.min)(0);}
GetMaxFilterX(void) const446 double GetMaxFilterX(void) const {return (m_filter.max)(0);}
GetMinFilterY(void) const447 double GetMinFilterY(void) const {return (m_filter.min)(1);}
GetMaxFilterY(void) const448 double GetMaxFilterY(void) const {return (m_filter.max)(1);}
GetMinFilterZ(void) const449 double GetMinFilterZ(void) const {return (m_filter.min)(2);}
GetMaxFilterZ(void) const450 double GetMaxFilterZ(void) const {return (m_filter.max)(2);}
451 void ClampFilterBounds(Bounds<double> const& m_bounds);
SetReader(Reader * reader)452 void SetReader(Reader *reader) {m_reader = reader;}
SetIStream(std::istream * ifs)453 void SetIStream(std::istream *ifs) {m_ifs = ifs;}
SetOStream(std::ostream * ofs)454 void SetOStream(std::ostream *ofs) {m_ofs = ofs;}
SetTmpFileName(const char * tmpfilenme)455 void SetTmpFileName(const char *tmpfilenme) {m_tempFileName = tmpfilenme;}
SetIndexAuthor(const char * indexauthor)456 void SetIndexAuthor(const char *indexauthor) {m_indexAuthor = indexauthor;}
SetIndexComment(const char * indexcomment)457 void SetIndexComment(const char *indexcomment) {m_indexComment = indexcomment;}
SetIndexDate(const char * indexdate)458 void SetIndexDate(const char *indexdate) {m_indexDate = indexdate;}
SetCellSizeZ(double cellsizez)459 void SetCellSizeZ(double cellsizez) {m_cellSizeZ = cellsizez;}
SetMaxMem(uint32_t maxmem)460 void SetMaxMem(uint32_t maxmem) {m_maxMemoryUsage = maxmem;}
SetDebugOutputLevel(int debugoutputlevel)461 void SetDebugOutputLevel(int debugoutputlevel) {m_debugOutputLevel = debugoutputlevel;}
SetReadOnly(bool readonly)462 void SetReadOnly(bool readonly) {m_readOnly = readonly;}
SetStandaloneIndex(bool writestandaloneindex)463 void SetStandaloneIndex(bool writestandaloneindex) {m_writestandaloneindex = writestandaloneindex;}
SetDebugger(FILE * debugger)464 void SetDebugger(FILE *debugger) {m_debugger = debugger;}
465 };
466
467 class LAS_DLL IndexIterator
468 {
469 friend class Index;
470
471 protected:
472 IndexData m_indexData;
473 Index *m_index;
474 uint32_t m_chunkSize, m_advance;
475 uint32_t m_curVLR, m_curCellStartPos, m_curCellX, m_curCellY, m_totalPointsScanned, m_ptsScannedCurCell,
476 m_ptsScannedCurVLR;
477 uint32_t m_conformingPtsFound;
478
479 public:
480 IndexIterator(Index *IndexSrc, double LowFilterX, double HighFilterX, double LowFilterY, double HighFilterY,
481 double LowFilterZ, double HighFilterZ, uint32_t ChunkSize);
482 IndexIterator(Index *IndexSrc, IndexData const& IndexDataSrc, uint32_t ChunkSize);
483 IndexIterator(Index *IndexSrc, Bounds<double> const& BoundsSrc, uint32_t ChunkSize);
484 /// Copy constructor.
485 IndexIterator(IndexIterator const& other);
486 /// Assignment operator.
487 IndexIterator& operator=(IndexIterator const& rhs);
488 private:
489 void Copy(IndexIterator const& other);
490 void ResetPosition(void);
MinMajorVersion(void)491 uint8_t MinMajorVersion(void) {return(1);}
MinMinorVersion(void)492 uint8_t MinMinorVersion(void) {return(2);}
493
494 public:
495 /// n=0 or n=1 gives next sequence with no gap, n>1 skips n-1 filter-compliant points, n<0 jumps backwards n compliant points
496 const std::vector<uint32_t>& advance(int32_t n);
497 /// returns filter-compliant points as though the first point returned is element n in a zero-based array
498 const std::vector<uint32_t>& operator()(int32_t n);
499 /// returns next set of filter-compliant points with no skipped points
operator ++()500 inline const std::vector<uint32_t>& operator++() {return (advance(1));}
501 /// returns next set of filter-compliant points with no skipped points
operator ++(int)502 inline const std::vector<uint32_t>& operator++(int) {return (advance(1));}
503 /// returns set of filter-compliant points skipping backwards 1 from the end of the last set
operator --()504 inline const std::vector<uint32_t>& operator--() {return (advance(-1));}
505 /// returns set of filter-compliant points skipping backwards 1 from the end of the last set
operator --(int)506 inline const std::vector<uint32_t>& operator--(int) {return (advance(-1));}
507 /// returns next set of filter-compliant points with n-1 skipped points, for n<0 acts like -=()
operator +=(int32_t n)508 inline const std::vector<uint32_t>& operator+=(int32_t n) {return (advance(n));}
509 /// returns next set of filter-compliant points with n-1 skipped points, for n<0 acts like -()
operator +(int32_t n)510 inline const std::vector<uint32_t>& operator+(int32_t n) {return (advance(n));}
511 /// returns set of filter-compliant points beginning n points backwards from the end of the last set, for n<0 acts like +=()
operator -=(int32_t n)512 inline const std::vector<uint32_t>& operator-=(int32_t n) {return (advance(-n));}
513 /// returns set of filter-compliant points beginning n points backwards from the end of the last set, for n<0 acts like +()
operator -(int32_t n)514 inline const std::vector<uint32_t>& operator-(int32_t n) {return (advance(-n));}
515 /// returns filter-compliant points as though the first point returned is element n in a zero-based array
operator [](int32_t n)516 inline const std::vector<uint32_t>& operator[](int32_t n) {return ((*this)(n));}
517 /// tests viability of index for filtering with iterator
ValidateIndexVersion(uint8_t VersionMajor,uint8_t VersionMinor)518 bool ValidateIndexVersion(uint8_t VersionMajor, uint8_t VersionMinor) {return (VersionMajor > MinMajorVersion() || (VersionMajor == MinMajorVersion() && VersionMinor >= MinMinorVersion()));}
519 };
520
521 template <typename T, typename Q>
ReadVLRData_n(T & dest,IndexVLRData const & src,Q & pos)522 inline void ReadVLRData_n(T& dest, IndexVLRData const& src, Q& pos)
523 {
524 // error if reading past array end
525 if (static_cast<size_t>(pos) + sizeof(T) > src.size())
526 throw std::out_of_range("liblas::detail::ReadVLRData_n: array index out of range");
527 // copy sizeof(T) bytes to destination
528 memcpy(&dest, &src[pos], sizeof(T));
529 // Fix little-endian
530 LIBLAS_SWAP_BYTES_N(dest, sizeof(T));
531 // increment the write position to end of written data
532 pos = pos + static_cast<Q>(sizeof(T));
533 }
534
535 template <typename T, typename Q>
ReadVLRDataNoInc_n(T & dest,IndexVLRData const & src,Q const & pos)536 inline void ReadVLRDataNoInc_n(T& dest, IndexVLRData const& src, Q const& pos)
537 {
538 // error if reading past array end
539 if (static_cast<size_t>(pos) + sizeof(T) > src.size())
540 throw std::out_of_range("liblas::detail::ReadVLRDataNoInc_n: array index out of range");
541 // copy sizeof(T) bytes to destination
542 memcpy(&dest, &src[pos], sizeof(T));
543 // Fix little-endian
544 LIBLAS_SWAP_BYTES_N(dest, sizeof(T));
545 }
546
547 template <typename T, typename Q>
ReadeVLRData_str(char * dest,IndexVLRData const & src,T const srclen,Q & pos)548 inline void ReadeVLRData_str(char * dest, IndexVLRData const& src, T const srclen, Q& pos)
549 {
550 // error if reading past array end
551 if (static_cast<size_t>(pos) + static_cast<size_t>(srclen) > src.size())
552 throw std::out_of_range("liblas::detail::ReadeVLRData_str: array index out of range");
553 // copy srclen bytes to destination
554 memcpy(dest, &src[pos], srclen);
555 // increment the write position to end of written data
556 pos = pos + static_cast<Q>(srclen);
557 }
558
559 template <typename T, typename Q>
ReadVLRDataNoInc_str(char * dest,IndexVLRData const & src,T const srclen,Q pos)560 inline void ReadVLRDataNoInc_str(char * dest, IndexVLRData const& src, T const srclen, Q pos)
561 {
562 // error if reading past array end
563 if (static_cast<size_t>(pos) + static_cast<size_t>(srclen) > src.size())
564 throw std::out_of_range("liblas::detail::ReadVLRDataNoInc_str: array index out of range");
565 // copy srclen bytes to destination
566 std::memcpy(dest, &src[pos], srclen);
567 }
568
569 } // namespace liblas
570
571 #endif // LIBLAS_LASINDEX_HPP_INCLUDED
572