private PointCloudFrame ParsePointCloudFrame(string fileName)
    {
        List <CsvFrameEntity> records;

        using (StreamReader reader = new StreamReader(fileName))
        {
            using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
            {
                records = csv.GetRecords <CsvFrameEntity>().ToList();
            }
        }

        FloatPoint[] positionFrames = new FloatPoint[records.Count];

        for (int i = 0; i < positionFrames.Length; i++)
        {
            var record = records[i];
            positionFrames[i] = new FloatPoint()
            {
                X = record.X, Y = record.Z, Z = record.Y
            };
        }

        PointCloudFrame pointCloudFrame = new PointCloudFrame();

        pointCloudFrame.Points    = positionFrames;
        pointCloudFrame.Timestamp = records.First().Timestamp;
        return(pointCloudFrame);
    }
    private void LoadFrame(PointCloudFrame frame, float time)
    {
        Vector3[] vertices = new Vector3[frame.Points.Length];
        Color[]   colors   = new Color[frame.Points.Length];
        for (int i = 0; i < frame.Points.Length; i++)
        {
            vertices[i] = frame.Points[i].ToVector();
            colors[i]   = Color.Lerp(Color.green, Color.blue, vertices[i].y / gradientRange);
        }
        SetPoints(vertices, colors);

        float splineTime = driveData.PositionFrames.GetSplineTimeAtNormalizedTime(time);

        particleSystem.transform.localRotation = Quaternion.LookRotation(splineBuilder.GetVelocityAtTime(splineTime));
    }