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 #include <liblas/index.hpp>
43 #include <liblas/writer.hpp>
44 #include <liblas/detail/index/indexoutput.hpp>
45 #include <liblas/detail/index/indexcell.hpp>
46 #include <liblas/detail/writer/writer.hpp>
47 
48 namespace liblas
49 {
50 
Index()51 Index::Index()
52 {
53 	SetValues();
54 	m_indexBuilt = false;
55 } // Index::Index
56 
Index(IndexData const & ParamSrc)57 Index::Index(IndexData const& ParamSrc)
58 {
59 	SetValues();
60 	Prep(ParamSrc);
61 } // Index::Index
62 
Prep(IndexData const & ParamSrc)63 bool Index::Prep(IndexData const& ParamSrc)
64 {
65 
66 	m_reader = ParamSrc.m_reader;
67 	m_idxreader = ParamSrc.m_idxreader;
68  	m_readerCreated = false;
69 	if (! m_reader)
70 	{
71 		try {
72 			// fails if input stream is invalid
73 			m_reader = new liblas::Reader(*ParamSrc.m_ifs);
74  			m_readerCreated = true;
75  		} // try
76  		catch (std::runtime_error) {
77  			return (InputFileError("Index::Prep"));
78  		} // catch
79 	} // if
80 	m_ofs = ParamSrc.m_ofs;
81     m_debugOutputLevel = ParamSrc.m_debugOutputLevel;
82 	m_tempFileName = ParamSrc.m_tempFileName ? ParamSrc.m_tempFileName: "";
83 	m_indexAuthor = ParamSrc.m_indexAuthor ? ParamSrc.m_indexAuthor: "";
84 	m_indexComment = ParamSrc.m_indexComment ? ParamSrc.m_indexComment: "";
85 	m_indexDate = ParamSrc.m_indexDate ? ParamSrc.m_indexDate: "";
86 	m_cellSizeZ = ParamSrc.m_cellSizeZ;
87 	m_debugger = ParamSrc.m_debugger ? ParamSrc.m_debugger: stderr;
88 	m_readOnly = ParamSrc.m_readOnly;
89 	m_writestandaloneindex = ParamSrc.m_writestandaloneindex;
90 	m_forceNewIndex = ParamSrc.m_forceNewIndex;
91 	if (ParamSrc.m_maxMemoryUsage > 0)
92 		m_maxMemoryUsage = ParamSrc.m_maxMemoryUsage;
93 	else
94 		m_maxMemoryUsage = LIBLAS_INDEX_MAXMEMDEFAULT;
95 	if (m_maxMemoryUsage < LIBLAS_INDEX_MINMEMDEFAULT)
96 		m_maxMemoryUsage = LIBLAS_INDEX_MINMEMDEFAULT;
97 	m_indexBuilt = IndexInit();
98 	return (m_indexBuilt);
99 
100 } // Index::Prep
101 
SetValues(void)102 void Index::SetValues(void)
103 {
104 	m_bounds.dimension(3);
105     m_reader = 0;
106 	m_idxreader = 0;
107     m_ofs = 0;
108   	m_readerCreated = false;
109 	m_tempFile = 0;
110 	m_outputFile = 0;
111     m_debugOutputLevel = 0;
112     m_tempFileName = "";
113 	m_indexAuthor = "";
114 	m_indexComment = "";
115 	m_indexDate = "";
116 	m_versionMajor = LIBLAS_INDEX_VERSIONMAJOR;
117 	m_versionMinor = LIBLAS_INDEX_VERSIONMINOR;
118 	m_cellSizeZ = 0.0;
119 	m_debugger = stderr;
120 	m_readOnly = false;
121 	m_forceNewIndex = false;
122 	m_DataVLR_ID = 43;
123 	m_maxMemoryUsage = LIBLAS_INDEX_MAXMEMDEFAULT;
124     m_rangeX = m_rangeY = m_rangeZ = m_cellSizeZ = m_cellSizeX = m_cellSizeY =
125 		m_pointRecordsCount = m_maxMemoryUsage = m_cellsX = m_cellsY = m_cellsZ = m_totalCells = 0;
126     m_tempFileWrittenBytes = 0;
127 	m_indexBuilt = m_tempFileStarted = m_readerCreated = false;
128 } // Index::SetValues
129 
~Index(void)130 Index::~Index(void)
131 {
132 	if (m_readerCreated)
133 		delete m_reader;
134 } // Index::~Index
135 
IndexInit(void)136 bool Index::IndexInit(void)
137 {
138 	bool Success = false;
139 	bool IndexFound = false;
140 
141 	if (m_idxreader || m_reader)
142 	{
143 		if (m_idxreader)
144 		{
145 			m_idxheader = m_idxreader->GetHeader();
146 		} // if
147 		else if (m_reader)
148 		{
149 			m_idxheader = m_reader->GetHeader();
150 		} // else
151 		if (m_reader)
152 		{
153 			m_pointheader = m_reader->GetHeader();
154 		} // else
155 		uint32_t initialVLRs = m_idxheader.GetRecordsCount();
156 		for (uint32_t i = 0; i < initialVLRs; ++i)
157 		{
158 			VariableRecord const& vlr = m_idxheader.GetVLR(i);
159 			// a combination of "liblas" and 42 denotes that this is a liblas spatial index id
160 			if (std::string(vlr.GetUserId(false)) == std::string("liblas"))
161 			{
162 				if (vlr.GetRecordId() == 42)
163 				{
164 					LoadIndexVLR(vlr);
165 					IndexFound = true;
166 					break;
167 				}
168 			}
169 		}
170 		if (IndexFound)
171 		{
172 			if (m_forceNewIndex)
173 			{
174 				ClearOldIndex();
175 				IndexFound = false;
176 				if (m_debugOutputLevel > 1)
177 					fprintf(m_debugger, "Old index removed.\n");
178 			} // if
179 			else if (! Validate())
180 			{
181 				IndexFound = false;
182 				if (m_debugOutputLevel > 1)
183 					fprintf(m_debugger, "Existing index out of date.\n");
184 			} // else if failed index validation test
185 			else
186 				return (true);
187 		} // if
188 		if (! IndexFound)
189 		{
190 			if (! m_readOnly)
191 			{
192 				Success = BuildIndex();
193 				uint32_t test = m_idxheader.GetRecordsCount() - initialVLRs;
194 				if (m_debugOutputLevel > 1)
195 					fprintf(m_debugger, "VLRs created %d\n", test);
196 			} // if
197 			else if (m_debugOutputLevel > 1)
198 				fprintf(m_debugger, "Index not found nor created per user instructions.\n");
199 		} // if
200 		return Success;
201 	} // m_reader
202 	return (InitError("Index::IndexInit"));
203 } // Index::IndexInit
204 
ClearOldIndex(void)205 void Index::ClearOldIndex(void)
206 {
207 	uint32_t initialVLRs = m_idxheader.GetRecordsCount();
208 	uint32_t TempDataVLR_ID = GetDataVLR_ID();
209 
210 	for (uint32_t i = 0; i < initialVLRs; ++i)
211 	{
212 		VariableRecord const& vlr = m_idxheader.GetVLR(i);
213 		// a combination of "liblas" and 42 denotes that this is a liblas spatial index id
214 		if (std::string(vlr.GetUserId(false)) == std::string("liblas"))
215 		{
216 			// 42 is index ID
217 			if (vlr.GetRecordId() == 42)
218 			{
219 				// sets DataVLR_ID to value in index header
220 				LoadIndexVLR(vlr);
221 				m_idxheader.DeleteVLR(i);
222 			} // if
223 			else if (vlr.GetRecordId() == GetDataVLR_ID())
224 			{
225 				m_idxheader.DeleteVLR(i);
226 			} // else if
227 		} // if
228 	} // for
229 
230 	// restore Data VLR ID
231 	SetDataVLR_ID(TempDataVLR_ID);
232 
233 } // Index::ClearOldIndex
234 
Validate(void)235 bool Index::Validate(void)
236 {
237 
238 	// compare the index-stored values to the ones in the las file header
239 	// Index needs to be current in order to be valid.
240 	// The validity test cannot determine if points have been moved but if the number of points or the
241 	// bounds of the points has changed since the index was built then the index is deemed invalid and
242 	// not to be used for filtering.
243     Bounds<double> HeaderBounds(m_pointheader.GetMinX(), m_pointheader.GetMinY(), m_pointheader.GetMinZ(), m_pointheader.GetMaxX(), m_pointheader.GetMaxY(), m_pointheader.GetMaxZ());
244 	if (m_bounds == HeaderBounds)
245 	{
246 		if (m_pointheader.GetPointRecordsCount() == GetPointRecordsCount())
247 			return (true);
248 	} // if
249 	return (false);
250 
251 } // Index::Validate
252 
GetDefaultReserve(void)253 uint32_t Index::GetDefaultReserve(void)
254 {
255 	return (GetPointRecordsCount() < LIBLAS_INDEX_RESERVEFILTERDEFAULT ? GetPointRecordsCount(): LIBLAS_INDEX_RESERVEFILTERDEFAULT);
256 } // Index::GetDefaultReserve
257 
Filter(IndexData & ParamSrc)258 const std::vector<uint32_t>& Index::Filter(IndexData & ParamSrc)
259 {
260 
261 	try {
262 		// if there is already a list, get rid of it
263 		m_filterResult.resize(0);
264 		// are we asked to advance beyond the number of points in the file? that would be a mistake and waste of time.
265 		if (ParamSrc.m_iterator &&
266 			(ParamSrc.m_iterator->m_advance + ParamSrc.m_iterator->m_totalPointsScanned > GetPointRecordsCount()))
267 			return (m_filterResult);
268 
269 		m_filterResult.reserve(ParamSrc.m_iterator ? ParamSrc.m_iterator->m_chunkSize: GetDefaultReserve());
270 		if (m_reader)
271 		{
272 			uint32_t i;
273 			i = ParamSrc.m_iterator ? ParamSrc.m_iterator->m_curVLR: 0;
274 			for (; i < m_idxheader.GetRecordsCount(); ++i)
275 			{
276 				VariableRecord const& vlr = m_idxheader.GetVLR(i);
277 				// a combination of "liblas" and 42 denotes that this is a liblas spatial index id
278 				if (std::string(vlr.GetUserId(false)) == std::string("liblas"))
279 				{
280 					uint16_t RecordID = vlr.GetRecordId();
281 					if (RecordID == 42)
282 					{
283 						if (! LoadIndexVLR(vlr))
284 							break;
285 						// Beyond the first record would be more VLR's with the actual index data
286 						// some cells will fall completely inside, some outside and some straddling the filter bounds
287 						SetCellFilterBounds(ParamSrc);
288 						if (! m_bounds.intersects(ParamSrc.m_filter))
289 						{
290 							if (m_debugOutputLevel > 1)
291 								fprintf(m_debugger, "Index bounds do not intersect filter bounds.\n");
292 							break;
293 						} // if
294 						if (ParamSrc.m_iterator && ! ParamSrc.m_iterator->ValidateIndexVersion(GetVersionMajor(), GetVersionMinor()))
295 						{
296 							if (m_debugOutputLevel > 1)
297 								fprintf(m_debugger, "Index version does not support iterator access. Regenerate Index.\n");
298 							break;
299 						} // if
300 					} // if 42
301 					else if (RecordID == m_DataVLR_ID)
302 					{
303 						// some of our data is in this record
304 						bool VLRDone = false;
305 						const uint32_t HeadVLR = i;
306 						if (! FilterOneVLR(vlr, i, ParamSrc, VLRDone))
307 							break;
308 						if (ParamSrc.m_iterator)
309 						{
310 							if (VLRDone)
311 								ParamSrc.m_iterator->m_curCellStartPos = ParamSrc.m_iterator->m_ptsScannedCurCell =
312 									ParamSrc.m_iterator->m_ptsScannedCurVLR = 0;
313 							// if we've filled our quota break out of loop
314 							if (m_filterResult.size() >= ParamSrc.m_iterator->m_chunkSize)
315 							{
316 								// if we've scanned the entire VLR
317 								if (VLRDone)
318 									++i;	// increment i so that next iteration starts on next VLR
319 								else if (i != HeadVLR)	// if VLR's are linked FilterOneVLR() will have incremented i
320 									i = HeadVLR;	// put back i so that the right VLR is loaded first next iteration
321 								break;
322 							} // if
323 						} // if
324 					} // else if ID matches ID stored in index header
325 				}
326 			}
327 			if (ParamSrc.m_iterator)
328 				ParamSrc.m_iterator->m_curVLR = i;
329 		} // m_reader
330 	} // try
331 	catch (std::bad_alloc) {
332 		m_filterResult.resize(0);
333 	} // catch
334 	return (m_filterResult);
335 
336 } // Index::Filter
337 
Filter(IndexData const & ParamSrc,uint32_t ChunkSize)338 IndexIterator* Index::Filter(IndexData const& ParamSrc, uint32_t ChunkSize)
339 {
340 	IndexIterator* NewIter = NULL;
341 
342 	try {
343 		NewIter = new IndexIterator(this, ParamSrc, ChunkSize);
344 	} // try
345 	catch (std::bad_alloc) {
346 		return (NULL);
347 	} // catch
348 
349 	return (NewIter);
350 
351 } // Index::Filter
352 
Filter(double LowFilterX,double HighFilterX,double LowFilterY,double HighFilterY,double LowFilterZ,double HighFilterZ,uint32_t ChunkSize)353 IndexIterator* Index::Filter(double LowFilterX, double HighFilterX, double LowFilterY, double HighFilterY,
354 	double LowFilterZ, double HighFilterZ, uint32_t ChunkSize)
355 {
356 	IndexIterator* NewIter = NULL;
357 
358 	try {
359 		NewIter = new IndexIterator(this, LowFilterX, HighFilterX, LowFilterY, HighFilterY,
360 			LowFilterZ, HighFilterZ, ChunkSize);
361 	} // try
362 	catch (std::bad_alloc) {
363 		return (NULL);
364 	} // catch
365 
366 	return (NewIter);
367 
368 } // Index::Filter
369 
Filter(Bounds<double> const & BoundsSrc,uint32_t ChunkSize)370 IndexIterator* Index::Filter(Bounds<double> const& BoundsSrc, uint32_t ChunkSize)
371 {
372 	IndexIterator* NewIter = NULL;
373 
374 	try {
375 		NewIter = new IndexIterator(this, BoundsSrc, ChunkSize);
376 	} // try
377 	catch (std::bad_alloc) {
378 		return (NULL);
379 	} // catch
380 
381 	return (NewIter);
382 
383 } // Index::Filter
384 
SetCellFilterBounds(IndexData & ParamSrc)385 void Index::SetCellFilterBounds(IndexData & ParamSrc)
386 {
387 	double LowXCell, HighXCell, LowYCell, HighYCell, LowZCell, HighZCell,
388 		filterMinXCell, filterMaxXCell, filterMinYCell, filterMaxYCell, filterMinZCell, filterMaxZCell;
389 	// convert filter bounds into cell numbers
390 	// X and Y range can not be 0 or the index would not have been built
391 	filterMinXCell = m_cellsX * (ParamSrc.GetMinFilterX() - GetMinX()) / GetRangeX();
392 	filterMaxXCell = m_cellsX * (ParamSrc.GetMaxFilterX() - GetMinX()) / GetRangeX();
393 	filterMinYCell = m_cellsY * (ParamSrc.GetMinFilterY() - GetMinY()) / GetRangeY();
394 	filterMaxYCell = m_cellsY * (ParamSrc.GetMaxFilterY() - GetMinY()) / GetRangeY();
395 	// Z range however can be 0
396 	if (GetRangeZ() > 0.0 && ! detail::compare_distance(GetRangeZ(), 0.0))
397 	{
398 		filterMinZCell = m_cellsZ * (ParamSrc.GetMinFilterZ() - GetMinZ()) / GetRangeZ();
399 		filterMaxZCell = m_cellsZ * (ParamSrc.GetMaxFilterZ() - GetMinZ()) / GetRangeZ();
400 	} // if
401 	else
402 	{
403 		filterMinZCell = filterMaxZCell = 0;
404 	} // else
405 	LowXCell = ceil(filterMinXCell);
406 	HighXCell = floor(filterMaxXCell) - 1.0;
407 	LowYCell = ceil(filterMinYCell);
408 	HighYCell = floor(filterMaxYCell) - 1.0;
409 	LowZCell = ceil(filterMinZCell);
410 	HighZCell = floor(filterMaxZCell) - 1.0;
411 	ParamSrc.m_LowXCellCompletelyIn = (int32_t)LowXCell;
412 	ParamSrc.m_HighXCellCompletelyIn = (int32_t)HighXCell;
413 	ParamSrc.m_LowYCellCompletelyIn = (int32_t)LowYCell;
414 	ParamSrc.m_HighYCellCompletelyIn = (int32_t)HighYCell;
415 	ParamSrc.m_LowZCellCompletelyIn = (int32_t)LowZCell;
416 	ParamSrc.m_HighZCellCompletelyIn = (int32_t)HighZCell;
417 
418     LowXCell = floor(filterMinXCell);
419     HighXCell = ceil(filterMaxXCell) - 1.0;
420     LowYCell = floor(filterMinYCell);
421     HighYCell = ceil(filterMaxYCell) - 1.0;
422     LowZCell = floor(filterMinZCell);
423     HighZCell = ceil(filterMaxZCell) - 1.0;
424     ParamSrc.m_LowXBorderCell = (int32_t)LowXCell;
425     ParamSrc.m_HighXBorderCell = (int32_t)HighXCell;
426     ParamSrc.m_LowYBorderCell = (int32_t)LowYCell;
427     ParamSrc.m_HighYBorderCell = (int32_t)HighYCell;
428     ParamSrc.m_LowZBorderCell = (int32_t)LowZCell;
429     ParamSrc.m_HighZBorderCell = (int32_t)HighZCell;
430 
431     ParamSrc.m_LowXBorderPartCell = filterMinXCell - LowXCell;
432     ParamSrc.m_HighXBorderPartCell = filterMaxXCell - HighXCell;
433     ParamSrc.m_LowYBorderPartCell = filterMinYCell - LowYCell;
434     ParamSrc.m_HighYBorderPartCell = filterMaxYCell - HighYCell;
435 
436 } // Index::SetCellFilterBounds
437 
LoadIndexVLR(VariableRecord const & vlr)438 bool Index::LoadIndexVLR(VariableRecord const& vlr)
439 {
440 	char DestStr[512];
441 	uint16_t StringLen;
442 	uint16_t ReadPos = 0;
443 
444 	try {
445 		//uint16_t VLRIndexRecLen = vlr.GetRecordLength();
446 		// GetData returns a vector of uint8_t
447 		// std::vector<uint8_t>
448 		// read the first record of our index data
449 		IndexVLRData const& VLRIndexData = vlr.GetData();
450 		// parse the index header data
451 		ReadVLRData_n(m_versionMajor, VLRIndexData, ReadPos);
452 		ReadVLRData_n(m_versionMinor, VLRIndexData, ReadPos);
453 		// creator
454 		ReadVLRData_n(StringLen, VLRIndexData, ReadPos);
455 		ReadeVLRData_str(DestStr, VLRIndexData, StringLen, ReadPos);
456 		SetIndexAuthorStr(DestStr);
457 
458 		// comment
459 		ReadVLRData_n(StringLen, VLRIndexData, ReadPos);
460 		ReadeVLRData_str(DestStr, VLRIndexData, StringLen, ReadPos);
461 		SetIndexCommentStr(DestStr);
462 
463 		// date
464 		ReadVLRData_n(StringLen, VLRIndexData, ReadPos);
465 		ReadeVLRData_str(DestStr, VLRIndexData, StringLen, ReadPos);
466 		SetIndexDateStr(DestStr);
467 
468 		// file index extents
469 		double TempData;
470 		ReadVLRData_n(TempData, VLRIndexData, ReadPos);
471 		SetMinX(TempData);
472 		ReadVLRData_n(TempData, VLRIndexData, ReadPos);
473 		SetMaxX(TempData);
474 		ReadVLRData_n(TempData, VLRIndexData, ReadPos);
475 		SetMinY(TempData);
476 		ReadVLRData_n(TempData, VLRIndexData, ReadPos);
477 		SetMaxY(TempData);
478 		ReadVLRData_n(TempData, VLRIndexData, ReadPos);
479 		SetMinZ(TempData);
480 		ReadVLRData_n(TempData, VLRIndexData, ReadPos);
481 		SetMaxZ(TempData);
482 
483 		// ID number of associated data VLR's - normally 43 but may use heigher numbers
484 		// in order to store more than one index in a file
485 		uint32_t TempLong;
486 		ReadVLRData_n(TempLong, VLRIndexData, ReadPos);
487 		SetDataVLR_ID(TempLong);
488 
489 		// number of points indexed and cells in the index
490 		ReadVLRData_n(TempLong, VLRIndexData, ReadPos);
491 		SetPointRecordsCount(TempLong);
492 		ReadVLRData_n(TempLong, VLRIndexData, ReadPos);
493 		SetCellsX(TempLong);
494 		ReadVLRData_n(TempLong, VLRIndexData, ReadPos);
495 		SetCellsY(TempLong);
496 		ReadVLRData_n(TempLong, VLRIndexData, ReadPos);
497 		SetCellsZ(TempLong);
498 
499 		CalcRangeX();
500 		CalcRangeY();
501 		CalcRangeZ();
502 	} // try
503 	catch (std::bad_alloc) {
504 		return (false);
505 	} // catch
506 	catch (std::out_of_range) {
507 		return (false);
508 	} // catch
509 	return true;
510 
511 } // Index::LoadIndexVLR
512 
FilterOneVLR(VariableRecord const & vlr,uint32_t & i,IndexData & ParamSrc,bool & VLRDone)513 bool Index::FilterOneVLR(VariableRecord const& vlr, uint32_t& i, IndexData & ParamSrc, bool & VLRDone)
514 {
515 
516 	uint32_t ReadPos = 0;
517 	uint32_t MinCellX, MinCellY, MaxCellX, MaxCellY, PointsThisRecord = 0, PointsThisCell = 0, DataRecordSize = 0,
518 		PointsScannedThisTime = 0, PointsScannedCurVLR = 0, PointsToIgnore = 0;
519 	IndexVLRData CompositeData;
520 
521 	try {
522 		IndexVLRData const& VLRIndexRecordData = vlr.GetData();
523 		uint16_t VLRIndexRecLen = vlr.GetRecordLength();
524 		CompositeData.resize(VLRIndexRecLen);
525 		ReadVLRDataNoInc_str((char *)&CompositeData[0], VLRIndexRecordData, VLRIndexRecLen, 0);
526 
527 		ReadVLRData_n(MinCellX, CompositeData, ReadPos);
528 		ReadVLRData_n(MinCellY, CompositeData, ReadPos);
529 		// last cell in VLR, x, y
530 		ReadVLRData_n(MaxCellX, CompositeData, ReadPos);
531 		ReadVLRData_n(MaxCellY, CompositeData, ReadPos);
532 		// data record size
533 		ReadVLRData_n(DataRecordSize, CompositeData, ReadPos);
534 		// number of points in this VLR - added in Index version 1.1
535 		if (m_versionMajor > 1 || m_versionMinor >= 1)
536 			ReadVLRData_n(PointsThisRecord, CompositeData, ReadPos);
537 
538 		if (DataRecordSize > VLRIndexRecLen)
539 		{
540 			CompositeData.resize(DataRecordSize);
541 			// read more records and concatenate data
542 			uint32_t ReadData = VLRIndexRecLen;
543 			uint32_t UnreadData = DataRecordSize - ReadData;
544 			while (UnreadData)
545 			{
546 				++i;
547 				VariableRecord const& vlr2 = m_idxheader.GetVLR(i);
548 				IndexVLRData const& TempData = vlr2.GetData();
549 				uint16_t TempRecLen = vlr2.GetRecordLength();
550 				ReadVLRDataNoInc_str((char *)&CompositeData[ReadData], TempData, TempRecLen, 0);
551 				ReadData += TempRecLen;
552 				if (UnreadData >= TempRecLen)
553 					UnreadData -= TempRecLen;
554 				else
555 					// this is an error if we get here
556 					UnreadData = 0;
557 			} // while
558 		} // if
559 
560 		if (VLRInteresting(MinCellX, MinCellY, MaxCellX, MaxCellY, ParamSrc))
561 		{
562 			// if using iterator, jump to start of last cell that was being scanned
563 			if (ParamSrc.m_iterator && (ParamSrc.m_iterator->m_curCellStartPos >= ReadPos))
564 			{
565 				ReadPos = ParamSrc.m_iterator->m_curCellStartPos;
566 				PointsToIgnore = ParamSrc.m_iterator->m_ptsScannedCurCell;
567 				PointsScannedCurVLR = ParamSrc.m_iterator->m_ptsScannedCurVLR;
568 			} // if
569 			// translate the data for this VLR
570 			while (ReadPos + sizeof (uint32_t) < DataRecordSize)
571 			{
572 				if (ParamSrc.m_iterator)
573 				{
574 					ParamSrc.m_iterator->m_curCellStartPos = ReadPos;
575 					ParamSrc.m_iterator->m_ptsScannedCurCell = 0;
576 				} // if
577 				// current cell, x, y
578 				uint32_t x, y, PtRecords, SubCellsXY, SubCellsZ;
579 				ReadVLRData_n(x, CompositeData, ReadPos);
580 				ReadVLRData_n(y, CompositeData, ReadPos);
581 				if (ParamSrc.m_iterator)
582 				{
583 					ParamSrc.m_iterator->m_curCellX = x;
584 					ParamSrc.m_iterator->m_curCellY = y;
585 				} // if
586 				// number of points in this cell - added in Index version 1.1
587 				if (m_versionMajor > 1 || m_versionMinor >= 1)
588 					ReadVLRData_n(PointsThisCell, CompositeData, ReadPos);
589 
590 				bool TestPointsInThisCell = CellInteresting(x, y, ParamSrc);
591 				// min and max Z
592 				liblas::detail::ElevExtrema CellMinZ, CellMaxZ;
593 				ReadVLRData_n(CellMinZ, CompositeData, ReadPos);
594 				ReadVLRData_n(CellMaxZ, CompositeData, ReadPos);
595 				// number of subcells in this cell in both XY and Z
596 				ReadVLRData_n(PtRecords, CompositeData, ReadPos);
597 				ReadVLRData_n(SubCellsXY, CompositeData, ReadPos);
598 				ReadVLRData_n(SubCellsZ, CompositeData, ReadPos);
599 
600 				// read the data stored in Z cells, if any
601 				for (uint32_t SubCellZ = 0; SubCellZ < SubCellsZ; ++SubCellZ)
602 				{
603 					uint32_t ZCellID;
604 					ReadVLRData_n(ZCellID, CompositeData, ReadPos);
605 					// number of point records in subcell
606 					uint32_t ZCellNumRecords;
607 					ReadVLRData_n(ZCellNumRecords, CompositeData, ReadPos);
608 					for (uint32_t SubCellZPt = 0; SubCellZPt < ZCellNumRecords; ++SubCellZPt)
609 					{
610 						uint32_t PointID;
611 						ReadVLRData_n(PointID, CompositeData, ReadPos);
612 						assert(PointID < m_pointRecordsCount);
613 						liblas::detail::ConsecPtAccumulator ConsecutivePts;
614 						ReadVLRData_n(ConsecutivePts, CompositeData, ReadPos);
615 						if (TestPointsInThisCell && ZCellInteresting(ZCellID, ParamSrc))
616 						{
617 							FilterPointSeries(PointID, PointsScannedThisTime, PointsToIgnore, x, y, ZCellID,
618 								ConsecutivePts, ParamSrc.m_iterator, ParamSrc);
619 						} // if
620 						else
621 						{
622 							PointsScannedThisTime += ConsecutivePts;
623 							if (ParamSrc.m_iterator)
624 								ParamSrc.m_iterator->m_ptsScannedCurCell += ConsecutivePts;
625 						} // else
626 						if (ParamSrc.m_iterator && (m_filterResult.size() >= ParamSrc.m_iterator->m_chunkSize))
627 							break;
628 					} // for
629 					if (ParamSrc.m_iterator && (m_filterResult.size() >= ParamSrc.m_iterator->m_chunkSize))
630 						break;
631 				} // for
632 				// read the data stored in XY quadtree cells
633 				for (uint32_t SubCellXY = 0; SubCellXY < SubCellsXY; ++SubCellXY)
634 				{
635 					uint32_t SubCellID;
636 					ReadVLRData_n(SubCellID, CompositeData, ReadPos);
637 					// number of point records in subcell
638 					uint32_t SubCellNumRecords;
639 					ReadVLRData_n(SubCellNumRecords, CompositeData, ReadPos);
640 					for (uint32_t SubCellPt = 0; SubCellPt < SubCellNumRecords; ++SubCellPt)
641 					{
642 						uint32_t PointID;
643 						ReadVLRData_n(PointID, CompositeData, ReadPos);
644 						assert(PointID < m_pointRecordsCount);
645 						liblas::detail::ConsecPtAccumulator ConsecutivePts;
646 						ReadVLRData_n(ConsecutivePts, CompositeData, ReadPos);
647 						if (TestPointsInThisCell && SubCellInteresting(SubCellID, x, y, ParamSrc))
648 						{
649 							FilterPointSeries(PointID, PointsScannedThisTime, PointsToIgnore, x, y, 0,
650 								ConsecutivePts, ParamSrc.m_iterator, ParamSrc);
651 						} // if
652 						else
653 						{
654 							PointsScannedThisTime += ConsecutivePts;
655 							if (ParamSrc.m_iterator)
656 								ParamSrc.m_iterator->m_ptsScannedCurCell += ConsecutivePts;
657 						} // else
658 						if (ParamSrc.m_iterator && (m_filterResult.size() >= ParamSrc.m_iterator->m_chunkSize))
659 							break;
660 					} // for
661 					if (ParamSrc.m_iterator && (m_filterResult.size() >= ParamSrc.m_iterator->m_chunkSize))
662 						break;
663 				} // for
664 				// read data in unsubdivided cells
665 				if (! (SubCellsZ || SubCellsXY))
666 				{
667 					for (uint32_t CurPt = 0; CurPt < PtRecords; ++CurPt)
668 					{
669 						uint32_t PointID;
670 						ReadVLRData_n(PointID, CompositeData, ReadPos);
671 						assert(PointID < m_pointRecordsCount);
672 						liblas::detail::ConsecPtAccumulator ConsecutivePts;
673 						ReadVLRData_n(ConsecutivePts, CompositeData, ReadPos);
674 						if (TestPointsInThisCell)
675 						{
676 							FilterPointSeries(PointID, PointsScannedThisTime, PointsToIgnore, x, y, 0,
677 								ConsecutivePts, ParamSrc.m_iterator, ParamSrc);
678 						} // if
679 						else
680 						{
681 							PointsScannedThisTime += ConsecutivePts;
682 							if (ParamSrc.m_iterator)
683 								ParamSrc.m_iterator->m_ptsScannedCurCell += ConsecutivePts;
684 						} // else
685 					if (ParamSrc.m_iterator && (m_filterResult.size() >= ParamSrc.m_iterator->m_chunkSize))
686 						break;
687 					} // for
688 				} // if
689 				if (ParamSrc.m_iterator && (m_filterResult.size() >= ParamSrc.m_iterator->m_chunkSize))
690 					break;
691 			} // while
692 			if (PointsScannedThisTime >= PointsToIgnore)
693 			{
694 				PointsScannedCurVLR += PointsScannedThisTime - PointsToIgnore;
695 				if (PointsScannedCurVLR >= PointsThisRecord)
696 					VLRDone = true;
697 				if (ParamSrc.m_iterator)
698 				{
699 					ParamSrc.m_iterator->m_totalPointsScanned += PointsScannedThisTime - PointsToIgnore;
700 					ParamSrc.m_iterator->m_ptsScannedCurVLR = PointsScannedCurVLR;
701 				} // if
702 			} // if
703 		} // if
704 		else if (ParamSrc.m_iterator)
705 		{
706 			ParamSrc.m_iterator->m_totalPointsScanned += PointsThisRecord;
707 			VLRDone = true;
708 		} // else if
709 		// need to be more sophisticated but this is a test
710 	} // try
711 	catch (std::bad_alloc) {
712 		return (false);
713 	} // catch
714 	catch (std::out_of_range) {
715 		return (false);
716 	} // catch
717 	return true;
718 
719 } // Index::FilterOneVLR
720 
FilterPointSeries(uint32_t & PointID,uint32_t & PointsScanned,uint32_t const PointsToIgnore,uint32_t const x,uint32_t const y,uint32_t const z,liblas::detail::ConsecPtAccumulator const ConsecutivePts,IndexIterator * Iterator,IndexData const & ParamSrc)721 bool Index::FilterPointSeries(uint32_t & PointID, uint32_t & PointsScanned,
722 	uint32_t const PointsToIgnore, uint32_t const x, uint32_t const y, uint32_t const z,
723 	liblas::detail::ConsecPtAccumulator const ConsecutivePts, IndexIterator *Iterator,
724 	IndexData const& ParamSrc)
725 {
726 	bool LastPtRead = 0;
727 	uint32_t LastPointID = static_cast<uint32_t>(~0);
728 
729 	try {
730 		for (uint32_t PtCt = 0; PtCt < ConsecutivePts; ++PointID, ++PtCt)
731 		{
732 			++PointsScanned;
733 			if (Iterator)
734 				++Iterator->m_ptsScannedCurCell;
735 			if (PointsScanned > PointsToIgnore)
736 			{
737 				if (FilterOnePoint(x, y, z, PointID, LastPointID, LastPtRead, ParamSrc))
738 				{
739 					bool SkipIt = false;
740 					if (Iterator)
741 					{
742 						++Iterator->m_conformingPtsFound;
743 						if (Iterator->m_advance)
744 						{
745 							--Iterator->m_advance;
746 							if (Iterator->m_advance)
747 								SkipIt = true;
748 						} // if
749 					} // if
750 					if (! SkipIt)
751 					{
752 						m_filterResult.push_back(PointID);
753 						if (Iterator && (m_filterResult.size() >= Iterator->m_chunkSize))
754 							break;
755 					} // if
756 				} // if
757 			} // if
758 			LastPointID = PointID;
759 		} // for
760 		return (true);
761 	} // try
762 	catch (std::bad_alloc) {
763 		return (false);
764 	} // catch
765 
766 } // Index::FilterPointSeries
767 
VLRInteresting(int32_t MinCellX,int32_t MinCellY,int32_t MaxCellX,int32_t MaxCellY,IndexData const & ParamSrc)768 bool Index::VLRInteresting(int32_t MinCellX, int32_t MinCellY, int32_t MaxCellX, int32_t MaxCellY, IndexData const& ParamSrc)
769 {
770 
771 	// cells are written in south to north cell order columns (x) and west to east rows (y)
772 	// The writing loops through y inside a for x loop. Therefore if the low x and high x are not the same then
773 	// we have to assume that all y cells are interesting
774 	if (ParamSrc.m_noFilterX || (MaxCellX >= ParamSrc.m_LowXBorderCell && MinCellX <= ParamSrc.m_HighXBorderCell))
775 	{
776 		if (ParamSrc.m_noFilterY || (MaxCellX != MinCellX) ||
777 			(MaxCellY >= ParamSrc.m_LowYBorderCell && MinCellY <= ParamSrc.m_HighYBorderCell))
778 			return true;
779 	} // if
780 	return false;
781 
782 } // Index::VLRInteresting
783 
CellInteresting(int32_t XCellID,int32_t YCellID,IndexData const & ParamSrc)784 bool Index::CellInteresting(int32_t XCellID, int32_t YCellID, IndexData const& ParamSrc)
785 {
786 
787 	if (ParamSrc.m_noFilterX || (XCellID >= ParamSrc.m_LowXBorderCell && XCellID <= ParamSrc.m_HighXBorderCell))
788 	{
789 		if (ParamSrc.m_noFilterY || (YCellID >= ParamSrc.m_LowYBorderCell && YCellID <= ParamSrc.m_HighYBorderCell))
790 			return true;
791 	} // if
792 	return false;
793 
794 } // Index::CellInteresting
795 
ZCellInteresting(int32_t ZCellID,IndexData const & ParamSrc)796 bool Index::ZCellInteresting(int32_t ZCellID, IndexData const& ParamSrc)
797 {
798 
799 	if (ParamSrc.m_noFilterZ || (ZCellID >= ParamSrc.m_LowZBorderCell && ZCellID <= ParamSrc.m_HighZBorderCell))
800 	{
801 		return true;
802 	} // if
803 	return false;
804 
805 } // Index::ZCellInteresting
806 
SubCellInteresting(int32_t SubCellID,int32_t XCellID,int32_t YCellID,IndexData const & ParamSrc)807 bool Index::SubCellInteresting(int32_t SubCellID, int32_t XCellID, int32_t YCellID, IndexData const& ParamSrc)
808 {
809 	bool XGood = false, YGood = false;
810 
811 	// only need test sub cell if border cell
812 	if (ParamSrc.m_noFilterX || (XCellID >= ParamSrc.m_LowXCellCompletelyIn && XCellID <= ParamSrc.m_HighXCellCompletelyIn))
813 	{
814 		XGood = true;
815 	} // if
816 	else
817 	{
818 		if (XCellID == ParamSrc.m_LowXBorderCell)
819 		{
820 			// left (low) border cell
821 			if (SubCellID == 0 || SubCellID == 2)
822 			{
823 				// low half of cell in X
824 				// only true if boundary of search area falls in the left (lower) half of the cell
825 				if (ParamSrc.m_LowXBorderPartCell <= .5)	// .5 exactly is part of low half of cell
826 					XGood = true;
827 			} // if
828 			else
829 			{
830 				// high half of cell in X
831 				// always true if boundary of search area falls anywhere in the cell
832 				XGood = true;
833 			} // else
834 		} // if
835 		else
836 		{
837 			// right (upper) border cell
838 			if (SubCellID == 0 || SubCellID == 2)
839 			{
840 				// low half of cell in X
841 				// always true if boundary of search area falls anywhere in the cell
842 				XGood = true;
843 			} // if
844 			else
845 			{
846 				// high half of cell in X
847 				// only true if boundary of search area falls in the right (upper) half of the cell
848 				if (ParamSrc.m_HighXBorderPartCell > .5)
849 					XGood = true;
850 			} // else
851 		} // else
852 	} // else
853 	if (ParamSrc.m_noFilterY || (YCellID >= ParamSrc.m_LowYCellCompletelyIn && YCellID <= ParamSrc.m_HighYCellCompletelyIn))
854 	{
855 		YGood = true;
856 	} // if
857 	else
858 	{
859 		if (YCellID == ParamSrc.m_LowYBorderCell)
860 		{
861 			// bottom (low) border cell
862 			if (SubCellID == 0 || SubCellID == 1)
863 			{
864 				// low half of cell in Y
865 				// only true if boundary of search area falls in the bottom (lower) half of the cell
866 				if (ParamSrc.m_LowYBorderPartCell <= .5)	// .5 exactly is part of low half of cell
867 					YGood = true;
868 			} // if
869 			else
870 			{
871 				// high half of cell in Y
872 				// always true if boundary of search area falls anywhere in the cell
873 				YGood = true;
874 			} // else
875 		} // if
876 		else
877 		{
878 			// top (upper) border cell
879 			if (SubCellID == 0 || SubCellID == 1)
880 			{
881 				// low half of cell in Y
882 				// always true if boundary of search area falls anywhere in the cell
883 				YGood = true;
884 			} // if
885 			else
886 			{
887 				// high half of cell in Y
888 				// only true if boundary of search area falls in the top (upper) half of the cell
889 				if (ParamSrc.m_HighYBorderPartCell > .5)
890 					YGood = true;
891 			} // else
892 		} // else
893 	} // else
894 
895 	return (XGood && YGood);
896 
897 } // Index::SubCellInteresting
898 
FilterOnePoint(int32_t x,int32_t y,int32_t z,int32_t PointID,int32_t LastPointID,bool & LastPtRead,IndexData const & ParamSrc)899 bool Index::FilterOnePoint(int32_t x, int32_t y, int32_t z, int32_t PointID, int32_t LastPointID, bool &LastPtRead,
900 	IndexData const& ParamSrc)
901 {
902 	bool XGood = false, YGood = false, ZGood = false, PtRead = false;
903 	double PtX, PtY = 0.0, PtZ = 0.0;
904 
905 	// filtering turned on for X?
906 	if (ParamSrc.m_noFilterX)
907 		XGood = true;
908 	// container cell in the region of the filter that requires no individual point testing?
909 	else if (x >= ParamSrc.m_LowXCellCompletelyIn && x <= ParamSrc.m_HighXCellCompletelyIn)
910 		XGood = true;
911 	// container cell in the region of the filter that does require individual point testing?
912 	else if (x == ParamSrc.m_LowXBorderCell || x == ParamSrc.m_HighXBorderCell)
913 	{
914 		// save a file seek if it is the subsequent point from the last one read
915 		if (PointID == LastPointID + 1)
916 		{
917 			if (LastPtRead)
918 			{
919 				PtRead = m_reader->ReadNextPoint();
920 			} // if
921 		} // if
922 		if (! PtRead)
923 		{
924 			// seek and read
925 			assert(static_cast<uint32_t>(PointID) < m_pointRecordsCount);
926 			PtRead = (m_reader->Seek(PointID) && m_reader->ReadNextPoint());
927 		} // if
928 		if (PtRead)
929 		{
930 			Point const& TestPt = m_reader->GetPoint();
931 			PtX = TestPt.GetX();
932 			PtY = TestPt.GetY();
933 			PtZ = TestPt.GetZ();
934 			if (PtX >= ParamSrc.GetMinFilterX() && PtX <= ParamSrc.GetMaxFilterX())
935 				XGood = true;
936 		} // if
937 	} // else
938 	if (XGood)
939 	{
940 		// filtering turned on for Y?
941 		if (ParamSrc.m_noFilterY)
942 			YGood = true;
943 		// container cell in the region of the filter that requires no individual point testing?
944 		else if (y >= ParamSrc.m_LowYCellCompletelyIn && y <= ParamSrc.m_HighYCellCompletelyIn)
945 			YGood = true;
946 		// container cell in the region of the filter that does require individual point testing?
947 		else if (y == ParamSrc.m_LowYBorderCell || y == ParamSrc.m_HighYBorderCell)
948 		{
949 			if (PtRead)
950 			{
951 				// we already have the data for this point
952 				if (PtY >= ParamSrc.GetMinFilterY() && PtY <= ParamSrc.GetMaxFilterY())
953 					YGood = true;
954 			}
955 			else
956 			{
957 				// save a file seek if it is the subsequent point from the last one read
958 				if (PointID == LastPointID + 1)
959 				{
960 					if (LastPtRead)
961 					{
962 						PtRead = m_reader->ReadNextPoint();
963 					} // if
964 				} // if
965 				if (! PtRead)
966 				{
967 					// seek and read
968 					assert(static_cast<uint32_t>(PointID) < m_pointRecordsCount);
969 					PtRead = (m_reader->Seek(PointID) && m_reader->ReadNextPoint());
970 				} // if
971 				if (PtRead)
972 				{
973 					Point const& TestPt = m_reader->GetPoint();
974 					PtY = TestPt.GetY();
975 					PtZ = TestPt.GetZ();
976 					if (PtY >= ParamSrc.GetMinFilterY() && PtY <= ParamSrc.GetMaxFilterY())
977 						YGood = true;
978 				} // if
979 			} // else
980 		} // else if
981 	} // if
982 	if (XGood && YGood)
983 	{
984 		// filtering turned on for Z?
985 		if (ParamSrc.m_noFilterZ)
986 			ZGood = true;
987 		// container cell in the region of the filter that requires no individual point testing?
988 		else if (z >= ParamSrc.m_LowZCellCompletelyIn && z <= ParamSrc.m_HighZCellCompletelyIn)
989 			ZGood = true;
990 		// container cell in the region of the filter that does require individual point testing?
991 		else if (z == ParamSrc.m_LowZBorderCell || z == ParamSrc.m_HighZBorderCell)
992 		{
993 			if (PtRead)
994 			{
995 				// we already have the data for this point
996 				if (PtZ >= ParamSrc.GetMinFilterZ() && PtZ <= ParamSrc.GetMaxFilterZ())
997 					ZGood = true;
998 			}
999 			else
1000 			{
1001 				// save a file seek if it is the subsequent point from the last one read
1002 				if (PointID == LastPointID + 1)
1003 				{
1004 					if (LastPtRead)
1005 					{
1006 						PtRead = m_reader->ReadNextPoint();
1007 					} // if
1008 				} // if
1009 				if (! PtRead)
1010 				{
1011 					// seek and read
1012 					assert(static_cast<uint32_t>(PointID) < m_pointRecordsCount);
1013 					PtRead = (m_reader->Seek(PointID) && m_reader->ReadNextPoint());
1014 				} // if
1015 				if (PtRead)
1016 				{
1017 					Point const& TestPt = m_reader->GetPoint();
1018 					PtZ = TestPt.GetZ();
1019 					if (PtZ >= ParamSrc.GetMinFilterZ() && PtZ <= ParamSrc.GetMaxFilterZ())
1020 						ZGood = true;
1021 				} // if
1022 			} // else
1023 		} // else if
1024 	} // if
1025 	LastPtRead = PtRead;
1026 	return (XGood && YGood && ZGood);
1027 
1028 } // Index::FilterOnePoint
1029 
BuildIndex(void)1030 bool Index::BuildIndex(void)
1031 {
1032 	// Build an array of two dimensions. Sort data points into
1033 	uint32_t MaximumCells = LIBLAS_INDEX_MAXCELLS;
1034 	m_versionMajor = LIBLAS_INDEX_VERSIONMAJOR;
1035 	m_versionMinor = LIBLAS_INDEX_VERSIONMINOR;
1036 
1037 	// reset to beginning of point data records in case points had been examined before index is built
1038 	m_reader->Seek(0);
1039 	// need the header to get number of point records
1040     m_pointRecordsCount = m_pointheader.GetPointRecordsCount();
1041     // get the bounds of the data and scale factors in case they are needed for point translation
1042     m_bounds = Bounds<double>(m_pointheader.GetMinX(), m_pointheader.GetMinY(), m_pointheader.GetMinZ(), m_pointheader.GetMaxX(), m_pointheader.GetMaxY(), m_pointheader.GetMaxZ());
1043     try {
1044 		m_bounds.verify();
1045 	} // try
1046 	catch (std::runtime_error) {
1047 		return (InputBoundsError("Index::BuildIndex"));
1048 	} // catch
1049 	CalcRangeX();
1050 	CalcRangeY();
1051 	CalcRangeZ();
1052 
1053 	if (m_cellSizeZ > 0.0 && ! detail::compare_distance(m_cellSizeZ, 0.0))
1054 		m_cellsZ = static_cast<uint32_t>(ceil(m_rangeZ / m_cellSizeZ));
1055 	else
1056 		m_cellsZ = 1;
1057 
1058 	// under the conditions of one dimension (x or y) being 0 or negative in size, no index is possible
1059 	if ((m_bounds.max)(0) <= (m_bounds.min)(0) || (m_bounds.max)(1) <= (m_bounds.min)(1))
1060 	{
1061 		return (PointBoundsError("Index::BuildIndex"));
1062 	} // if
1063 
1064 	// fix a cell size and number of cells in X and Y to begin the process of indexing
1065 	double XRatio = m_rangeX >= m_rangeY ? 1.0: m_rangeX / m_rangeY;
1066 	double YRatio = m_rangeY >= m_rangeX ? 1.0: m_rangeY / m_rangeX;
1067 
1068 	m_totalCells = m_pointRecordsCount / LIBLAS_INDEX_OPTPTSPERCELL;
1069 	m_totalCells = static_cast<uint32_t>(sqrt((double)m_totalCells));
1070 	if (m_totalCells < 10)
1071 		m_totalCells = 10;	// let's set a minimum number of cells to make the effort worthwhile
1072 	m_cellsX = static_cast<uint32_t>(XRatio * m_totalCells);
1073 	m_cellsY = static_cast<uint32_t>(YRatio * m_totalCells);
1074 	if (m_cellsX < 1)
1075 		m_cellsX = 1;
1076 	if (m_cellsY < 1)
1077 		m_cellsY = 1;
1078 	m_totalCells = m_cellsX * m_cellsY;
1079 	if (m_totalCells > MaximumCells)
1080 	{
1081 		double CellReductionRatio = (double)MaximumCells / (double)m_totalCells;
1082 		CellReductionRatio = sqrt(CellReductionRatio);
1083 		m_cellsX = static_cast<uint32_t>(m_cellsX * CellReductionRatio);
1084 		m_cellsY = static_cast<uint32_t>(m_cellsY * CellReductionRatio);
1085 		m_totalCells = m_cellsX * m_cellsY;
1086 	} // if
1087 	m_cellSizeX = m_rangeX / m_cellsX;
1088 	m_cellSizeY = m_rangeY / m_cellsY;
1089 
1090 	// print some statistics to the console
1091 	if (m_debugOutputLevel > 1)
1092 	{
1093 		fprintf(m_debugger, "Points in file %d, Cell matrix x %d, y %d, z %d\n", m_pointRecordsCount, m_cellsX, m_cellsY,
1094 			m_cellsZ);
1095 		fprintf(m_debugger, "Point ranges x %.2f-%.2f, y %.2f-%.2f, z %.2f-%.2f, z range %.2f\n", (m_bounds.min)(0), (m_bounds.max)(0), (m_bounds.min)(1), (m_bounds.max)(1),
1096 			(m_bounds.min)(2), (m_bounds.max)(2), m_rangeZ);
1097 	} // if
1098 
1099 	// now we know how large our index array is going to be
1100 	// we'll create a vector of that many entities
1101 
1102 	try {
1103 		// a one dimensional array to represent cell matrix
1104 		IndexCellRow IndexCellsY(m_cellsY);
1105 		// a two dimensional array
1106 		IndexCellDataBlock IndexCellBlock(m_cellsX, IndexCellsY);
1107 		liblas::detail::IndexOutput IndexOut(this);
1108 
1109 		// for Z bounds debugging
1110 		uint32_t ZRangeSum = 0;
1111 		uint32_t PointSum = 0;
1112 		// read each point in the file
1113 		// figure out what cell in X and Y
1114 		// test to see if it is the same as the last cell
1115 		uint32_t LastCellX = static_cast<uint32_t>(~0), LastCellY = static_cast<uint32_t>(~0);
1116 		liblas::detail::ElevRange ZRange;
1117 		uint32_t PointID = 0;
1118 		uint32_t LastPointID = 0;
1119 		uint32_t PtsIndexed = 0;
1120 		uint32_t PointsInMemory = 0, MaxPointsInMemory;
1121 		MaxPointsInMemory = m_maxMemoryUsage / sizeof(liblas::detail::IndexCell);
1122 		// ReadNextPoint() throws a std::out_of_range error when it hits end of range so don't
1123 		// get excited when you see it in the debug output
1124 		while (m_reader->ReadNextPoint())
1125 		{
1126 			uint32_t CurCellX, CurCellY;
1127 			// analyze the point to determine its cell ID
1128 			Point const& CurPt = m_reader->GetPoint();
1129 			if (IdentifyCell(CurPt, CurCellX, CurCellY))
1130 			{
1131 				// if same cell as last point, attempt to increment the count of consecutive points for the cell
1132 				// otherwise add a new point, first checking to see if the memory allocated to this process is full
1133 				if (! (CurCellX == LastCellX && CurCellY == LastCellY &&
1134 					IndexCellBlock[CurCellX][CurCellY].IncrementPointRecord(LastPointID)))
1135 				{
1136 					// if memory allocated to this process is full, write all the point data to a temp file
1137 					if (m_tempFileName.size() && PointsInMemory >= MaxPointsInMemory)
1138 					{
1139 						if (! PurgePointsToTempFile(IndexCellBlock))
1140 							return (FileError("Index::BuildIndex"));
1141 						PointsInMemory = 0;
1142 					} // if
1143 					IndexCellBlock[CurCellX][CurCellY].AddPointRecord(PointID);
1144 					LastPointID = PointID;
1145 					LastCellX = CurCellX;
1146 					LastCellY = CurCellY;
1147 					++PointsInMemory;
1148 				} // else
1149 			// update Z cell bounds
1150 			IndexCellBlock[CurCellX][CurCellY].UpdateZBounds(CurPt.GetZ());
1151 			} // if
1152 		++PointID;
1153 		} // while
1154 		// write remaining points to temp file
1155 		if (m_tempFileName.size())
1156 		{
1157 			if (! PurgePointsToTempFile(IndexCellBlock))
1158 				return (FileError("Index::BuildIndex"));
1159 		} // if using temp file
1160 
1161 		// print some statistics to the console
1162 		if (m_debugOutputLevel > 2)
1163 		{
1164 			if (! OutputCellStats(IndexCellBlock))
1165 			{
1166 				return (DebugOutputError("Index::BuildIndex"));
1167 			} // if
1168 		} // if
1169 
1170 		// Here's where it gets fun
1171 		// Read the binned data from the temp file, one cell at a time
1172 		// Store the data in Variable records section of the LAS file
1173 		// If a cell contains too many points, subdivide the cell and save sub-cells within the cell structure
1174 		// If Z-binning is desired, define the bounds of each Z zone and subdivide sort each cell's points into Z bins
1175 		// Save Z bins within the cell structure.
1176 
1177 		if (IndexOut.InitiateOutput())
1178 		{
1179 			for (uint32_t x = 0; x < m_cellsX; ++x)
1180 			{
1181 				for (uint32_t y = 0; y < m_cellsY; ++y)
1182 				{
1183 					if (m_debugOutputLevel > 3)
1184 						fprintf(m_debugger, "reloading %d %d\n", x, y);
1185 					if (LoadCellFromTempFile(&IndexCellBlock[x][y], x, y))
1186 					{
1187 						ZRange = IndexCellBlock[x][y].GetZRange();
1188 						// if Z-binning is specified, create Z sub-cells first
1189 						// otherwise, subdivide the cell by quadrants if the number of points in the cell
1190 						// exceeds LIBLAS_INDEX_MAXPTSPERCELL
1191 						if ((m_cellsZ > 1 && ZRange > m_cellSizeZ) ||
1192 							(IndexCellBlock[x][y].GetNumPoints() > LIBLAS_INDEX_MAXPTSPERCELL))
1193 						{
1194 							// walk the points in this cell and divvy them up into Z - cells or quadtree cells
1195 							// create an iterator for the map
1196 							// walk the map entities
1197 							liblas::detail::IndexCellData::iterator MapIt = IndexCellBlock[x][y].GetFirstRecord();
1198 							for (; MapIt != IndexCellBlock[x][y].GetEnd(); ++MapIt)
1199 							{
1200 								// get the actual point from the las file
1201 								assert(MapIt->first < m_pointRecordsCount);
1202 								if (m_reader->Seek(MapIt->first) && m_reader->ReadNextPoint())
1203 								{
1204 									uint32_t FirstPt = 0, LastCellZ = static_cast<uint32_t>(~0);
1205 									uint32_t LastSubCell = static_cast<uint32_t>(~0);
1206 									for (liblas::detail::ConsecPtAccumulator PtsTested = 0; PtsTested < MapIt->second; )
1207 									{
1208 										Point const& CurPt = m_reader->GetPoint();
1209 										// Z cell subdivision takes precedence over sub-cell quadrant subdivision
1210 										if (m_cellsZ > 1 && ZRange > m_cellSizeZ)
1211 										{
1212 											// for the number of consecutive points, identify the Z cell
1213 											uint32_t CurCellZ;
1214 											if (IdentifyCellZ(CurPt, CurCellZ))
1215 											{
1216 												// add a record to the z cell chain or increment existing record
1217 												if (! (CurCellZ == LastCellZ && IndexCellBlock[x][y].IncrementZCell(CurCellZ, FirstPt)))
1218 												{
1219 													FirstPt = MapIt->first + PtsTested;
1220 													IndexCellBlock[x][y].AddZCell(CurCellZ, FirstPt);
1221 													LastCellZ = CurCellZ;
1222 												} // else
1223 											} // if
1224 										} // if
1225 										else
1226 										{
1227 											uint32_t CurSubCell;
1228 											// for the number of consecutive points, identify the sub cell in a 2x2 matrix
1229 											// 0 is lower left, 1 is lower right, 2 is upper left, 3 is upper right
1230 											if (IdentifySubCell(CurPt, x, y, CurSubCell))
1231 											{
1232 												// add a record to the sub cell chain or increment existing record
1233 												if (! (CurSubCell == LastSubCell && IndexCellBlock[x][y].IncrementSubCell(CurSubCell, FirstPt)))
1234 												{
1235 													FirstPt = MapIt->first + PtsTested;
1236 													IndexCellBlock[x][y].AddSubCell(CurSubCell, FirstPt);
1237 													LastSubCell = CurSubCell;
1238 												} // else
1239 											} // if
1240 										} // else
1241 										++PtsTested;
1242 										if (PtsTested < MapIt->second)
1243 										{
1244 											if (! m_reader->ReadNextPoint())
1245 												return (FileError("Index::BuildIndex"));
1246 										} // if
1247 									} // for
1248 								} // if
1249 								else
1250 									return (FileError("Index::BuildIndex"));
1251 							} // for
1252 							IndexCellBlock[x][y].RemoveMainRecords();
1253 						} // if
1254 						// sum the points for later debugging
1255 						PtsIndexed += IndexCellBlock[x][y].GetNumPoints();
1256 						// write the cell out to permanent file VLR
1257 						if (! IndexOut.OutputCell(&IndexCellBlock[x][y], x, y))
1258 							return (FileError("Index::BuildIndex"));
1259 
1260 						// some statistical stuff for z bounds debugging
1261 						ZRangeSum += ZRange;
1262 						++PointSum;
1263 
1264 						// purge the memory for this cell
1265 						IndexCellBlock[x][y].RemoveAllRecords();
1266 					} // if
1267 					else
1268 					{
1269 						return (FileError("Index::BuildIndex"));
1270 					}  // else
1271 				} // for y
1272 			} // for x
1273 			// done with this baby
1274 			CloseTempFile();
1275 			if (! IndexOut.FinalizeOutput())
1276 				return (FileError("Index::BuildIndex"));
1277 			if (m_debugOutputLevel)
1278 			{
1279 				if (PtsIndexed < m_pointRecordsCount)
1280 				{
1281 				fprintf(m_debugger, "%d of %d points in las file were indexed.\n", PtsIndexed, m_pointRecordsCount);
1282 				} // if
1283 			} // if
1284 			if (m_debugOutputLevel > 2 && PointSum)
1285 			{
1286 				ZRangeSum /= PointSum;
1287 				fprintf(m_debugger, "Z range average per cell %d\n", ZRangeSum);
1288 			} // if
1289 			if (m_writestandaloneindex)
1290 			{
1291 				// save a standalone index file
1292 				if (! SaveIndexInStandAloneFile())
1293 					return false;
1294 			} // if
1295 			else
1296 			{
1297 				// resave the entire file with new index VLR's
1298 				if (! SaveIndexInLASFile())
1299 					return false;
1300 			} // else
1301 		} // if
1302 	} // try
1303 	catch (std::bad_alloc) {
1304 		CloseTempFile();
1305 		return (MemoryError("Index::BuildIndex"));
1306 	} // catch
1307 
1308 	return true;
1309 
1310 } // Index::BuildIndex
1311 
IdentifyCell(Point const & CurPt,uint32_t & CurCellX,uint32_t & CurCellY) const1312 bool Index::IdentifyCell(Point const& CurPt, uint32_t& CurCellX, uint32_t& CurCellY) const
1313 {
1314 	double OffsetX, OffsetY;
1315 
1316 	OffsetX = (CurPt.GetX() - (m_bounds.min)(0)) / m_rangeX;
1317 	if (OffsetX >= 0 && OffsetX < 1.0)
1318 		CurCellX = static_cast<uint32_t>(OffsetX * m_cellsX);
1319 	else if (detail::compare_distance(OffsetX, 1.0))
1320 		CurCellX = m_cellsX - 1;
1321 	else
1322 	{
1323 		return (PointBoundsError("Index::IdentifyCell"));
1324 	} // else
1325 
1326 	OffsetY = (CurPt.GetY() - (m_bounds.min)(1)) / m_rangeY;
1327 	if (OffsetY >= 0 && OffsetY < 1.0)
1328 		CurCellY = static_cast<uint32_t>(OffsetY * m_cellsY);
1329 	else if (detail::compare_distance(OffsetY, 1.0))
1330 		CurCellY = m_cellsY - 1;
1331 	else
1332 	{
1333 		return (PointBoundsError("Index::IdentifyCell"));
1334 	} // else
1335 
1336 	return true;
1337 
1338 } // Index::IdentifyCell
1339 
IdentifyCellZ(Point const & CurPt,uint32_t & CurCellZ) const1340 bool Index::IdentifyCellZ(Point const& CurPt, uint32_t& CurCellZ) const
1341 {
1342 	double OffsetZ;
1343 
1344 	OffsetZ = (CurPt.GetZ() - (m_bounds.min)(2)) / m_rangeZ;
1345 	if (OffsetZ >= 0 && OffsetZ < 1.0)
1346 		CurCellZ = static_cast<uint32_t>(OffsetZ * m_cellsZ);
1347 	else if (detail::compare_distance(OffsetZ, 1.0))
1348 		CurCellZ = m_cellsZ - 1;
1349 	else
1350 	{
1351 		return (PointBoundsError("Index::IdentifyCellZ"));
1352 	} // else
1353 
1354 	return true;
1355 
1356 } // Index::IdentifyCellZ
1357 
IdentifySubCell(Point const & CurPt,uint32_t x,uint32_t y,uint32_t & CurSubCell) const1358 bool Index::IdentifySubCell(Point const& CurPt, uint32_t x, uint32_t y, uint32_t& CurSubCell) const
1359 {
1360 	double Offset, CellMinX, CellMinY;
1361 
1362 	CellMinX = x * m_cellSizeX + (m_bounds.min)(0);
1363 	CellMinY = y * m_cellSizeY + (m_bounds.min)(1);
1364 	// find point position in X
1365 	Offset = (CurPt.GetX() - CellMinX) / m_cellSizeX;
1366 	if (Offset > .5)	//upper half X
1367 	{
1368 		// find point position in Y
1369 		Offset = (CurPt.GetY() - CellMinY) / m_cellSizeY;
1370 		if (Offset > .5)
1371 			CurSubCell = 3;	// upper half of Y, NE
1372 		else	// <= .5
1373 			CurSubCell = 1;	// lower half of Y, SE
1374 	} // if
1375 	else	// lower half X
1376 	{
1377 		// <= .5
1378 		// find point position in Y
1379 		Offset = (CurPt.GetY() - CellMinY) / m_cellSizeY;
1380 		if (Offset > .5)
1381 			CurSubCell = 2;	// upper half of Y, NW
1382 		else	// <= .5
1383 			CurSubCell = 0;	// lower half of Y, SW
1384 	} // else
1385 
1386 	return true;
1387 
1388 } // Index::IdentifySubCell
1389 
PurgePointsToTempFile(IndexCellDataBlock & CellBlock)1390 bool Index::PurgePointsToTempFile(IndexCellDataBlock& CellBlock)
1391 {
1392 	if (m_tempFile || OpenTempFile())
1393 	{
1394 		liblas::detail::TempFileOffsetType EmptyOffset = 0;	// this might not be large enough
1395 
1396 		if (! m_tempFileStarted)
1397 		{
1398 			// there is some setup of the temp file to be done first
1399 			// write out a block of file offsets the size of the number of cells
1400 			for (uint32_t i = 0; i < m_totalCells; ++i)
1401 			{
1402 				if (fwrite(&EmptyOffset, sizeof(liblas::detail::TempFileOffsetType), 1, m_tempFile) < 1)
1403 				{
1404 					return (FileError("Index::PurgePointsToTempFile"));
1405 				} // if error
1406 			} // for
1407 			m_tempFileWrittenBytes = m_totalCells * sizeof(liblas::detail::TempFileOffsetType);
1408 			m_tempFileStarted = true;
1409 		} // if
1410 		for (uint32_t x = 0; x < m_cellsX; ++x)
1411 		{
1412 			for (uint32_t y = 0; y < m_cellsY; ++y)
1413 			{
1414 				uint32_t RecordsToWrite = CellBlock[x][y].GetNumRecords();
1415 				if (RecordsToWrite)
1416 				{
1417 					// write the current file location in the cell block header
1418 					// if cell block header is 0 write the current file location in the file header
1419 					// otherwise write the current file location at the file location specified in the
1420 					// cell block header
1421 					liblas::detail::TempFileOffsetType LastWriteLocation = CellBlock[x][y].GetFileOffset();
1422 					if (LastWriteLocation == 0)
1423 						LastWriteLocation = (x * m_cellsY + y) * sizeof(liblas::detail::TempFileOffsetType);
1424 #ifdef _MSC_VER
1425 					_fseeki64(m_tempFile, LastWriteLocation, SEEK_SET);
1426 #else
1427 					fseek(m_tempFile, LastWriteLocation, SEEK_SET);
1428 #endif
1429 					if (fwrite(&m_tempFileWrittenBytes, sizeof(liblas::detail::TempFileOffsetType), 1, m_tempFile) < 1)
1430 						return (FileError("Index::PurgePointsToTempFile"));
1431 					CellBlock[x][y].SetFileOffset(m_tempFileWrittenBytes);
1432 
1433 					// seek to end of file where next block of data will be written
1434 #ifdef _MSC_VER
1435 					_fseeki64(m_tempFile, 0, SEEK_END);
1436 #else
1437 					fseek(m_tempFile, 0, SEEK_END);
1438 #endif
1439 
1440 					// write a blank space for later placement of next file block for this cell
1441 					if (fwrite(&EmptyOffset, sizeof(liblas::detail::TempFileOffsetType), 1, m_tempFile) < 1)
1442 						return (FileError("Index::PurgePointsToTempFile"));
1443 					m_tempFileWrittenBytes += sizeof(liblas::detail::TempFileOffsetType);
1444 					// write the number of records stored in this section
1445 					if (fwrite(&RecordsToWrite, sizeof(uint32_t), 1, m_tempFile) < 1)
1446 						return (FileError("Index::PurgePointsToTempFile"));
1447 					m_tempFileWrittenBytes += sizeof(uint32_t);
1448 
1449 					liblas::detail::IndexCellData::iterator MapIt = CellBlock[x][y].GetFirstRecord();
1450 					for (uint32_t RecordNum = 0; RecordNum < RecordsToWrite && MapIt != CellBlock[x][y].GetEnd(); ++RecordNum, ++MapIt)
1451 					{
1452 						// write the point ID
1453 						uint32_t PointID = MapIt->first;
1454 						// write the number of consecutive points
1455 						liblas::detail::ConsecPtAccumulator ConsecutivePoints = MapIt->second;
1456 						if (fwrite(&PointID, sizeof(uint32_t), 1, m_tempFile) < 1)
1457 							return (FileError("Index::PurgePointsToTempFile"));
1458 						if (fwrite(&ConsecutivePoints, sizeof(liblas::detail::ConsecPtAccumulator), 1, m_tempFile) < 1)
1459 							return (FileError("Index::PurgePointsToTempFile"));
1460 						m_tempFileWrittenBytes += sizeof(uint32_t);
1461 						m_tempFileWrittenBytes += sizeof(liblas::detail::ConsecPtAccumulator);
1462 					} // for
1463 					// purge the records for this cell from active memory
1464 					CellBlock[x][y].RemoveMainRecords();
1465 				} // if
1466 			} // for y
1467 		} // for x
1468 		// necessary for subsequent reads in case fseek isn't called first
1469 		fflush(m_tempFile);
1470 		return true;
1471 	} // if file
1472 
1473 	return (FileError("Index::PurgePointsToTempFile"));
1474 
1475 } // Index::PurgePointsToTempFile
1476 
LoadCellFromTempFile(liblas::detail::IndexCell * CellBlock,uint32_t CurCellX,uint32_t CurCellY)1477 bool Index::LoadCellFromTempFile(liblas::detail::IndexCell *CellBlock,
1478 	uint32_t CurCellX, uint32_t CurCellY)
1479 {
1480 
1481 	uint32_t RecordsToRead, FormerNumPts, NewNumPts = 0;
1482 	liblas::detail::TempFileOffsetType FileOffset;
1483 
1484 	FormerNumPts = CellBlock->GetNumPoints();
1485 	CellBlock->SetNumPoints(0);
1486 
1487 	// load the cell as it was written
1488 	// read the first offset for this cell
1489 
1490 #ifdef _MSC_VER
1491 	if (_fseeki64(m_tempFile, (CurCellX * m_cellsY + CurCellY) * sizeof (liblas::detail::TempFileOffsetType), SEEK_SET))
1492 #else
1493 	if (fseek(m_tempFile, (CurCellX * m_cellsY + CurCellY) * sizeof (liblas::detail::TempFileOffsetType), SEEK_SET))
1494 #endif
1495 		return (FileError("Index::LoadCellFromTempFile"));
1496 	if (fread(&FileOffset, sizeof (liblas::detail::TempFileOffsetType), 1, m_tempFile) < 1)
1497 		return (FileError("Index::LoadCellFromTempFile"));
1498 	while (FileOffset > 0)
1499 	{
1500 		// jump to the first block for this cell, read the next offset
1501 
1502 #ifdef _MSC_VER
1503 		if (_fseeki64(m_tempFile, FileOffset, SEEK_SET))
1504 #else
1505 		if (fseek(m_tempFile, FileOffset, SEEK_SET))
1506 #endif
1507 
1508 			return (FileError("Index::LoadCellFromTempFile"));
1509 		if (fread(&FileOffset, sizeof (liblas::detail::TempFileOffsetType), 1, m_tempFile) < 1)
1510 			return (FileError("Index::LoadCellFromTempFile"));
1511 		// read the data for the cell in this block
1512 		// first is the number of items to read now
1513 		if (fread(&RecordsToRead, sizeof (uint32_t), 1, m_tempFile) < 1)
1514 			return (FileError("Index::LoadCellFromTempFile"));
1515 		for (uint32_t RecordNum = 0; RecordNum < RecordsToRead; ++RecordNum)
1516 		{
1517 			uint32_t PointID;
1518 			liblas::detail::ConsecPtAccumulator ConsecutivePoints;
1519 			// read the point ID
1520 			if (fread(&PointID, sizeof(uint32_t), 1, m_tempFile) < 1)
1521 				return (FileError("Index::LoadCellFromTempFile"));
1522 			// read the number of consecutive points
1523 			if (fread(&ConsecutivePoints, sizeof(liblas::detail::ConsecPtAccumulator), 1, m_tempFile) < 1)
1524 				return (FileError("Index::LoadCellFromTempFile"));
1525 			CellBlock->AddPointRecord(PointID, ConsecutivePoints);
1526 		} // for
1527 	} // while
1528 	// check to see that we got the number of points back that we started with
1529 	NewNumPts = CellBlock->GetNumPoints();
1530 	if (NewNumPts != FormerNumPts)
1531 	{
1532 		CloseTempFile();
1533 		return (PointCountError("Index::LoadCellFromTempFile"));
1534 	} // if
1535 	return (true);
1536 
1537 } // Index::LoadCellFromTempFile
1538 
OpenTempFile(void)1539 FILE *Index::OpenTempFile(void)
1540 {
1541 
1542 	m_tempFileStarted = 0;
1543 	m_tempFileWrittenBytes = 0;
1544 	return (m_tempFile = fopen(m_tempFileName.c_str(), "wb+"));
1545 
1546 } // Index::OpenTempFile
1547 
CloseTempFile(void)1548 void Index::CloseTempFile(void)
1549 {
1550 
1551 	if (m_tempFile)
1552 	{
1553 		fclose(m_tempFile);
1554 		remove(m_tempFileName.c_str());
1555 	} // if
1556 	m_tempFile = 0;
1557 	m_tempFileWrittenBytes = 0;
1558 
1559 } // Index::CloseTempFile
1560 
SaveIndexInLASFile(void)1561 bool Index::SaveIndexInLASFile(void)
1562 {
1563 	try {
1564 		Writer writer(*m_ofs, m_idxheader);
1565 		m_reader->Seek(0);
1566 		while (m_reader->ReadNextPoint())
1567 		{
1568 			Point const& CurPt = m_reader->GetPoint();
1569 			if (! writer.WritePoint(CurPt))
1570 				return (OutputFileError("Index::SaveIndexInLASFile"));
1571 		} // while
1572 	} // try
1573 	catch (std::runtime_error) {
1574 		return (OutputFileError("Index::SaveIndexInLASFile"));
1575 	} // catch
1576 	return true;
1577 } // Index::SaveIndexInLASFile
1578 
SaveIndexInStandAloneFile(void)1579 bool Index::SaveIndexInStandAloneFile(void)
1580 {
1581 	try {
1582 		Writer writer(*m_ofs, m_idxheader);
1583 		/* test block - uncommenting this makes it just like above version with included points
1584 		m_reader->Seek(0);
1585 		while (m_reader->ReadNextPoint())
1586 		{
1587 			Point const& CurPt = m_reader->GetPoint();
1588 			if (! writer.WritePoint(CurPt))
1589 				return (OutputFileError("Index::SaveIndexInLASFile"));
1590 		} // while
1591 		*/
1592 	} // try
1593 	catch (std::runtime_error) {
1594 		return (OutputFileError("Index::SaveIndexInStandAloneFile"));
1595 	} // catch
1596 	return true;
1597 } // Index::SaveIndexInStandAloneFile
1598 
FileError(const char * Reporter)1599 bool Index::FileError(const char *Reporter)
1600 {
1601 
1602 	CloseTempFile();
1603 	if (m_debugOutputLevel)
1604 		fprintf(m_debugger, "File i/o error, %s\n", Reporter);
1605 	return false;
1606 
1607 } // Index::FileError
1608 
InputFileError(const char * Reporter) const1609 bool Index::InputFileError(const char *Reporter) const
1610 {
1611 
1612 	if (m_debugOutputLevel)
1613 		fprintf(m_debugger, "Input file i/o error, %s\n", Reporter);
1614 	return false;
1615 
1616 } // Index::InputFileError
1617 
OutputFileError(const char * Reporter) const1618 bool Index::OutputFileError(const char *Reporter) const
1619 {
1620 
1621 	if (m_debugOutputLevel)
1622 		fprintf(m_debugger, "Output file i/o error, %s\n", Reporter);
1623 	return false;
1624 
1625 } // Index::OutputFileError
1626 
DebugOutputError(const char * Reporter) const1627 bool Index::DebugOutputError(const char *Reporter) const
1628 {
1629 
1630 	if (m_debugOutputLevel)
1631 		fprintf(m_debugger, "Debug output error, %s\n", Reporter);
1632 	return false;
1633 
1634 } // Index::DebugOutputError
1635 
PointCountError(const char * Reporter) const1636 bool Index::PointCountError(const char *Reporter) const
1637 {
1638 
1639 	if (m_debugOutputLevel)
1640 		fprintf(m_debugger, "Point checksum error, %s\n", Reporter);
1641 	return false;
1642 
1643 } // Index::PointCountError
1644 
PointBoundsError(const char * Reporter) const1645 bool Index::PointBoundsError(const char *Reporter) const
1646 {
1647 
1648 	if (m_debugOutputLevel)
1649 		fprintf(m_debugger, "Point out of bounds error, %s\n", Reporter);
1650 	return false;
1651 
1652 } // Index::PointBoundsError
1653 
MemoryError(const char * Reporter) const1654 bool Index::MemoryError(const char *Reporter) const
1655 {
1656 
1657 	if (m_debugOutputLevel)
1658 		fprintf(m_debugger, "Memory error, %s\n", Reporter);
1659 	return false;
1660 
1661 } // Index::MemoryError
1662 
InitError(const char * Reporter) const1663 bool Index::InitError(const char *Reporter) const
1664 {
1665 
1666 	if (m_debugOutputLevel)
1667 		fprintf(m_debugger, "Index creation failure, %s\n", Reporter);
1668 	return false;
1669 
1670 } // Index::InitError
1671 
InputBoundsError(const char * Reporter) const1672 bool Index::InputBoundsError(const char *Reporter) const
1673 {
1674 
1675 	if (m_debugOutputLevel)
1676 		fprintf(m_debugger, "Input file has inappropriate bounds, %s\n", Reporter);
1677 	return false;
1678 
1679 } // Index::InputBoundsError
1680 
1681 #define LIBLAS_INDEX_DEBUGCELLBINS 20
1682 
OutputCellStats(IndexCellDataBlock & CellBlock) const1683 bool Index::OutputCellStats(IndexCellDataBlock& CellBlock) const
1684 {
1685 	uint32_t MaxPointsPerCell = 0;
1686 
1687 	for (uint32_t x = 0; x < m_cellsX; ++x)
1688 	{
1689 		for (uint32_t y = 0; y < m_cellsY; ++y)
1690 		{
1691 			uint32_t PointsThisCell = CellBlock[x][y].GetNumPoints();
1692 			if (PointsThisCell > MaxPointsPerCell)
1693 				MaxPointsPerCell = PointsThisCell;
1694 		} // for
1695 	} // for
1696 
1697 	std::vector<uint32_t> CellPopulation(LIBLAS_INDEX_DEBUGCELLBINS);
1698 
1699 	for (uint32_t x = 0; x < m_cellsX; ++x)
1700 	{
1701 		for (uint32_t y = 0; y < m_cellsY; ++y)
1702 		{
1703 			uint32_t PointsThisCell = CellBlock[x][y].GetNumPoints();
1704 			uint32_t BinThisCell = (uint32_t )(LIBLAS_INDEX_DEBUGCELLBINS * (double)PointsThisCell / (double)MaxPointsPerCell);
1705 			if (BinThisCell >= LIBLAS_INDEX_DEBUGCELLBINS)
1706 				BinThisCell = LIBLAS_INDEX_DEBUGCELLBINS - 1;
1707 			++CellPopulation[BinThisCell];
1708 		} // for
1709 	} // for
1710 
1711 	fprintf(m_debugger, "Max points per cell %d\n", MaxPointsPerCell);
1712 	OutputCellGraph(CellPopulation, MaxPointsPerCell);
1713 	// no way for this to fail at this time but allow for future modifications by having a return value
1714 	return true;
1715 
1716 } // Index::OutputCellStats
1717 
OutputCellGraph(std::vector<uint32_t> CellPopulation,uint32_t MaxPointsPerCell) const1718 bool Index::OutputCellGraph(std::vector<uint32_t> CellPopulation, uint32_t MaxPointsPerCell) const
1719 {
1720 
1721 	for (uint32_t i = 0; i < CellPopulation.size(); ++i)
1722 	{
1723 		fprintf(m_debugger,"Bin %2d (%4d-%4d)... Cells in point range bin %d\n", i, (i * MaxPointsPerCell / LIBLAS_INDEX_DEBUGCELLBINS),
1724 			((i + 1)* MaxPointsPerCell / LIBLAS_INDEX_DEBUGCELLBINS), CellPopulation[i]);
1725 	} // for
1726 	// no way for this to fail at this time but allow for future modifications by having a return value
1727 	return true;
1728 
1729 } // Index::OutputCellGraph
1730 
GetIndexAuthorStr(void) const1731 const char *Index::GetIndexAuthorStr(void) const
1732 {
1733 	return (m_indexAuthor.c_str());
1734 } // Index::GetIndexAuthorStr
1735 
GetIndexCommentStr(void) const1736 const char *Index::GetIndexCommentStr(void) const
1737 {
1738 	return (m_indexComment.c_str());
1739 } // Index::GetIndexAuthorStr
1740 
GetIndexDateStr(void) const1741 const char *Index::GetIndexDateStr(void) const
1742 {
1743 	return (m_indexDate.c_str());
1744 } // Index::GetIndexAuthorStr
1745 
IndexData(void)1746 IndexData::IndexData(void)
1747 {
1748 	SetValues();
1749 } // IndexData::IndexData
1750 
IndexData(Index const & index)1751 IndexData::IndexData(Index const& index)
1752 {
1753 	SetValues();
1754 	m_reader = index.GetReader();
1755 	m_idxreader = index.GetIndexReader();
1756 	m_filter = index.GetBounds();
1757     m_debugOutputLevel = index.GetDebugOutputLevel();
1758 	m_tempFileName = index.GetTempFileName() ? index.GetTempFileName(): "";
1759 	m_indexAuthor = index.GetIndexAuthorStr() ? index.GetIndexAuthorStr(): "";
1760 	m_indexComment = index.GetIndexCommentStr() ? index.GetIndexCommentStr(): "";
1761 	m_indexDate = index.GetIndexDateStr() ? index.GetIndexDateStr(): "";
1762 	m_cellSizeZ = index.GetCellSizeZ();
1763 	m_debugger = index.GetDebugger() ? index.GetDebugger(): stderr;
1764 	m_readOnly = index.GetReadOnly();
1765 	m_forceNewIndex = index.GetForceNewIndex();
1766 	if (index.GetMaxMemoryUsage() > 0)
1767 		m_maxMemoryUsage = index.GetMaxMemoryUsage();
1768 	else
1769 		m_maxMemoryUsage = LIBLAS_INDEX_MAXMEMDEFAULT;
1770 	if (m_maxMemoryUsage < LIBLAS_INDEX_MINMEMDEFAULT)
1771 		m_maxMemoryUsage = LIBLAS_INDEX_MINMEMDEFAULT;
1772 	m_indexValid = index.IndexReady();
1773 } // IndexData::IndexData
1774 
IndexData(IndexData const & other)1775 IndexData::IndexData(IndexData const& other)
1776 {
1777 	Copy(other);
1778 } // IndexData::IndexData
1779 
operator =(IndexData const & rhs)1780 IndexData& IndexData::operator=(IndexData const& rhs)
1781 {
1782     Copy(rhs);
1783 	return (*this);
1784 } // IndexData::operator=
1785 
Copy(IndexData const & other)1786 void IndexData::Copy(IndexData const& other)
1787 {
1788     if (&other != this)
1789     {
1790 		m_reader = other.m_reader;
1791 		m_idxreader = other.m_idxreader;
1792 		m_iterator = other.m_iterator;
1793 		m_ifs = other.m_ifs;
1794 		m_ofs = other.m_ofs;
1795 		m_tempFileName = other.m_tempFileName;
1796 		m_indexAuthor = other.m_indexAuthor;
1797 		m_indexComment = other.m_indexComment;
1798 		m_indexDate = other.m_indexDate;
1799 		m_cellSizeZ = other.m_cellSizeZ;
1800 		m_maxMemoryUsage = other.m_maxMemoryUsage;
1801 		m_debugOutputLevel = other.m_debugOutputLevel;
1802 		m_readOnly = other.m_readOnly;
1803 		m_writestandaloneindex = other.m_writestandaloneindex;
1804 		m_forceNewIndex = other.m_forceNewIndex;
1805 		m_debugger = other.m_debugger;
1806 		m_indexValid = other.m_indexValid;
1807 		m_noFilterX = other.m_noFilterX;
1808 		m_noFilterY = other.m_noFilterY;
1809 		m_noFilterZ = other.m_noFilterZ;
1810 		m_filter = other.m_filter;
1811 		m_LowXCellCompletelyIn = other.m_LowXCellCompletelyIn;
1812 		m_HighXCellCompletelyIn = other.m_HighXCellCompletelyIn;
1813 		m_LowYCellCompletelyIn = other.m_LowYCellCompletelyIn;
1814 		m_HighYCellCompletelyIn = other.m_HighYCellCompletelyIn;
1815 		m_LowZCellCompletelyIn = other.m_LowZCellCompletelyIn;
1816 		m_HighZCellCompletelyIn = other.m_HighZCellCompletelyIn;
1817 		m_LowXBorderCell = other.m_LowXBorderCell;
1818 		m_HighXBorderCell = other.m_HighXBorderCell;
1819 		m_LowYBorderCell = other.m_LowYBorderCell;
1820 		m_HighYBorderCell = other.m_HighYBorderCell;
1821 		m_LowZBorderCell = other.m_LowZBorderCell;
1822 		m_HighZBorderCell = other.m_HighZBorderCell;
1823 		m_LowXBorderPartCell = other.m_LowXBorderPartCell;
1824 		m_HighXBorderPartCell = other.m_HighXBorderPartCell;
1825 		m_LowYBorderPartCell = other.m_LowYBorderPartCell;
1826 		m_HighYBorderPartCell = other.m_HighYBorderPartCell;
1827 	} // if
1828 } // IndexData::Copy
1829 
SetValues(void)1830 void IndexData::SetValues(void)
1831 {
1832 	m_reader = 0;
1833 	m_idxreader = 0;
1834 	m_iterator = 0;
1835 	m_ifs = 0;
1836 	m_ofs = 0;
1837 	m_tempFileName = 0;
1838 	m_indexAuthor = 0;
1839 	m_indexComment = 0;
1840 	m_indexDate = 0;
1841 	m_cellSizeZ = 0.0;
1842 	m_maxMemoryUsage = 0;
1843 	m_debugOutputLevel = 0;
1844 	m_readOnly = false;
1845 	m_writestandaloneindex = false;
1846 	m_forceNewIndex = false;
1847 	m_debugger = 0;
1848 	m_indexValid = false;
1849 	m_noFilterX = m_noFilterY = m_noFilterZ = false;
1850     m_LowXCellCompletelyIn = m_HighXCellCompletelyIn = m_LowYCellCompletelyIn = m_HighYCellCompletelyIn =
1851 		m_LowZCellCompletelyIn = m_HighZCellCompletelyIn =
1852 		m_LowXBorderCell = m_HighXBorderCell = m_LowYBorderCell = m_HighYBorderCell =
1853 		m_LowZBorderCell = m_HighZBorderCell = 0;
1854 	m_LowXBorderPartCell = m_HighXBorderPartCell = m_LowYBorderPartCell = m_HighYBorderPartCell = 0.0;
1855 } // IndexData::SetValues
1856 
SetInitialValues(std::istream * ifs,Reader * reader,std::ostream * ofs,Reader * idxreader,const char * tmpfilenme,const char * indexauthor,const char * indexcomment,const char * indexdate,double zbinht,uint32_t maxmem,int debugoutputlevel,bool readonly,bool writestandaloneindex,bool forcenewindex,FILE * debugger)1857 bool IndexData::SetInitialValues(std::istream *ifs, Reader *reader, std::ostream *ofs, Reader *idxreader,
1858 	const char *tmpfilenme, const char *indexauthor,
1859 	const char *indexcomment, const char *indexdate, double zbinht,
1860 	uint32_t maxmem, int debugoutputlevel, bool readonly, bool writestandaloneindex,
1861 	bool forcenewindex, FILE *debugger)
1862 {
1863 
1864 	m_ifs = ifs;
1865 	m_ofs = ofs;
1866 	m_reader = reader;
1867 	m_idxreader = idxreader;
1868 	m_iterator = 0;
1869 	m_tempFileName = tmpfilenme;
1870 	m_indexAuthor = indexauthor;
1871 	m_indexComment = indexcomment;
1872 	m_indexDate = indexdate;
1873 	m_cellSizeZ = zbinht;
1874 	m_maxMemoryUsage = maxmem;
1875 	m_debugOutputLevel = debugoutputlevel;
1876 	m_readOnly = readonly;
1877 	m_writestandaloneindex = writestandaloneindex;
1878 	m_forceNewIndex = forcenewindex;
1879 	m_debugger = debugger;
1880 	m_indexValid = false;
1881     m_LowXCellCompletelyIn = m_HighXCellCompletelyIn = m_LowYCellCompletelyIn = m_HighYCellCompletelyIn =
1882 		m_LowZCellCompletelyIn = m_HighZCellCompletelyIn =
1883 		m_LowXBorderCell = m_HighXBorderCell = m_LowYBorderCell = m_HighYBorderCell =
1884 		m_LowZBorderCell = m_HighZBorderCell = 0;
1885 	m_LowXBorderPartCell = m_HighXBorderPartCell = m_LowYBorderPartCell = m_HighYBorderPartCell = 0.0;
1886 	return (m_reader || m_ifs);
1887 
1888 } // IndexData::SetInitialValues
1889 
SetBuildEmbedValues(Reader * reader,std::ostream * ofs,const char * tmpfilenme,const char * indexauthor,const char * indexcomment,const char * indexdate,double zbinht,uint32_t maxmem,int debugoutputlevel,FILE * debugger)1890 bool IndexData::SetBuildEmbedValues(Reader *reader, std::ostream *ofs, const char *tmpfilenme, const char *indexauthor,
1891 	const char *indexcomment, const char *indexdate, double zbinht,
1892 	uint32_t maxmem, int debugoutputlevel, FILE *debugger)
1893 {
1894 
1895 	m_ifs = 0;
1896 	m_ofs = ofs;
1897 	m_reader = reader;
1898 	m_idxreader = 0;
1899 	m_iterator = 0;
1900 	m_tempFileName = tmpfilenme;
1901 	m_indexAuthor = indexauthor;
1902 	m_indexComment = indexcomment;
1903 	m_indexDate = indexdate;
1904 	m_cellSizeZ = zbinht;
1905 	m_maxMemoryUsage = maxmem;
1906 	m_debugOutputLevel = debugoutputlevel;
1907 	m_readOnly = false;
1908 	m_writestandaloneindex = false;
1909 	m_forceNewIndex = true;
1910 	m_debugger = debugger;
1911 	m_indexValid = false;
1912 	return (m_reader && m_ofs && m_tempFileName);
1913 
1914 } // IndexData::SetBuildEmbedValues
1915 
SetBuildAloneValues(Reader * reader,std::ostream * ofs,const char * tmpfilenme,const char * indexauthor,const char * indexcomment,const char * indexdate,double zbinht,uint32_t maxmem,int debugoutputlevel,FILE * debugger)1916 bool IndexData::SetBuildAloneValues(Reader *reader, std::ostream *ofs, const char *tmpfilenme, const char *indexauthor,
1917 	const char *indexcomment, const char *indexdate, double zbinht,
1918 	uint32_t maxmem, int debugoutputlevel, FILE *debugger)
1919 {
1920 
1921 	m_ifs = 0;
1922 	m_ofs = ofs;
1923 	m_reader = reader;
1924 	m_idxreader = 0;
1925 	m_iterator = 0;
1926 	m_tempFileName = tmpfilenme;
1927 	m_indexAuthor = indexauthor;
1928 	m_indexComment = indexcomment;
1929 	m_indexDate = indexdate;
1930 	m_cellSizeZ = zbinht;
1931 	m_maxMemoryUsage = maxmem;
1932 	m_debugOutputLevel = debugoutputlevel;
1933 	m_readOnly = false;
1934 	m_writestandaloneindex = true;
1935 	m_forceNewIndex = true;
1936 	m_debugger = debugger;
1937 	m_indexValid = false;
1938 	return (m_reader && m_ofs && m_tempFileName);
1939 
1940 } // IndexData::SetBuildAloneValues
1941 
SetReadEmbedValues(Reader * reader,int debugoutputlevel,FILE * debugger)1942 bool IndexData::SetReadEmbedValues(Reader *reader, int debugoutputlevel, FILE *debugger)
1943 {
1944 
1945 	m_ifs = 0;
1946 	m_ofs = 0;
1947 	m_reader = reader;
1948 	m_idxreader = 0;
1949 	m_iterator = 0;
1950 	m_tempFileName = 0;
1951 	m_indexAuthor = 0;
1952 	m_indexComment = 0;
1953 	m_indexDate = 0;
1954 	m_cellSizeZ = 0.0;
1955 	m_maxMemoryUsage = 0;
1956 	m_debugOutputLevel = debugoutputlevel;
1957 	m_readOnly = true;
1958 	m_writestandaloneindex = false;
1959 	m_forceNewIndex = false;
1960 	m_debugger = debugger;
1961 	m_indexValid = false;
1962 	return (m_reader ? true: false);
1963 
1964 } // IndexData::SetReadEmbedValues
1965 
SetReadAloneValues(Reader * reader,Reader * idxreader,int debugoutputlevel,FILE * debugger)1966 bool IndexData::SetReadAloneValues(Reader *reader, Reader *idxreader, int debugoutputlevel, FILE *debugger)
1967 {
1968 
1969 	m_ifs = 0;
1970 	m_ofs = 0;
1971 	m_reader = reader;
1972 	m_idxreader = idxreader;
1973 	m_iterator = 0;
1974 	m_tempFileName = 0;
1975 	m_indexAuthor = 0;
1976 	m_indexComment = 0;
1977 	m_indexDate = 0;
1978 	m_cellSizeZ = 0.0;
1979 	m_maxMemoryUsage = 0;
1980 	m_debugOutputLevel = debugoutputlevel;
1981 	m_readOnly = true;
1982 	m_writestandaloneindex = false;
1983 	m_forceNewIndex = false;
1984 	m_debugger = debugger;
1985 	m_indexValid = false;
1986 	return (m_reader && m_idxreader);
1987 
1988 } // IndexData::SetReadAloneValues
1989 
SetReadOrBuildEmbedValues(Reader * reader,std::ostream * ofs,const char * tmpfilenme,const char * indexauthor,const char * indexcomment,const char * indexdate,double zbinht,uint32_t maxmem,int debugoutputlevel,FILE * debugger)1990 bool IndexData::SetReadOrBuildEmbedValues(Reader *reader, std::ostream *ofs, const char *tmpfilenme, const char *indexauthor,
1991 	const char *indexcomment, const char *indexdate, double zbinht,
1992 	uint32_t maxmem, int debugoutputlevel, FILE *debugger)
1993 {
1994 
1995 	SetBuildEmbedValues(reader, ofs, tmpfilenme, indexauthor, indexcomment, indexdate, zbinht,
1996 		maxmem, debugoutputlevel, debugger);
1997 
1998 	m_forceNewIndex = false;
1999 	return (m_reader && m_ofs && m_tempFileName);
2000 
2001 } // IndexData::SetBuildEmbedValues
2002 
SetReadOrBuildAloneValues(Reader * reader,std::ostream * ofs,const char * tmpfilenme,const char * indexauthor,const char * indexcomment,const char * indexdate,double zbinht,uint32_t maxmem,int debugoutputlevel,FILE * debugger)2003 bool IndexData::SetReadOrBuildAloneValues(Reader *reader, std::ostream *ofs, const char *tmpfilenme, const char *indexauthor,
2004 	const char *indexcomment, const char *indexdate, double zbinht,
2005 	uint32_t maxmem, int debugoutputlevel, FILE *debugger)
2006 {
2007 
2008 	SetBuildAloneValues(reader, ofs, tmpfilenme, indexauthor, indexcomment, indexdate, zbinht,
2009 		maxmem, debugoutputlevel, debugger);
2010 
2011 	m_forceNewIndex = false;
2012 	return (m_reader && m_ofs && m_tempFileName);
2013 
2014 } // IndexData::SetBuildAloneValues
2015 
SetFilterValues(double LowFilterX,double HighFilterX,double LowFilterY,double HighFilterY,double LowFilterZ,double HighFilterZ,Index const & index)2016 bool IndexData::SetFilterValues(double LowFilterX, double HighFilterX, double LowFilterY, double HighFilterY,
2017 	double LowFilterZ, double HighFilterZ, Index const& index)
2018 {
2019 	try {
2020 		m_filter = Bounds<double>(LowFilterX, LowFilterY, LowFilterZ, HighFilterX, HighFilterY, HighFilterZ);
2021 		m_filter.verify();
2022 		m_filter.clip(index.GetBounds());
2023 	} // try
2024 	catch (std::runtime_error) {
2025 		return (false);
2026 	} // catch verification error
2027 	return (CalcFilterEnablers());
2028 
2029 } // IndexData::SetFilterValues
2030 
SetFilterValues(Bounds<double> const & src,Index const & index)2031 bool IndexData::SetFilterValues(Bounds<double> const& src, Index const& index)
2032 {
2033 	try {
2034 		m_filter = src;
2035 		m_filter.verify();
2036 		m_filter.clip(index.GetBounds());
2037 	} // try
2038 	catch (std::runtime_error) {
2039 		return (false);
2040 	} // catch verification error
2041 	return (CalcFilterEnablers());
2042 
2043 } // IndexData::SetFilterValues
2044 
CalcFilterEnablers(void)2045 bool IndexData::CalcFilterEnablers(void)
2046 {
2047 	if (detail::compare_distance((m_filter.min)(0), (m_filter.max)(0)))
2048 		m_noFilterX = true;
2049 	if (detail::compare_distance((m_filter.min)(1), (m_filter.max)(1)))
2050 		m_noFilterY = true;
2051 	if (detail::compare_distance((m_filter.min)(2), (m_filter.max)(2)))
2052 		m_noFilterZ = true;
2053 	return (! (m_noFilterX && m_noFilterY && m_noFilterZ));
2054 } // IndexData::CalcFilterEnablers
2055 
ClampFilterBounds(Bounds<double> const & m_bounds)2056 void IndexData::ClampFilterBounds(Bounds<double> const& m_bounds)
2057 {
2058 	m_filter.clip(m_bounds);
2059 } // IndexData::ClampFilterBounds
2060 
IndexIterator(Index * IndexSrc,double LowFilterX,double HighFilterX,double LowFilterY,double HighFilterY,double LowFilterZ,double HighFilterZ,uint32_t ChunkSize)2061 IndexIterator::IndexIterator(Index *IndexSrc, double LowFilterX, double HighFilterX, double LowFilterY, double HighFilterY,
2062 	double LowFilterZ, double HighFilterZ, uint32_t ChunkSize)
2063 	: m_indexData(*IndexSrc)
2064 {
2065 	m_index = IndexSrc;
2066 	m_indexData.m_filter = Bounds<double>(LowFilterX, LowFilterY, LowFilterZ, HighFilterX, HighFilterY, HighFilterZ);
2067 	m_chunkSize = ChunkSize;
2068 	m_advance = 0;
2069 	ResetPosition();
2070 } // IndexIterator::IndexIterator
2071 
IndexIterator(Index * IndexSrc,IndexData const & IndexDataSrc,uint32_t ChunkSize)2072 IndexIterator::IndexIterator(Index *IndexSrc, IndexData const& IndexDataSrc, uint32_t ChunkSize)
2073 	: m_indexData(IndexDataSrc)
2074 {
2075 	m_index = IndexSrc;
2076 	m_chunkSize = ChunkSize;
2077 	m_advance = 0;
2078 	ResetPosition();
2079 } // IndexIterator::IndexIterator
2080 
IndexIterator(Index * IndexSrc,Bounds<double> const & BoundsSrc,uint32_t ChunkSize)2081 IndexIterator::IndexIterator(Index *IndexSrc, Bounds<double> const& BoundsSrc, uint32_t ChunkSize)
2082 {
2083 	m_index = IndexSrc;
2084 	m_indexData = IndexData(*IndexSrc);
2085 	m_indexData.m_filter = BoundsSrc;
2086 	m_chunkSize = ChunkSize;
2087 	m_advance = 0;
2088 	ResetPosition();
2089 } // IndexIterator::IndexIterator
2090 
IndexIterator(IndexIterator const & other)2091 IndexIterator::IndexIterator(IndexIterator const& other)
2092 {
2093 	Copy(other);
2094 } // IndexIterator::IndexIterator
2095 
operator =(IndexIterator const & rhs)2096 IndexIterator& IndexIterator::operator=(IndexIterator const& rhs)
2097 {
2098 	Copy(rhs);
2099 	return (*this);
2100 } // IndexIterator::operator=
2101 
Copy(IndexIterator const & other)2102 void IndexIterator::Copy(IndexIterator const& other)
2103 {
2104 	if (&other != this)
2105 	{
2106 		m_index = other.m_index;
2107 		m_indexData = other.m_indexData;
2108 		m_chunkSize = other.m_chunkSize;
2109 		m_advance = other.m_advance;
2110 		m_curVLR = other.m_curVLR;
2111 		m_curCellStartPos = other.m_curCellStartPos;
2112 		m_curCellX = other.m_curCellX;
2113 		m_curCellY = other.m_curCellY;
2114 		m_totalPointsScanned = other.m_totalPointsScanned;
2115 		m_ptsScannedCurCell = other.m_ptsScannedCurCell;
2116 		m_ptsScannedCurVLR = other.m_ptsScannedCurVLR;
2117 		m_conformingPtsFound = other.m_conformingPtsFound;
2118 	} // if
2119 } // IndexIterator::Copy
2120 
ResetPosition(void)2121 void IndexIterator::ResetPosition(void)
2122 {
2123 	m_curVLR = m_curCellStartPos = m_curCellX = m_curCellY = 0;
2124 	m_totalPointsScanned = m_ptsScannedCurCell = m_ptsScannedCurVLR = 0;
2125 	m_conformingPtsFound = 0;
2126 } // IndexIterator::ResetPosition
2127 
operator ()(int32_t n)2128 const std::vector<uint32_t>& IndexIterator::operator()(int32_t n)
2129 {
2130 	if (n <= 0)
2131 	{
2132 		ResetPosition();
2133 		m_advance = 1;
2134 	} // if
2135 	else if ((uint32_t)n < m_conformingPtsFound)
2136 	{
2137 		ResetPosition();
2138 		m_advance = n + 1;
2139 	} // if
2140 	else
2141 	{
2142 		m_advance = n - m_conformingPtsFound + 1;
2143 	} // else
2144 	m_indexData.SetIterator(this);
2145 	return (m_index->Filter(m_indexData));
2146 } // IndexIterator::operator++
2147 
advance(int32_t n)2148 const std::vector<uint32_t>& IndexIterator::advance(int32_t n)
2149 {
2150 	if (n > 0)
2151 		--n;
2152 	return ((*this)(m_conformingPtsFound + n));
2153 } // IndexIterator::advance
2154 
2155 } // namespace liblas
2156 
2157