Newer
Older
Correlator / Correlator / Util / MethodExtensions.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Correlator.Model;
using Correlator.SensorHubTag;
using HandyControl.Controls;
using MathWorks.MATLAB.NET.Arrays;
using Tag = Correlator.SensorHubTag.Tag;

namespace Correlator.Util
{
    public static class MethodExtensions
    {
        private const int HeaderSize = 44;

        private static FileStream CreateEmptyWaveHeader(this string filePath)
        {
            var fileStream = new FileStream(filePath, FileMode.OpenOrCreate);
            const byte emptyByte = new byte();

            for (var i = 0; i < HeaderSize; i++)
            {
                fileStream.WriteByte(emptyByte);
            }

            return fileStream;
        }

        public static void SaveWavFile(this string filePath, double[] dataArray, double[] dataArray1)
        {
            try
            {
                var fileStream = filePath.CreateEmptyWaveHeader();

                var bytesData = new byte[dataArray.Length * 16];

                for (var i = 0; i < dataArray.Length; i++)
                {
                    var byteArray16 = new byte[16];
                    BitConverter.GetBytes(dataArray[i]).CopyTo(byteArray16, 0);
                    BitConverter.GetBytes(dataArray1[i]).CopyTo(byteArray16, 8);
                    byteArray16.CopyTo(bytesData, i * 16);
                }

                fileStream.Write(bytesData, 0, bytesData.Length);
                fileStream.Flush();

                //重写头文件
                fileStream.WriteHeader(7500, 2);
            }
            catch (Exception e)
            {
                "MethodExtensions".WriteLog(e.Message);
            }
        }

        private static void WriteHeader(this FileStream fileStream, int hz, int channels)
        {
            //hz = 7500;//采样频率
            //channels = 1;//单声道为1,双声道为2
            //samples = 3750;//实际样本数

            try
            {
                fileStream.Seek(0, SeekOrigin.Begin);

                //资源交换文件标志(RIFF)
                var riff = Encoding.UTF8.GetBytes("RIFF"); //###
                fileStream.Write(riff, 0, 4);

                //从下个地址开始到文件尾的总字节数
                var chunkSize = BitConverter.GetBytes(fileStream.Length - 8); //###
                fileStream.Write(chunkSize, 0, 4);

                //WAV文件标志
                var wave = Encoding.UTF8.GetBytes("WAVE"); //###
                fileStream.Write(wave, 0, 4);

                //波形格式标志
                var fmt = Encoding.UTF8.GetBytes("fmt "); //###
                fileStream.Write(fmt, 0, 4);

                //过滤字节一般为00000010H,若为00000012H则说明数据头携带附加信息
                var subChunk1 = BitConverter.GetBytes(16); //###
                fileStream.Write(subChunk1, 0, 4);

                //格式种类值为1时表示数据为线性PCM编码
                var audioFormat = BitConverter.GetBytes((short)1); //###
                fileStream.Write(audioFormat, 0, 2);

                //通道数,单声道为1,双声道为2
                var numChannels = BitConverter.GetBytes((short)channels); //###
                fileStream.Write(numChannels, 0, 2);

                //采样频率 #
                var sampleRate = BitConverter.GetBytes(hz);
                fileStream.Write(sampleRate, 0, 4);

                //波形数据传输速率
                var byRate = BitConverter.GetBytes(hz * channels * 2 * 8 / 8);
                fileStream.Write(byRate, 0, 4);

                //data数据块长度,字节
                var blockAlign = (ushort)(channels * 8 * 2 / 8);
                fileStream.Write(BitConverter.GetBytes(blockAlign), 0, 2);

                //PCM位宽
                const ushort bps = 16;
                var bitsPerSample = BitConverter.GetBytes(bps);
                fileStream.Write(bitsPerSample, 0, 2);

                //数据标志符data
                var dataString = Encoding.UTF8.GetBytes("data");
                fileStream.Write(dataString, 0, 4);

                var samples = ((int)fileStream.Length - 44) / 16;
                //Data总数据长度,字节
                var subChunk2 = BitConverter.GetBytes(samples * channels * 2);
                fileStream.Write(subChunk2, 0, 4);

                fileStream.Close();
            }
            catch (Exception ex)
            {
                "MethodExtensions".WriteLog(ex.Message);
            }
        }

