//----------------------------------------------------------------------------- /// <summary> /// Calculates the size of the canvas and determine the number of required tiles. /// It then creates polygons (rectangle) for each area considering the given offset. /// </summary> /// <param name="prmFiles">List of LAS files to be processed</param> private void UpdateCommonHeader(IEnumerable <String> prmFiles) { m_AreaHeader = GetDefaultLasHeader(); foreach (String lasFile in prmFiles) { using (TcLasReader lasReader = new TcLasReader(lasFile)) { m_AreaHeader.MinX = Math.Min(m_AreaHeader.MinX, lasReader.Header.MinX); m_AreaHeader.MinY = Math.Min(m_AreaHeader.MinY, lasReader.Header.MinY); m_AreaHeader.MinZ = Math.Min(m_AreaHeader.MinZ, lasReader.Header.MinZ); m_AreaHeader.MaxX = Math.Max(m_AreaHeader.MaxX, lasReader.Header.MaxX); m_AreaHeader.MaxY = Math.Max(m_AreaHeader.MaxY, lasReader.Header.MaxY); m_AreaHeader.MaxZ = Math.Max(m_AreaHeader.MaxZ, lasReader.Header.MaxZ); m_AreaHeader.XOffset = Math.Min(m_AreaHeader.XOffset, lasReader.Header.XOffset); m_AreaHeader.YOffset = Math.Min(m_AreaHeader.YOffset, lasReader.Header.YOffset); m_AreaHeader.ZOffset = Math.Min(m_AreaHeader.ZOffset, lasReader.Header.ZOffset); m_AreaHeader.XScaleFactor = Math.Min(m_AreaHeader.XScaleFactor, lasReader.Header.XScaleFactor); m_AreaHeader.YScaleFactor = Math.Min(m_AreaHeader.YScaleFactor, lasReader.Header.YScaleFactor); m_AreaHeader.ZScaleFactor = Math.Min(m_AreaHeader.ZScaleFactor, lasReader.Header.ZScaleFactor); m_TileInfos[lasFile] = new TcIndexedLasInfo(lasFile) { Header = lasReader.Header }; } } }
//----------------------------------------------------------------------------- public LasPoint2[] GetPointsByTile(String prmInput, Int32 prmRow, Int32 prmCol) { String blockFile = String.Format(@"{0}\{1}.xml", Path.GetDirectoryName(prmInput), Path.GetFileNameWithoutExtension(prmInput)); TcTileBlockInfoCollection tileInfoCollection = TcTileUtils.GetTileBlocks(blockFile); IEnumerable <TcTileBlockInfo> blocks = tileInfoCollection.TileBlocks.Where(iter => iter.Row == prmRow && iter.Col == prmCol); Int32 numberOfPoints = blocks.Aggregate(0, (result, iter) => result += iter.NoOfPoints); using (TcLasReader reader = new TcLasReader(prmInput)) { LasHeader header = reader.GetHeaderOld(); LasPoint2[] points = new LasPoint2[numberOfPoints]; Int32 arrayStart = 0; foreach (TcTileBlockInfo info in blocks) { if (reader.GetLasBlock(ref points, arrayStart, info.StartPoint, info.NoOfPoints, header)) { arrayStart += info.NoOfPoints; } else { throw new Exception(String.Format("Couldn't read the las tile ({0},{1})", prmRow, prmCol)); } } return(points); } }
//----------------------------------------------------------------------------- public void Index(String prmInput, String prmOutput) { if (!File.Exists(prmInput)) { throw new FileNotFoundException("LAS file not found"); } using (TcLasReader reader = new TcLasReader(prmInput)) { switch (reader.Header.PointDataFormatID) { case 0: ProcessTiles <TsLasPoint0>(reader, prmOutput); break; case 1: ProcessTiles <TsLasPoint1>(reader, prmOutput); break; case 2: ProcessTiles <TsLasPoint2>(reader, prmOutput); break; case 3: ProcessTiles <TsLasPoint3>(reader, prmOutput); break; case 4: ProcessTiles <TsLasPoint4>(reader, prmOutput); break; case 5: ProcessTiles <TsLasPoint5>(reader, prmOutput); break; case 6: ProcessTiles <TsLasPoint6>(reader, prmOutput); break; case 7: ProcessTiles <TsLasPoint7>(reader, prmOutput); break; case 8: ProcessTiles <TsLasPoint8>(reader, prmOutput); break; case 9: ProcessTiles <TsLasPoint9>(reader, prmOutput); break; case 10: ProcessTiles <TsLasPoint10>(reader, prmOutput); break; default: throw new FormatException("Couldn't process the tile. LAS format not supported"); } } }
//----------------------------------------------------------------------------- public void LasToCls(String prmInput, Int64 prmOriginalNumberOfPoints, String prmOutputAcl, String prmOutputAcb) { try { // Process the LAS file. using (TcLasReader reader = new TcLasReader(prmInput)) { switch (reader.Header.PointDataFormatID) { case 1: LasToCls <TsLasPoint1>(reader, prmOriginalNumberOfPoints, prmOutputAcl, prmOutputAcb); break; case 3: LasToCls <TsLasPoint3>(reader, prmOriginalNumberOfPoints, prmOutputAcl, prmOutputAcb); break; case 4: LasToCls <TsLasPoint4>(reader, prmOriginalNumberOfPoints, prmOutputAcl, prmOutputAcb); break; case 5: LasToCls <TsLasPoint5>(reader, prmOriginalNumberOfPoints, prmOutputAcl, prmOutputAcb); break; case 6: LasToCls <TsLasPoint6>(reader, prmOriginalNumberOfPoints, prmOutputAcl, prmOutputAcb); break; case 7: LasToCls <TsLasPoint7>(reader, prmOriginalNumberOfPoints, prmOutputAcl, prmOutputAcb); break; case 8: LasToCls <TsLasPoint8>(reader, prmOriginalNumberOfPoints, prmOutputAcl, prmOutputAcb); break; case 9: LasToCls <TsLasPoint9>(reader, prmOriginalNumberOfPoints, prmOutputAcl, prmOutputAcb); break; case 10: LasToCls <TsLasPoint10>(reader, prmOriginalNumberOfPoints, prmOutputAcl, prmOutputAcb); break; default: throw new FormatException("Couldn't produce the file. LAS format not supported"); } } } catch (Exception ex) { ReportError("Could not construct Acl and Acb files from LAS", ex); } }
//----------------------------------------------------------------------------- public void ClsToLas(String prmOriginalLasFile, String prmAclFile, String prmAcbFile, String prmOutputLas) { try { using (TcLasReader lasReader = new TcLasReader(prmOriginalLasFile)) { switch (lasReader.Header.PointDataFormatID) { case 1: ClsToLas <TsLasPoint1>(lasReader, prmAclFile, prmAcbFile, prmOutputLas); break; case 3: ClsToLas <TsLasPoint3>(lasReader, prmAclFile, prmAcbFile, prmOutputLas); break; case 4: ClsToLas <TsLasPoint4>(lasReader, prmAclFile, prmAcbFile, prmOutputLas); break; case 5: ClsToLas <TsLasPoint5>(lasReader, prmAclFile, prmAcbFile, prmOutputLas); break; case 6: ClsToLas <TsLasPoint6>(lasReader, prmAclFile, prmAcbFile, prmOutputLas); break; case 7: ClsToLas <TsLasPoint7>(lasReader, prmAclFile, prmAcbFile, prmOutputLas); break; case 8: ClsToLas <TsLasPoint8>(lasReader, prmAclFile, prmAcbFile, prmOutputLas); break; case 9: ClsToLas <TsLasPoint9>(lasReader, prmAclFile, prmAcbFile, prmOutputLas); break; case 10: ClsToLas <TsLasPoint10>(lasReader, prmAclFile, prmAcbFile, prmOutputLas); break; default: throw new FormatException("Couldn't produce the file. LAS format not supported"); } } } catch (Exception ex) { ReportError("Could not reconstruct LAS from Acb and Acl files", ex); } }
//----------------------------------------------------------------------------- #region LasToCls - Converter function from LAS to Classification format private void LasToCls <T>(TcLasReader prmReader, String prmOutput) where T : TiLasPoint { m_Progress = 0; ReportMessage(String.Format("Processing {0}", Path.GetFileName(prmOutput))); using (TcClsWriter writer = new TcClsWriter(prmReader.Header, prmOutput)) { writer.WriteHeader(prmReader.OffsetBytes); Int64 numberOfPointRecords = prmReader.Header.GetNumberOfPoints(); Int64 noOfPointsLoaded = 0; Int64 noOfPointsToRead = 0; while (noOfPointsLoaded < numberOfPointRecords) { noOfPointsToRead = Math.Min(TcConstants.MaxLasPointsToProcessAtOnce, numberOfPointRecords - noOfPointsLoaded); writer.WritePoints <T>(prmReader.ReadPoints <T>(noOfPointsToRead)); noOfPointsLoaded += noOfPointsToRead; ReportProgress(noOfPointsLoaded, numberOfPointRecords); } } ReportMessage(String.Format("Finished {0}", Path.GetFileName(prmOutput))); }
//----------------------------------------------------------------------------- private void ClsToLas <T>(TcLasReader prmReader, String prmAclFile, String prmAcbFile, String prmOutputLas) where T : TiLasGPS { using (BinaryReader acbReader = new BinaryReader(new FileStream(prmAcbFile, FileMode.Open))) { Int64 totalPoints = acbReader.ReadInt64(); // When the binary file doesn't have enough points. if (totalPoints != (acbReader.BaseStream.Length - acbReader.BaseStream.Position)) { throw new InvalidDataException(String.Format("Length of data mismatched in {0} file", Path.GetFileName(prmAcbFile))); } // Check against the number of points in the original LAS files. if (totalPoints != prmReader.TotalPoints) { throw new InvalidDataException(String.Format("{0} file doesn't have save number of points as LAS", Path.GetFileName(prmAcbFile))); } using (TcLasWriter lasWriter = new TcLasWriter(prmOutputLas)) { Int64 noOfPointsToProcess = 0; Int64 noOfPointsProcessed = 0; T[] points = new T[TcConstants.MaxLasPointsToProcessAtOnce]; Byte[] clsData = acbReader.ReadBytes((Int32)totalPoints); // Write the header. lasWriter.WriteHeader(prmReader.Header, prmReader.OffsetBytes); while (noOfPointsProcessed < prmReader.TotalPoints) { // Calculate how many points to read. noOfPointsToProcess = Math.Min(TcConstants.MaxLasPointsToProcessAtOnce, prmReader.TotalPoints - noOfPointsProcessed); // Read a block of points from the LAS file. points = prmReader.ReadPoints <T>(noOfPointsToProcess); // Update the classification flag. for (int i = 0; i < noOfPointsToProcess; i++) { points[i].Classification = clsData[noOfPointsProcessed + i]; } lasWriter.WritePoints <T>(points); // Notify the progress to the caller thread. ReportProgress(noOfPointsProcessed, totalPoints); noOfPointsProcessed += noOfPointsToProcess; } // Process the extra points if there is any. if (!String.IsNullOrWhiteSpace(prmAclFile) && File.Exists(prmAclFile)) { using (TcClsReader clsReader = new TcClsReader(prmAclFile)) { TsClsLasPoint[] extraPoints = clsReader.ReadPoints(clsReader.TotalPoints); TiLasGPS[] extraLasPoints = new TiLasGPS[clsReader.TotalPoints]; for (int i = 0; i < clsReader.TotalPoints; i++) { extraLasPoints[i] = ClsToLasPoint(extraPoints[i], clsReader.Header.PointDataFormatID); // Point transformation as the offset and/or scaling factor might be changed in different software. extraLasPoints[i].X = (Int32)(((clsReader.Header.XOffset + extraLasPoints[i].X * clsReader.Header.XScaleFactor) - prmReader.Header.XOffset) / prmReader.Header.XScaleFactor); extraLasPoints[i].Y = (Int32)(((clsReader.Header.YOffset + extraLasPoints[i].Y * clsReader.Header.YScaleFactor) - prmReader.Header.YOffset) / prmReader.Header.YScaleFactor); extraLasPoints[i].Z = (Int32)(((clsReader.Header.ZOffset + extraLasPoints[i].Z * clsReader.Header.ZScaleFactor) - prmReader.Header.ZOffset) / prmReader.Header.ZScaleFactor); } lasWriter.WritePoints(extraLasPoints); // Write the updated header. lasWriter.WriteHeader(GetHeaderForMergedLas(prmReader.Header, clsReader.TotalPoints)); } } } } }
//----------------------------------------------------------------------------- private void LasToCls <T>(TcLasReader prmReader, Int64 prmOriginalNumberOfPoints, String prmOutputAcl, String prmOutputAcb) where T : TiLasGPS { ReportMessage(String.Format("Processing {0}", Path.GetFileName(prmOutputAcb))); ReportMessage("Reading all LAS points"); // Read all the points. T[] clsPoints = prmReader.ReadPoints <T>(prmReader.TotalPoints); ReportMessage("Sorting LAS points according to the GPS time"); // Sort the points according to the GPS time. new TcLasSort <T>().SortByGpsTime(clsPoints, 0, prmReader.TotalPoints - 1); Int64 pointsProcessed = 0; Byte[] clsData = new Byte[prmOriginalNumberOfPoints]; ReportMessage("Extracting the new points"); // Count the number of points with GPSTime ~ 0 (new point) Int32 exptCnt = 0; while (clsPoints[exptCnt].GPSTime < 1) { exptCnt++; } // Write the new points in .acl file. if (exptCnt > 0) { using (TcClsWriter clsWriter = new TcClsWriter(GetHeaderForCls(prmReader.Header, exptCnt), prmOutputAcl)) { clsWriter.WriteHeader(prmReader.OffsetBytes); clsWriter.WritePoints <T>(clsPoints.Take(exptCnt).ToArray()); } } pointsProcessed += exptCnt; // Counter for the original points. Int64 origPtCnt = 0; // Current expected GPS time to map the deleted points. Double expecteGPSTime = 1.0; ReportMessage("Processing original points"); while (pointsProcessed < clsPoints.Length && origPtCnt < prmOriginalNumberOfPoints) { // If deleted points have been detected. if (clsPoints[pointsProcessed].GPSTime != expecteGPSTime) { clsData[origPtCnt++] = 255; expecteGPSTime++; continue; } clsData[origPtCnt++] = clsPoints[pointsProcessed++].Classification; expecteGPSTime++; } ReportMessage("Writing the output classification files"); // Write into the stream. if (origPtCnt > 0) { using (BinaryWriter acbWriter = new BinaryWriter(new FileStream(prmOutputAcb, FileMode.Create))) { acbWriter.Write(origPtCnt); acbWriter.Write(clsData); } } ReportMessage(String.Format("Finished {0}", Path.GetFileName(prmOutputAcb))); }
//----------------------------------------------------------------------------- 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); } }
//----------------------------------------------------------------------------- public void LasToCls(String prmInput, String prmOutput) { try { if (!File.Exists(prmInput)) { throw new FileNotFoundException("LAS file not found"); } if (!Path.GetExtension(prmInput).Contains("las")) { throw new InvalidDataException("Invalid input file format"); } if (!Path.GetExtension(prmOutput).Contains(TcEnums.ShortName(m_Type))) { throw new InvalidDataException("Invalid output file format"); } using (TcLasReader reader = new TcLasReader(prmInput)) { switch (reader.Header.PointDataFormatID) { case 0: LasToCls <TsLasPoint0>(reader, prmOutput); break; case 1: LasToCls <TsLasPoint1>(reader, prmOutput); break; case 2: LasToCls <TsLasPoint2>(reader, prmOutput); break; case 3: LasToCls <TsLasPoint3>(reader, prmOutput); break; case 4: LasToCls <TsLasPoint4>(reader, prmOutput); break; case 5: LasToCls <TsLasPoint5>(reader, prmOutput); break; case 6: LasToCls <TsLasPoint6>(reader, prmOutput); break; case 7: LasToCls <TsLasPoint7>(reader, prmOutput); break; case 8: LasToCls <TsLasPoint8>(reader, prmOutput); break; case 9: LasToCls <TsLasPoint9>(reader, prmOutput); break; case 10: LasToCls <TsLasPoint10>(reader, prmOutput); break; default: throw new FormatException("Couldn't produce the file. LAS format not supported"); } } } catch (Exception ex) { ReportError("Failed to convert LAS file into Acl", ex); } }