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