        /// <summary>
        /// Log本地化,并输出在Console,便于Debug
        /// </summary>
        /// <param name="className"></param>
        /// <param name="log"></param>
        public static void WriteLog(this string className, string log)
        {
            Console.WriteLine($@"{className} => {log}");
            LogHelper.Info(log);
        }

        /// <summary>
        /// 计算文件占用空间大小
        /// </summary>
        /// <param name="size"></param>
        /// <returns></returns>
        public static string FormatFileSize(this long size)
        {
            string fileSize;
            if (size == 0)
            {
                fileSize = "0B";
            }
            else if (size < 1024)
            {
                fileSize = $"{size:#.0}" + "B";
            }
            else if (size < 1048576)
            {
                fileSize = $"{(double)size / 1024:#.0}" + "K";
            }
            else if (size < 1073741824)
            {
                fileSize = $"{(double)size / 1048576:#.0}" + "M";
            }
            else
            {
                fileSize = $"{(double)size / 1073741824:#.0}" + "G";
            }

            return fileSize;
        }

        /// <summary>
        /// 字节数组转Int
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static int ConvertToInt(this byte[] bytes)
        {
            return bytes.Aggregate(0, (current, b) => 16 * 16 * current + b);
        }

        /// <summary>
        /// 字节数组转String
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        private static string ConvertToString(this byte[] bytes)
        {
            return bytes.Aggregate("", (current, t) => current + t.ToString("X2"));
        }

        /// <summary>
        /// 字符串转byte
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static byte ConvertToByte(this string str)
        {
            return byte.Parse(str, NumberStyles.HexNumber);
        }

        /// <summary>
        /// 字符串转BCD码
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static byte ConvertToBcdCode(this string str)
        {
            return (byte)(int.Parse(str.Substring(0, 1)) * 16 + int.Parse(str.Substring(1, 1)));
        }

        /// <summary>
        /// 字符串转byte[]
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static byte[] ConvertToByteArray(string str)
        {
            var ret = new byte[str.Length / 2];
            for (var i = 0; i < str.Length / 2; i++)
            {
                ret[i] = byte.Parse(str.Substring(i * 2, 2), NumberStyles.HexNumber);
            }

            return ret;
        }

        public static string AppendLeftZero(this int i)
        {
            //数据固定长度2
            return i.ToString("G").PadLeft(2, '0');
        }

        /// <summary>
        /// 转16进制字符串
        /// </summary>
        /// <param name="src"></param>
        /// <returns></returns>
        public static string ConvertToHexString(this string src)
        {
            if (src.Length == 4)
            {
                return src;
            }

            var temp = "";
            for (var i = 0; i < 4 - src.Length; i++)
            {
                temp += "0";
            }

            return temp + src;
        }

        /// <summary>
        /// 截屏
        /// </summary>
        /// <param name="filePath"></param>
        public static void SnapShot(this string filePath)
        {
            var width = Screen.PrimaryScreen.Bounds.Width;
            var height = Screen.PrimaryScreen.Bounds.Height;
            var memoryImage = new Bitmap(width, height);
            var memoryGraphics = Graphics.FromImage(memoryImage);
            memoryGraphics.CopyFromScreen(0, 0, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy);
            var data = new MemoryStream();
            memoryImage.Save(data, ImageFormat.Png);

            var fs = new FileStream(filePath, FileMode.OpenOrCreate);
            var w = new BinaryWriter(fs);
            w.Write(data.ToArray());
            fs.Close();
            data.Close();

            Growl.Success("快照已保存");
        }

        /// <summary>
        /// 字节数组转数据Tag集合
        /// </summary>
        /// <param name="tagBytes"></param>
        /// <returns></returns>
        public static List<Tag> GetTags(this byte[] tagBytes)
        {
            var tags = new List<Tag>();
            try
            {
                var i = 0;
                // var n = 0;
                while (i < tagBytes.Length)
                {
                    // n++;
                    var oidBytes = new byte[4];
                    Array.Copy(tagBytes, i, oidBytes, 0, 4);
                    var oid = oidBytes.ConvertToString();

                    //value域的长度
                    var tagValueBytes = new byte[2];
                    Array.Copy(tagBytes, i + 4, tagValueBytes, 0, 2);
                    Array.Reverse(tagValueBytes);
                    int tagValueLength = BitConverter.ToInt16(tagValueBytes, 0);
                    // Console.WriteLine($@"value域的长度 => {tagValueLength}");

                    var valueBytes = new byte[tagValueLength];
                    Array.Copy(tagBytes, i + 6, valueBytes, 0, tagValueLength);
                    // Console.WriteLine($@"第{n}个Tag => {BitConverter.ToString(valueBytes)}");

                    i = i + 6 + tagValueLength;
                    var tag = TagFactory.Create(oid, tagValueLength, valueBytes);
                    tags.Add(tag);
                }
            }
            catch (Exception e)
            {
                "MethodExtensions".WriteLog($"设备上传协议出错:{e.Message}");
            }

            return tags;
        }

