csharp/ABTSoftware/SciChart.Wpf.Examples/Sandbox/CustomerExamples/Lidar3DPointCloudDemo/AscReader.cs

AscReader.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Media;
using SciChart.Charting3D.Model;
using SciChart.Core.Extensions;

namespace Lidar3DPointCloudDemo
{
    public struct AscData
    {
        public List XValues { get; set; }
        public List YValues { get; set; }
        public List ZValues { get; set; }
        public List ColorValues { get; set; }
        public int CellSize { get; set; }
        public int XllCorner { get; set; }
        public int YllCorner { get; set; }
        public int NumberColumns { get; set; }
        public int NumberRows { get; set; }
        public int NoDataValue { get; set; }
    }
    public clast AscReader
    {
        public static async Task ReadFileToAscData(
            string filename, Func colorMapFunction, Action reportProgress = null)
        {
            AscData result = new AscData()
            {
                XValues = new List(),
                YValues = new List(),
                ZValues = new List(),
                ColorValues = new List(),
            };

            await Task.Run(() =>
            {
                using (var file = File.OpenText(filename))
                {
                    // Load the ASC file format 
                    result.NumberColumns = ReadInt(file, "ncols");
                    result.NumberRows = ReadInt(file, "nrows");
                    result.XllCorner = ReadInt(file, "xllcorner");
                    result.YllCorner = ReadInt(file, "yllcorner");
                    result.CellSize = ReadInt(file, "cellsize");
                    result.NoDataValue = ReadInt(file, "NODATA_value");

                    // Generate X-values based off cell position 
                    float[] xValuesRow = Enumerable.Range(0, result.NumberColumns).Select(x => (float)x * result.CellSize).ToArray();

                    for (int i = 0; i < result.NumberRows; i++)
                    {
                        // Read heights from the ASC file and generate Z-cell values
                        float[] heightValuesRow = ReadFloats(file, " ", result.NoDataValue);
                        float[] zValuesRow = Enumerable.Repeat(0 + i * result.CellSize, result.NumberRows).Select(x => (float)x).ToArray();

                        result.XValues.AddRange(xValuesRow);
                        result.YValues.AddRange(heightValuesRow);
                        result.ZValues.AddRange(zValuesRow);

                        if (colorMapFunction != null)
                        {
                            // Optional color-mapping of points based on height 
                            Color[] colorValuesRow = heightValuesRow
                                .Select(colorMapFunction)
                                .ToArray();
                            result.ColorValues.AddRange(colorValuesRow);
                        }

                        // Optional report loading progress 0-100%
                        reportProgress?.Invoke((int)(100.0f * i / result.NumberRows));
                    }
                }
            });

            return result;
        }

        public static async Task ParseToXyzDataSeries(AscData lidarData, string identifier)
        {
            var xyzDataSeries3D = new XyzDataSeries3D() { SeriesName = identifier };

            await Task.Run(() =>
            {
                if (lidarData.ColorValues.IsNullOrEmpty())
                {
                    xyzDataSeries3D.Append(lidarData.XValues, lidarData.YValues, lidarData.ZValues);
                }
                else
                {
                    xyzDataSeries3D.Append(lidarData.XValues, lidarData.YValues, lidarData.ZValues, lidarData.ColorValues.Select(x => new PointMetadata3D(x)));
                }
            });

            return xyzDataSeries3D;
        }

        public static async Task ParseToGridDataSeries(AscData lidarData, string identifier)
        {
            UniformGridDataSeries3D uniformGridDataSeries = null;

            await Task.Run(() =>
            {
                uniformGridDataSeries = new UniformGridDataSeries3D(lidarData.NumberColumns, lidarData.NumberRows);
                uniformGridDataSeries.SeriesName = identifier;
                uniformGridDataSeries.StartX = 0;
                uniformGridDataSeries.StepX = lidarData.CellSize;
                uniformGridDataSeries.StartZ = 0;
                uniformGridDataSeries.StepZ = lidarData.CellSize;

                int index = 0;
                for (int z = 0; z < lidarData.NumberRows; z++)
                {
                    for (int x = 0; x < lidarData.NumberColumns; x++)
                    {
                        uniformGridDataSeries.InternalArray[z][x] = lidarData.YValues[index++];
                    }
                }
            });

            return uniformGridDataSeries;
        }

        private static int ReadInt(StreamReader file, string prefix)
        {
            string line = file.ReadLine();
            line = line.Replace(prefix, "").Trim();
            return int.Parse(line, CultureInfo.InvariantCulture);
        }

        private static float[] ReadFloats(StreamReader file, string separator, float noDataValue)
        {
            string line = file.ReadLine();

            float[] values = line.Split(new[] {separator}, StringSplitOptions.RemoveEmptyEntries)
                .Select(x =>
                {
                    float rawValue = float.Parse(x, CultureInfo.InvariantCulture);
                    return rawValue.CompareTo(noDataValue) == 0 ? float.NaN : rawValue;

                } ).ToArray();

            return values;
        }
    }
}