private void FilterBySigma(Int32 prmSigma) { Int32 pointsRemoved; do { pointsRemoved = 0; IEnumerable <TcReportPoint3D> acceptedPoints = ReportPoints.Where(iter => iter.Status == TePointStatus.Accepted); if (acceptedPoints.Count() > 0) { IEnumerable <Double> differences = acceptedPoints.Select(iter => iter.Difference); m_AvgDifference = Math.Round(differences.Average(), 2); m_Sigma = (Single)Math.Round(TcMathUtil.StDev(differences, m_AvgDifference), 2); Single diff = 0.0f; foreach (TcReportPoint3D point in acceptedPoints) { diff = (Single)Math.Round(Math.Abs(point.Difference - m_AvgDifference), 2); if (diff > prmSigma * m_Sigma) { point.Status = TePointStatus.OutOfSigma; pointsRemoved++; } } } } while (pointsRemoved != 0); }
public void CalculateReportPoints(Single prmZAdj) { Samples = 0; ReportPoints = new TcReportPoint3D[HeightPointCount]; var j = 0; foreach (var gcp in HeightPoints) { //no xy adjustments var subject = new TcReportPoint3D(gcp.X - m_XAdjustment, gcp.Y - m_YAjustment, gcp.Z); var lidarNear = Tree.NearestNeighbours(subject, Program.options.Radius); //nearby lidar if (lidarNear.Count > 0) { subject.LidarHeight = (float)Math.Round((float)lidarNear.Average(i => i.Z), 2); Samples++; //filter out bad quality points. if (subject.Difference > c_QATolerance) { subject.Status = TePointStatus.BadQuality; } else { subject.Status = TePointStatus.Accepted; } } else { subject.Status = TePointStatus.NotCovered; } ReportPoints[j] = new TcReportPoint3D(m_Heights[j], subject.LidarHeight, prmZAdj, subject.Status) { Id = j }; j++; } // Update the average. List <Double> acceptedPoints = ReportPoints.Where(iter => iter.Status == TePointStatus.Accepted).Select(iter => iter.Difference).ToList(); if (acceptedPoints.Count > 0) { m_AvgDifference = Math.Round(acceptedPoints.Average(), 2); m_Sigma = (Single)Math.Round(TcMathUtil.StDev(acceptedPoints, m_AvgDifference), 2); } FilterBySigma(3); }
//----------------------------------------------------------------------------- /// <summary> /// Function that update the grid with given points from a LAS tile block. /// </summary> /// <param name="prmObj">Gridding data object</param> /// <param name="prmInfo">Information of the LAS block</param> /// <param name="prmPoints">Collection of LAS points</param> private void UpdateGrid(TcGridObject prmObj, TcTileBlockInfo prmInfo, TcLasPointBase[] prmPoints) { Dictionary <Int32, List <TcLasPointBase> > gridPointCollection = new Dictionary <Int32, List <TcLasPointBase> >(prmObj.GridCount * prmObj.GridCount); Int32 row, col, index; Int32[] rowCol = new Int32[2]; //Boolean[] availableIndices = new Boolean[(Int32)Math.Pow((Int32)(prmObj.Info.TileInfo.Row * prmObj.Info.TileInfo.Col * (prmObj.TileSize * 1.0 / prmObj.GridSize)), 2)]; Boolean[] availableIndices = new Boolean[prmObj.Info.TileInfo.Row * prmObj.GridCount * prmObj.Info.TileInfo.Col * prmObj.GridCount]; for (int i = 0; i < prmPoints.Length; i++) { rowCol = TcMathUtil.GetRowCol(prmPoints[i].X, prmPoints[i].Y, prmInfo.East, prmInfo.North, prmObj.GridSize, prmObj.GridSize); index = rowCol[1] * prmObj.GridCount + rowCol[0]; if (index < 0) { index = 0; } // Add that into the intermediate tile block. if (!availableIndices[index]) { gridPointCollection[index] = new List <TcLasPointBase>(); availableIndices[index] = true; } gridPointCollection[index].Add(prmPoints[i]); } Single height; Int32 subGridIndex; Int32 rowIndex; foreach (Int32 key in gridPointCollection.Keys) { row = key % prmObj.GridCount; col = (key - row) / prmObj.GridCount; height = (Single)GetGridHeight(gridPointCollection[key], prmObj.Type); // Save the point into the specific TOR block. rowIndex = prmInfo.Row * prmObj.GridCount + row; subGridIndex = (Int32)Math.Floor(rowIndex * 1.0 / prmObj.MaxRowsInGridBlock); prmObj.TorBlocks[subGridIndex].Points[rowIndex % prmObj.MaxRowsInGridBlock, prmInfo.Col *prmObj.GridCount + col] = height; // Update the min and max. if (height != TcConstants.TorNullValue32Bit) { prmObj.MinZ = Math.Min(prmObj.MinZ, height); prmObj.MaxZ = Math.Max(prmObj.MaxZ, height); } } }
//----------------------------------------------------------------------------- static public TcHistogram Get(IEnumerable <Double> prmData, Double prmScaling) { List <Single> filteredPoints = new List <Single>(); Single minZ = Single.MaxValue; Single maxZ = Single.MinValue; Double sum = 0.0; Int32 count = 0; foreach (Single height in prmData) { if (height != TcAtlassUtilGlobal.TorNullHeight) { count++; sum += height; minZ = Math.Min(minZ, height); maxZ = Math.Max(maxZ, height); filteredPoints.Add(height); } } if (count == 0) { return(null); } Single avg = (Single)Math.Round(sum / count, 2); Single stDev = (Single)Math.Round(TcMathUtil.StDev(filteredPoints, avg), 2); Int32 min = (Int32)Math.Round((minZ - avg) * prmScaling); Int32 max = (Int32)Math.Round((maxZ - avg) * prmScaling); Int32[] steps = Enumerable.Range(min, max - min + 1).ToArray(); Dictionary <Single, Int32> histogram = new Dictionary <Single, Int32>(); for (int i = 0; i < steps.Length; i++) { histogram.Add(steps[i], 0); } for (int i = 0; i < count; i++) { var key = (Single)Math.Round((filteredPoints[i] - avg) * prmScaling); if (histogram.ContainsKey(key)) { histogram[key]++; } } return(new TcHistogram(avg, stDev, histogram.Keys.ToList(), histogram.Values.ToList())); }
//----------------------------------------------------------------------------- public Double GetLevellingGridHeight(List <TcLasPointBase> prmPoints) { // When there is no point. if (prmPoints.Count == 0) { return(TcConstants.TorNullValue32Bit); } // When there is less than 2 points with last echo. List <Double> heights = new List <Double>(); Double maxHeight = Double.MinValue; Double minHeight = Double.MaxValue; for (int i = 0; i < prmPoints.Count; i++) { if (prmPoints[i].ReturnNumber == prmPoints[i].NumberOfReturns) { heights.Add(prmPoints[i].Z); maxHeight = Math.Max(maxHeight, prmPoints[i].Z); minHeight = Math.Min(minHeight, prmPoints[i].Z); } } if (heights.Count <= 2 || (maxHeight - minHeight > TcConstants.MaxToleranceForFlatPoints)) { return(TcConstants.TorNullValue32Bit); } // Sort the heights. //TcSort.Quicksort(heights, 0, heights.Count - 1); Double avg = TcMathUtil.Average(heights); Double stDev = TcMathUtil.StDev(heights, avg); Int32 count = 0; Double sum = 0.0; // Get points inside 2 sigma boundary. for (int i = 0; i < heights.Count; i++) { if (Math.Abs(heights[i] - avg) < 2 * stDev) { sum += heights[i]; count++; } } return(count > 0 ? sum / count : TcConstants.TorNullValue32Bit); }
//----------------------------------------------------------------------------- public void Tile(String prmInput, String prmOutput) { // Variables to be used inside the big loop. LasPoint2 point; // Int32 east, north, col, row; Int32 tileOffset = 0; Int32 index = -1; Int32 pointsProcessed = 0; using (TcLasReader reader = new TcLasReader(prmInput)) { LasHeader header = reader.GetHeaderOld(); UpdateTileCounts(header, m_TileSize); String blockFile = String.Format(@"{0}\{1}.xml", Path.GetDirectoryName(prmOutput), Path.GetFileNameWithoutExtension(prmOutput)); if (File.Exists(blockFile)) { File.Delete(blockFile); } using (TcLasWriter writer = new TcLasWriter(prmOutput)) { header.MinX = m_RevisedEast; header.MaxY = m_RevisedNorth; writer.WriteHeader(header); Int32 onePercent = header.NumberOfPointRecords / 100; for (int i = 0; i < header.NumberOfPointRecords; i++) { point = reader.ReadPoint(header); if (point.X <= 0 || point.Y <= 0) { continue; } // Calculate the tile index for the point. tileOffset = m_TileSize * m_Factor; /* * east = Convert.ToInt32(point.X - (point.X % tileOffset)); * north = Convert.ToInt32(point.Y - (point.Y % tileOffset)) + tileOffset; * col = (east - m_RevisedEast) / tileOffset; * row = (m_RevisedNorth - north) / tileOffset; */ Int32[] rowCol = TcMathUtil.GetRowCol(point.X, point.Y, m_RevisedEast, m_RevisedNorth, tileOffset, tileOffset); index = rowCol[1] * m_TileRows + rowCol[0]; // Add that into the intermediate tile block. if (!m_TileBlocks.ContainsKey(index)) { m_TileBlocks[index] = new LasPoint2[m_TileBlockSize]; m_BlockPointCount[index] = 0; } m_TileBlocks[index][m_BlockPointCount[index]] = point; m_BlockPointCount[index]++; // When a tile block is full, write into file and remove the points. if (m_BlockPointCount[index] == m_TileBlockSize) { writer.WritePoints(m_TileBlocks[index], header, m_TileBlockSize); ProcessTileBlock(rowCol[0], rowCol[1], index, pointsProcessed); pointsProcessed += m_TileBlockSize; } if (i % onePercent == 0) { NotifyTileProgress(prmInput, prmOutput, rowCol[0], rowCol[1], pointsProcessed, i / onePercent); } } // Process the remaining blocks with incomplete size. int row, col; foreach (Int32 idx in m_TileBlocks.Keys.ToList()) { row = idx % m_TileRows; col = (idx - row) / m_TileRows; writer.WritePoints(m_TileBlocks[idx], header, m_BlockPointCount[idx]); ProcessTileBlock(row, col, idx, pointsProcessed); pointsProcessed += m_BlockPointCount[idx]; } TcTileUtils.SaveTileBlocks(m_TileBlockInfoCollection, blockFile); } } }
static void Main(string[] args) { options = new Options(); if (CommandLine.Parser.Default.ParseArguments(args, options)) { factor = options.Factor; TS = options.GridSize; var fs = Stopwatch.StartNew(); string input = options.InputFile; if (string.IsNullOrEmpty(options.OutputFile)) { if (options.OutputDir != string.Empty) { options.OutputFile = new FileInfo(options.InputFile).Directory.FullName; options.OutputFile = Path.Combine(options.OutputDir, Path.GetFileNameWithoutExtension(options.InputFile) + ".xyz"); options.LogFile = Path.Combine(options.OutputDir, Path.GetFileNameWithoutExtension(options.InputFile) + ".txt"); } } if (!new FileInfo(options.OutputFile).Directory.Exists) { new FileInfo(options.OutputFile).Directory.Create(); } #region Title ASCII Console.ForegroundColor = ConsoleColor.Green; RConsole.Write(@" db 88888 8 db .d88b. .d88b. dPYb 8 8 dPYb YPwww. YPwww. dPwwYb 8 8 dPwwYb d8 d8 dP Yb 8 8888 dP Yb `Y88P' `Y88P' 888b. 8888 888b. .d88b. 888b. 88888 8 .8 8www 8 .8 8P Y8 8 .8 8 8wwK' 8 8wwP' 8b d8 8wwK' 8 8 Yb 8888 8 `Y88P' 8 Yb 8 888b. 8 db 8b 8 8b 8 8888 888b. 8 .8 8 dPYb 8Ybm8 8Ybm8 8www 8 .8 8wwP' 8 dPwwYb 8 8 8 8 8wwK 8 8888 dP Yb 8 8 8 8 8888 8 Yb "); Console.ForegroundColor = ConsoleColor.White; #endregion #region ASCII Parameter Table Console.ForegroundColor = ConsoleColor.Magenta; RConsole.WriteLine(" Version: Test Build 0.0.1"); Console.ForegroundColor = ConsoleColor.White; RConsole.WriteLine(" --------------------------------------- "); RConsole.WriteLine(""); RConsole.Write(@" ....................... : Parameter : Value : :...........:.........: : Scale : {0:00} : : Grid Size : {1:00} : :...........:.........: ", factor, TS); RConsole.WriteLine(""); #endregion #region ASCII I/O Table RConsole.WriteLine(@" +--------+---------------------------------------------------------------------+ | Param | Values | +--------+---------------------------------------------------------------------+ | Input | {0, -43} | | Output | {1, -43} | | Log | {2, -43} | +--------+---------------------------------------------------------------------+ ", Path.GetFileName(options.InputFile), options.OutputFile, Path.GetFileName(options.LogFile)); #endregion if (!File.Exists(input)) { RConsole.WriteLine("IO Error: input {0} file does not exist.", input); return; } RConsole.WriteLine("Job Started {0} - {1}", Path.GetFileNameWithoutExtension(input), DateTime.Now.ToString()); try { #region LAS READER / PRE GRID using (var readerobj = new TcLasReader(input)) { var s = Stopwatch.StartNew(); RConsole.WriteLine("Reading {0} Points", readerobj.TotalPoints); var points = readerobj.ReadPoints(readerobj.TotalPoints, readerobj.Header); s.Stop(); RConsole.WriteLine("Reading {0} Points - Finished {1} secs", readerobj.TotalPoints, Math.Ceiling((double)s.ElapsedMilliseconds / 1000)); var set = points.GetEnumerator(); #region gridding s = Stopwatch.StartNew(); var minX = readerobj.Header.MinX; var minY = readerobj.Header.MinY; var maxX = readerobj.Header.MaxX; var maxY = readerobj.Header.MaxY; int X0 = (int)(minX - (minX % (TS * factor))); int Y0 = (int)(minY - (minY % (TS * factor))); int X1 = (int)(maxX - (maxX % (TS * factor))); int Y1 = (int)(maxY - (maxY % (TS * factor))); double dX = X1 - X0; double dY = Y1 - Y0; dX /= TS * factor; dY /= TS * factor; var tiles_x = (int)dX; var tiles_y = (int)dY; preMem = GC.GetTotalMemory(true); Tiles = new Tile[tiles_x, tiles_y]; postMem = GC.GetTotalMemory(true); calMem = ToReadableMemUnit((int)Math.Ceiling((double)postMem % preMem)); RConsole.WriteLine("Gridding Data Into Tiles {0}/{1} {2}", tiles_x, tiles_y, "- Memory Used: " + calMem); preMem = GC.GetTotalMemory(true); int reportStep = 0; int pointsProcessed = 0; int interval = points.Length > 1000000 ? 1000000 : points.Length > 100000 ? 10000 : points.Length > 10000 ? 10000 : points.Length > 1000 ? 1000 : points.Length > 100 ? 100 : points.Length > 10 ? 10 : 10; while (set.MoveNext()) { pointsProcessed++; if (reportStep++ % interval == 0) { var percent = Clamp((int)Math.Ceiling( (double)pointsProcessed * 100 / points.Length), 0, 100); } var point = (TcLasPointBase)set.Current; if (point.ReturnNumber != point.NumberOfReturns) { continue; } var x = Math.Round(point.X, 2); var y = Math.Round(point.Y, 2); var z = Math.Round(point.Z, 2); var X = (int)(x - (x % (TS * factor))); var Y = (int)(y - (y % (TS * factor))); var J = (int)(X - minX) / (TS * factor); var I = (int)(Y - minY) / (TS * factor); options.Buffer = Clamp(options.Buffer, 1, 20); J = Clamp(J, 0, tiles_x - options.Buffer); I = Clamp(I, 0, tiles_y - options.Buffer); if (Tiles[J, I] == null) { Tiles[J, I] = new Tile { East = J, North = I, }; Tiles[J, I].XVertices.Add(x); Tiles[J, I].YVertices.Add(y); Tiles[J, I].ZVertices.Add(z); } else { Tiles[J, I].XVertices.Add(x); Tiles[J, I].YVertices.Add(y); Tiles[J, I].ZVertices.Add(z); } } s.Stop(); postMem = GC.GetTotalMemory(true); calMem = ToReadableMemUnit((int)Math.Ceiling((double)postMem % preMem)); RConsole.WriteLine("Gridded Data Into {0} Tiles - Finished {1} secs - Memory Used: {2}", true, Tiles.Length, Math.Ceiling((double)s.ElapsedMilliseconds / 1000) , calMem); #endregion } #endregion } catch (Exception error) { RConsole.WriteLine("Error Las Reader / Pre Gridder\n {0}\n{1}\n{2}", error.StackTrace, error.Source, error.Message); return; } finally { fs.Stop(); RConsole.WriteLine("Job Completed - {0} secs - {1}", Math.Ceiling((double)fs.ElapsedMilliseconds / 1000), DateTime.Now.ToString()); } try { #region Extracting Planars GC.Collect(); GC.SuppressFinalize(Tiles); preMem = GC.GetTotalMemory(true); calMem = ToReadableMemUnit((int)Math.Ceiling((double)postMem % preMem)); RConsole.WriteLine("{0} Memory Truncated. ", true, calMem); preMem = GC.GetTotalMemory(true); RConsole.WriteLine("{0}", true, "Detecting Planar Surfaces"); var sw = Stopwatch.StartNew(); if (Tiles.GetLength(0) == 0 || Tiles.GetLength(1) == 0) { return; } var width = Tiles.GetLength(0); var height = Tiles.GetLength(1); var processed = 0; var tinterval = height > 100 ? 100 : 10; var removed = 0; var sigmas = new List <double>(); var hvalues = new List <double>(); var hinterval = 3; var tilesprocessed = 0; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { if (Tiles[i, j] != null) { var tile = Tiles[i, j]; var heights = new List <Double>(); var maxHeight = Double.MinValue; var minHeight = Double.MaxValue; foreach (var h in tile.ZVertices) { heights.Add(h); maxHeight = Math.Max(maxHeight, h); minHeight = Math.Min(minHeight, h); } //filter out flat planars above .20cm tolerance. if (heights.Count <= 2 || (maxHeight - minHeight > 0.20f)) { Tiles[i, j] = null; continue; } var avg = TcMathUtil.Average(heights); var stDev = TcMathUtil.StDev(heights, avg); var count = 0; var sum = 0.0; var indices = new List <double>(); for (int p = 0; p < heights.Count; p++) { if (Math.Abs(heights[p] - avg) < 2 * stDev) { sum += heights[p]; count++; } else { indices.Add(heights[p]); } } var result = count > 0 ? sum / count : TcConstants.TorNullValue32Bit; int k = 0; while (k < tile.ZVertices.Count) { if (!indices.Contains(Tiles[i, j].ZVertices[k]) && result != TcConstants.TorNullValue32Bit) { Tiles[i, j].ZVertices[k] = result; } else { Tiles[i, j].XVertices.RemoveAt(k); Tiles[i, j].YVertices.RemoveAt(k); Tiles[i, j].ZVertices.RemoveAt(k); removed++; } k++; } } } if (processed++ % tinterval == 0) { var percent = Clamp( (int)Math.Ceiling((double)processed * 100 / height), 0, 100); } if (tilesprocessed++ % hinterval == 0 && sigmas.Count > 0) { hvalues = new List <double>(); sigmas = new List <double>(); } } preMem = GC.GetTotalMemory(true); calMem = ToReadableMemUnit((int)Math.Ceiling((double)postMem % preMem)); RConsole.WriteLine("Non-Flat Points Removed From Data: {0}", removed); RConsole.WriteLine("{0}", true, "Permuting Flat Points - Finished " + Math.Ceiling((double)sw.ElapsedMilliseconds / 1000) + " secs - Memory Used: " + calMem); GC.Collect(); GC.SuppressFinalize(Tiles); postMem = GC.GetTotalMemory(true); calMem = ToReadableMemUnit((int)Math.Ceiling((double)postMem % preMem)); RConsole.WriteLine("{0} Memory Truncated. ", true, calMem); preMem = GC.GetTotalMemory(true); RConsole.WriteLine("{0}", true, "Saving Planar Surfaces to " + options.OutputFile); sw = Stopwatch.StartNew(); using (var sr = File.CreateText(options.OutputFile)) { processed = 0; tinterval = height > 100 ? 100 : 10; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { if (Tiles[i, j] != null) { var tile = Tiles[i, j]; for (int p = 0; p < tile.XVertices.Count; p++) { sr.WriteLine("{0:000000.00} {1:000000.00} {2:000.00}", tile.XVertices[p], tile.YVertices[p], tile.ZVertices[p]); } } } if (processed++ % tinterval == 0) { var percent = Clamp( (int)Math.Ceiling((double)processed * 100 / height), 0, 100); } } } sw.Stop(); preMem = GC.GetTotalMemory(true); calMem = ToReadableMemUnit((int)Math.Ceiling((double)postMem % preMem)); RConsole.WriteLine("Saved permuted flat points - Finished {1} secs - Memory Used: {2}", true, Tiles.Length, Math.Ceiling((double)sw.ElapsedMilliseconds / 1000) , calMem); preMem = GC.GetTotalMemory(true); GC.Collect(); GC.SuppressFinalize(Tiles); postMem = GC.GetTotalMemory(true); calMem = ToReadableMemUnit((int)Math.Ceiling((double)postMem % preMem)); RConsole.WriteLine("{0} Memory Truncated. ", true, calMem); #endregion } catch (Exception error) { RConsole.WriteLine("Error Flattening\n {0}\n{1}\n{2}", error.StackTrace, error.Source, error.Message); return; } finally { fs.Stop(); RConsole.WriteLine("Job Completed - {0} secs - {1}", Math.Ceiling((double)fs.ElapsedMilliseconds / 1000), DateTime.Now.ToString()); } } else { options.GetUsage(); } }
//----------------------------------------------------------------------------- private void ProcessTiles <T>(TcLasReader prmReader, String prmOutput) where T : TiLasPoint { // Variables to be used inside the big loop. Int32 tileOffset = 0; Int32 index = -1; Int32 pointsProcessed = 0; // Key: Index of the Tile, Value: Array of 1000 points. Dictionary <Int32, T[]> m_TileBlocks = new Dictionary <Int32, T[]>(); TiLasHeader newHeader = UpdateTileCounts <T>(prmReader.Header, TileSize); Byte[] offsetBytes = prmReader.OffsetBytes; String blockFile = String.Format(@"{0}\{1}.xml", Path.GetDirectoryName(prmOutput), Path.GetFileNameWithoutExtension(prmOutput)); if (File.Exists(blockFile)) { File.Delete(blockFile); } using (TcLasWriter writer = new TcLasWriter(prmOutput) { MinClampZ = MinClampZ, MaxClampZ = MaxClampZ, /* Added By Dean */ ZAdjustment = this.ZAdjustment, XAdjustment = this.XAdjustment, YAdjustment = this.YAdjustment }) { writer.WriteHeader(newHeader, offsetBytes); Int64 numberOfPointRecords = GetNumberOfPoints(prmReader.Header); Int32 onePercent = (Int32)numberOfPointRecords / 100; Int32[] rowCol = new Int32[2]; DateTime now = DateTime.Now; Boolean[] availIndices = new Boolean[m_TileBlockInfoCollection.TileInfo.Row * m_TileBlockInfoCollection.TileInfo.Col]; Double x, y; Double z = 0; // Added Z Property - Dean Int64 noOfPointsLoaded = 0; Int64 noOfPointsToRead = 0; while (noOfPointsLoaded < numberOfPointRecords) { noOfPointsToRead = Math.Min(TcConstants.MaxLasPointsToProcessAtOnce, numberOfPointRecords - noOfPointsLoaded); T[] loadedPoints = prmReader.ReadPoints <T>(noOfPointsToRead); noOfPointsLoaded += noOfPointsToRead; for (int i = 0; i < noOfPointsToRead; i++) { x = loadedPoints[i].X * newHeader.XScaleFactor + newHeader.XOffset + XAdjustment; y = loadedPoints[i].Y * newHeader.YScaleFactor + newHeader.YOffset + YAdjustment; //added by dean z = loadedPoints[i].Z * newHeader.ZScaleFactor + newHeader.ZOffset + ZAdjustment; if (x <= 0 || y <= 0) { continue; } // Calculate the tile index for the point. tileOffset = TileSize * Factor; rowCol = TcMathUtil.GetRowCol(x, y, m_RevisedEast, m_RevisedNorth, tileOffset, tileOffset); index = rowCol[1] * m_TileRows + rowCol[0]; if (!availIndices[index]) { m_TileBlocks[index] = new T[PointBlockSize]; m_BlockPointCount[index] = 0; availIndices[index] = true; } // Convert the int XY back with adjusted values. loadedPoints[i].X = (Int32)((x - newHeader.XOffset) / newHeader.XScaleFactor); loadedPoints[i].Y = (Int32)((y - newHeader.YOffset) / newHeader.YScaleFactor); loadedPoints[i].Z = (Int32)((z - newHeader.ZOffset) / newHeader.ZScaleFactor); m_TileBlocks[index][m_BlockPointCount[index]] = loadedPoints[i]; m_BlockPointCount[index]++; // When a tile block is full, write into file and remove the points. if (m_BlockPointCount[index] == PointBlockSize) { // writer.WritePoints<T>(m_TileBlocks[index], PointBlockSize); writer.WritePointsWithOptions <T>(m_TileBlocks[index], ref newHeader, PointBlockSize); ProcessTileBlock <T>(m_TileBlocks, rowCol[0], rowCol[1], index, pointsProcessed); pointsProcessed += PointBlockSize; availIndices[index] = false; } } } // Process the remaining blocks with incomplete size. int row, col; foreach (Int32 idx in m_TileBlocks.Keys.ToList()) { row = idx % m_TileRows; col = (idx - row) / m_TileRows; writer.WritePointsWithOptions <T>(m_TileBlocks[idx], ref newHeader, m_BlockPointCount[idx]); ProcessTileBlock <T>(m_TileBlocks, row, col, idx, pointsProcessed); pointsProcessed += m_BlockPointCount[idx]; } // Write the updated header. writer.WriteHeader(newHeader); TcTileUtils.SaveTileBlocks(m_TileBlockInfoCollection, blockFile); } }