        /// <summary>
        /// 通过Linq查找电量Tag
        /// </summary>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static CellTag GetCellTag(this List<Tag> tags)
        {
            return tags.Where(tag => tag is CellTag).Cast<CellTag>().FirstOrDefault();
        }

        /// <summary>
        /// 通过Linq查找状态Tag
        /// </summary>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static SensorExceptionTag GetSensorExceptionTag(this IEnumerable<Tag> tags)
        {
            return tags.Where(tag => tag is SensorExceptionTag).Cast<SensorExceptionTag>().FirstOrDefault();
        }

        /// <summary>
        /// 十六进制转double
        /// </summary>
        /// <param name="src"></param>
        /// <returns></returns>
        public static double HexToDouble(this IReadOnlyList<byte> src)
        {
            if (src.Count != 3)
                return 0;

            short result1 = src[0];
            short result2 = src[1];
            short result3 = src[2];

            if ((result1 & 0x80) == 0x80)
            {
                result1 = Convert.ToInt16(result1 - 255);
                result2 = Convert.ToInt16(result2 - 255);
                result3 = Convert.ToInt16(result3 - 255);
            }

            var data = (result1 * 65536 + result2 * 256 + result3) * 5 / 83.88607 / 100000;
            return data;
        }

        /// <summary>
        /// 通过Linq查找噪声Tag
        /// </summary>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static UploadTag GetUploadNoiseTag(this IEnumerable<Tag> tags)
        {
            return tags.Where(tag => tag is UploadTag).Cast<UploadTag>().FirstOrDefault();
        }

        /// <summary>
        /// MWNumericArray转double[]
        /// </summary>
        /// <param name="inputMw"></param>
        /// <returns></returns>
        public static double[] GetArray(this MWNumericArray inputMw)
        {
            var num = inputMw.NumberOfElements;
            var outArray = new double[num];
            for (var i = 0; i < num; i++)
            {
                outArray[i] = Convert.ToDouble(inputMw[i + 1].ToString());
            }

            return outArray;
        }

        /// <summary>
        /// 二进制转byte[]
        /// </summary>
        /// <param name="ints"></param>
        /// <returns></returns>
        public static byte[] ToByteArray(this List<int> ints)
        {
            var bitIndex = new List<byte>();
            for (var i = 1; i <= 64; i++)
            {
                bitIndex.Add(ints.Contains(i) ? (byte)0 : (byte)1);
            }

            //每八位为一个字节
            var tempBytes = new List<byte>();
            for (var i = 0; i < bitIndex.Count; i += 8)
            {
                var bytes = new List<byte>
                {
                    bitIndex[i],
                    bitIndex[i + 1],
                    bitIndex[i + 2],
                    bitIndex[i + 3],
                    bitIndex[i + 4],
                    bitIndex[i + 5],
                    bitIndex[i + 6],
                    bitIndex[i + 7]
                };
                var builder = new StringBuilder();
                foreach (var b in bytes)
                {
                    builder.Append(b);
                }

                var binary = builder.ToString();
                //二进制转十进制
                var decimalValue = Convert.ToInt32(binary, 2);
                //十进制转byte,0~255之间的int值才可以,否则需要先转为Hex,再由Hex转为byte[]
                tempBytes.Add(Convert.ToByte(decimalValue));
            }

            return tempBytes.ToArray();
        }

        /// <summary>
        /// 数据类型
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public static string ToChineseType(this int i)
        {
            //1,2,3,4分别代表流量、压力、液位、噪声
            switch (i)
            {
                case 1:
                    return "流量数据";
                case 2:
                    return "压力数据";
                case 3:
                    return "液位数据";
                case 4:
                    return "噪声数据";
                default:
                    return "未知类型数据";
            }
        }

        /// <summary>
        /// 二维集合转为一维数组
        /// </summary>
        /// <param name="doubleArrays">二维集合</param>
        /// <returns></returns>
        public static double[] ToOneDimensionalArray(this List<List<double>> doubleArrays)
        {
            var totalData = new List<double>();
            foreach (var item in doubleArrays)
            {
                totalData.AddRange(item);
            }

            return totalData.ToArray();
        }

        /// <summary>
        /// 保存传感器上传的原始数据
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="response"></param>
        public static void SaveSensorResponse(this string fileName, List<string> response)
        {
            var builder = new StringBuilder();
            for (var i = 0; i < response.Count; i++)
            {
                var str = response[i];
                if (i == response.Count - 1)
                {
                    builder.Append(str);
                }
                else
                {
                    builder.Append(str).Append("\r\n");
                }
            }

            File.AppendAllText(fileName, builder.ToString());
        }

        /// <summary>
        /// 每个音频数据
        /// </summary>
        private static string _perData;

        /// <summary>
        /// 保存听音上传的原始数据
        /// </summary>
        /// <param name="dataArray"></param>
        public static void SaveSoundData(this List<byte[]> dataArray)
        {
            using (var manager = new DataBaseManager())
            {
                var today = DateTime.Now.ToString("yyyyMMdd");
                var configModel = manager
                    .Table<CorrelatorConfigModel>()
                    .Where(x => x.Date == today)
                    .OrderBy(x => x.Date)
                    .LastOrDefault() ?? new CorrelatorConfigModel
                {
                    Date = today,
                    Pipe = 1,
                    LocateTimes = 1,
                    ListenTimes = 1
                };

                //如果配置里面的日期相同,则取配置里面的Pipe作为index,如果配置里面的日期不相同,则默认index=1
                var pipeIndex = configModel.Date.Equals(today) ? configModel.Pipe : 1;
                var listenDataDir = DirectoryManager.GetListenDir();

                var listenTimes = configModel.LocateTimes;
                var fileName = $"{listenDataDir}\\听音数据{today}.{pipeIndex}.{listenTimes}.txt";

                var builder = new StringBuilder();
                for (var i = 0; i < dataArray.Count; i++)
                {
                    _perData = BitConverter.ToString(dataArray[i]);
                    if (i == dataArray.Count - 1)
                    {
                        builder.Append(_perData);
                    }
                    else
                    {
                        builder.Append(_perData).Append("\r\n");
                    }
                }

                File.AppendAllText(fileName, builder.Replace("-", "").ToString());

                //插入新纪录
                configModel.Pipe++;
                configModel.LocateTimes++;
                manager.Insert(configModel);

                //清空缓存
                RuntimeCache.SoundCaches.Clear();
            }
        }

        /// <summary>
        /// 保存定位数据
        /// </summary>
        /// <param name="fileName">完整路径</param>
        /// <param name="it">CorrelatorDataModel</param>
        public static void SaveLocateData(this string fileName, CorrelatorDataModel it)
        {
            var builder = new StringBuilder();
            builder.Append(DateTime.Now.ToString(CultureInfo.InvariantCulture)).Append("\r\n");
            foreach (var d in it.LeftDeviceDataArray)
            {
                builder.Append(d).Append("\r\n");
            }

            builder.Append("===============").Append("\r\n");
            for (var i = 0; i < it.RightDeviceDataArray.Length; i++)
            {
                var d = it.RightDeviceDataArray[i];
                if (i == it.RightDeviceDataArray.Length - 1)
                {
                    builder.Append(d);
                }
                else
                {
                    builder.Append(d).Append("\r\n");
                }
            }

            File.AppendAllText(fileName, builder.ToString());
        }

        /// <summary>
        /// 本地数据读取
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static List<string> ReadFromFile(this string filePath)
        {
            var list = new List<string>();
            var streamReader = new StreamReader(filePath);
            string line;
            while ((line = streamReader.ReadLine()) != null)
            {
                list.Add(line);
            }

            streamReader.Close();
            return list;
        }

        public static void SaveArrayToFile(this double[] array, string fileName)
        {
            var builder = new StringBuilder();
            foreach (var d in array)
            {
                builder.Append(d).Append("\r\n");
            }

            File.AppendAllText(fileName, builder.ToString());
        }

        /// <summary>
        /// 根据列表返回总页码
        /// </summary>
        /// <param name="count"></param>
        /// <returns></returns>
        public static int GetPageSize(this int count)
        {
            return (count + RuntimeCache.PerPageItemCount - 1) / RuntimeCache.PerPageItemCount;
        }
    }
}