using CCDCount.DLL.AlarmTools;
using CCDCount.MODEL.ConfigModel;
using CCDCount.MODEL.ResultModel;
using CCDCount.MODEL.ShuLiModel;
using LogClass;
using MvCameraControl;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;

namespace CCDCount.DLL
{
    public class ShuLiClass
    {
        #region 变量
        /// <summary>
        /// 当活跃物体转变为历史物体时的回调事件
        /// </summary>
        public event EventHandler<ActiveObjectEventArgsClass> WorkCompleted;
        private List<ActiveObjectClass> activeObjects = new List<ActiveObjectClass>(); // 当前跟踪中的物体
        private List<ActiveObjectClass> historyActiveObjects = new List<ActiveObjectClass>(); // 历史物体
        private ConcurrentQueue<IImage> IFrameDatas = new ConcurrentQueue<IImage>(); //图像数据队列
        private Thread IdentifyImageProcessThread = null; // 识别线程
        private bool IsIdentify = false; //线程是否开始识别的标志
        private long currentLine = 0; //行数记录
        private ShuLiConfigClass shuLiConfig = null;// 数粒参数配置文件
        public List<int> ChannelsRoi { get { return _ChannelsRoi; } }
        private List<int> _ChannelsRoi = new List<int>();
        private int ChannelWidth = 0;//每个区域的宽度
        private int IdentifyImageWidth = -1;
        private int ObjectNum = 0;
        public int ImageNum { get { return IFrameDatas.Count; } }
        private ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
        private double XCoefficient = 1;
        private double YCoefficient = 2;
        private DateTime[] ChannelIntervalTime = new DateTime[8];
        #endregion

        #region 公共方法
        /// <summary>
        /// 初始化构造方法
        /// </summary>
        public ShuLiClass()
        {
            // 加载默认参数
            shuLiConfig = new ShuLiConfigClass()
            {
                Channel = 8,
                PandingCode = 2
            };
            for(int i = 0; i < ChannelIntervalTime.Length; i++)
            {
                ChannelIntervalTime[i] = DateTime.Now;
            }

        }

        /// <summary>
        /// 带参数的构造方法
        /// </summary>
        public ShuLiClass(ShuLiConfigClass config)
        {
            if (config.IsLoadCanfig)
            {
                // 加载传出的参数
                shuLiConfig = config;
                XCoefficient = shuLiConfig.ScaleX;
                YCoefficient = shuLiConfig.ScaleY;
            }
            else
            {
                // 加载默认参数
                shuLiConfig = new ShuLiConfigClass()
                {
                    Channel = 8,
                    PandingCode = 2
                };
            }
            InitChannel();
        }

        public long InitCurrentLine(int line)
        {
            currentLine = line;
            return currentLine;
        }

        public int InitNum(int num)
        {
            ObjectNum = num;
            return ObjectNum;
        }

        List<ActiveObjectClass> lostObjects = new List<ActiveObjectClass>();
        /// <summary>
        /// 处理图像序列的主入口
        /// </summary>
        /// <param name="image">图像像素数据</param>
        /// <param name="ImageWidth">图像宽</param>
        /// <param name="currentLine">当前行数</param>
        /// <returns>检测到的物体总数</returns>
        public bool ProcessImageSequence(IImage image)
        {
            bool result = false;
            for (int i = 0; i < image.Height; i++)
            {
                result = ProcessLine(image, i);
                currentLine += 1;
            }


            Stopwatch stopwatch = Stopwatch.StartNew();
            //识别到结果并输出
            //lock (_lockObj)
            //{
            _rwLock.EnterReadLock();
            // 清理超时未更新的物体
            lostObjects = activeObjects
                .Where(o => (currentLine - o.LastSeenLine) > shuLiConfig.MAX_GAP || (o.LastSeenLine - o.StartLine) > shuLiConfig.MAX_Idetify_Height)
                .ToList();
            _rwLock.ExitReadLock();
            //}
            if (stopwatch.ElapsedMilliseconds > 1)
            {
                FaultLog.RecordErrorMessage($"ShuLiClass-ProcessImageSequence:图像结果分析-结果筛选，此次识别耗时：{stopwatch.Elapsed}");
            }

            List<ActiveObjectClass> OneActive = new List<ActiveObjectClass>();

            // 有物体转变为活跃物体，返回值转为true
            if (lostObjects.Count > 0)
            {
                result = true;
                stopwatch.Restart();
                foreach (var item in lostObjects)
                {
                    //噪点判定
                    if (item.Area < shuLiConfig.NoiseFilter_Threshold)
                    {
                        item.StateCode = 9;
                        //LOG.log(string.Format("噪点过滤，噪点面积：{0}", item.Area), 6);
                        continue;
                    }
                    //转为历史物体，添加缺少的参数
                    item.Num = Interlocked.Increment(ref ObjectNum) + 1;
                    item.ChannelNO = ActiveChannel(item);
                    item.EndCheckTime = DateTime.Now;
                    if(item.StartLine == item.LastSeenLine)
                    {
                        item.MaxLength = item.MaxEndCol - item.MinStartCol;
                        item.StateCode = 10;
                        LOG.log(string.Format("颗粒{0}的有效高度仅一行", item.Num));
                    }
                    else
                    {
                        var CalculationResult = SizeCalculation(item.RowsData);
                        item.MaxLength = CalculationResult.Height;
                        item.hasSignificantConcavity = CalculationResult.hasSignificantConcavity;
                        item.concavityRatio = CalculationResult.concavityRatio;
                        if(CalculationResult.hasSignificantConcavity)
                        {
                            if(CalculationResult.concavityRatio>0.3)
                            {
                                item.StateCode= 11;
                            }
                        }
                    }
                    if ((item.LastSeenLine - item.StartLine) > shuLiConfig.MAX_Idetify_Height&&item.StateCode != -1)
                    {
                        item.StateCode = 7;
                        //FaultLog.RecordLogMessage("ShuLiClass-ProcessLine：非颗粒，视野异常", 3);
                        //LOG.log(string.Format("ShuLiClass-ProcessLine：非颗粒，视野异常"), 6);
                        //Console.WriteLine("ShuLiClass-ProcessLine：非颗粒，视野异常");
                    }
                    else if (shuLiConfig.PandingCode != -1)
                    {
                        if (item.StateCode != -1)
                        {
                            if (item.StateCode == 8)
                            {
                                LOG.log(string.Format("颗粒编号{0}：疑似叠片或缺损", item.Num));
                            }
                        }
                        else if (item.Area < shuLiConfig.MinArea
                            && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
                        {
                            item.StateCode = 5;
                            LOG.log(string.Format("颗粒编号{0}：面积过小", item.Num));
                            Console.WriteLine("颗粒编号{0}：面积过小", item.Num);
                        }
                        else if (item.Area > shuLiConfig.MaxArea
                            && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 1))
                        {
                            item.StateCode = 6;
                            LOG.log(string.Format("颗粒编号{0}：面积过大", item.Num));
                            Console.WriteLine("颗粒编号{0}：面积过大", item.Num);
                        }
                        else if (item.MaxLength < shuLiConfig.MIN_Object_LENGTH
                            && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
                        {
                            item.StateCode = 2;
                            LOG.log(string.Format("颗粒编号{0}：超短粒", item.Num));
                            Console.WriteLine("颗粒编号{0}：超短粒", item.Num);
                        }
                        else if (item.MaxLength > shuLiConfig.MAX_Object_LENGTH
                            && (shuLiConfig.PandingCode == 2 || shuLiConfig.PandingCode == 0))
                        {
                            item.StateCode = 1;
                            LOG.log(string.Format("颗粒编号{0}：超长粒", item.Num));
                            Console.WriteLine("颗粒编号{0}：超长粒", item.Num);
                        }
                        else
                        {
                            item.StateCode = 0;
                            LOG.log(string.Format("颗粒编号{0}：正常粒", item.Num));
                            Console.WriteLine("颗粒编号{0}：正常粒", item.Num);
                        }
                    }
                    OneActive.Add(item);
                }
                stopwatch.Stop();
                //if (stopwatch.ElapsedMilliseconds > 1)
                //{
                //    FaultLog.RecordErrorMessage($"ShuLiClass-ProcessImageSequence:图像结果分析-结果参数补全，此次识别耗时：{stopwatch.Elapsed}");
                //}
                //stopwatch.Restart();
                if (OneActive.Count > 0)
                {
                    //触发回调事件
                    OnWorkCompleted(OneActive);
                    //ThreadPool.QueueUserWorkItem(_ =>OnWorkCompleted(OneActive));
                }
                stopwatch.Stop();
                //if (stopwatch.ElapsedMilliseconds > 1)
                //{
                //    FaultLog.RecordErrorMessage($"ShuLiClass-ProcessImageSequence:图像结果分析-结果完成回调函数，此次识别耗时：{stopwatch.Elapsed}");
                //}
            }
            else
            {
                OneActive.Clear();
            }
            _rwLock.EnterWriteLock();
            // 累加到总数并从活跃物体转移到历史物体
            OneActive.ForEach(o => TryAdd(historyActiveObjects, o, 2500));
            //lostObjects.Where(o => o.StateCode != 7 && o.StateCode != 9).ToList().ForEach(o => TryAdd(historyActiveObjects, o, 2500));
            lostObjects.ForEach(o => activeObjects.Remove(o));
            _rwLock.ExitWriteLock();
            return result;
        }

        /// <summary>
        /// 返回最后一个历史物品
        /// </summary>
        /// <returns></returns>
        public ActiveObjectClass GetLastActive()
        {
            if (historyActiveObjects.Count() == 0)
                return null;
            return historyActiveObjects.Last();
        }

        /// <summary>
        /// 返回历史物品
        /// </summary>
        /// <returns></returns>
        public List<ActiveObjectClass> GetHistoryActive()
        {
            //lock (_lockObj) // 加锁
            //{
            _rwLock.EnterReadLock();
            var result = historyActiveObjects.ToList();
            _rwLock.ExitReadLock();
            return result;
            //}
        }

        /// <summary>
        /// 返回缓存在内存的历史物品的总数量
        /// </summary>
        /// <returns></returns>
        public int GetHistoryActiveNum()
        {
            //lock (_lockObj) // 加锁
            _rwLock.EnterReadLock();
            var result = historyActiveObjects.Count;
            _rwLock.ExitReadLock();
            return result;
        }

        /// <summary>
        /// 获取历史数据中，正常数据数量
        /// </summary>
        /// <returns></returns>
        public int GetOkHistoryNum()
        {
            //lock (_lockObj)
            _rwLock.EnterReadLock();
            var result = historyActiveObjects.Where(o => o.StateCode == 0).ToList().Count;
            _rwLock.ExitReadLock();
            return result;
        }

        /// <summary>
        /// 获取历史数据中，异常数据数量
        /// </summary>
        /// <returns></returns>
        public int GetNgHistoryNum()
        {
            //lock (_lockObj)
            _rwLock.EnterReadLock();
            var result = historyActiveObjects.Where(o => o.StateCode != 0).ToList().Count;
            _rwLock.ExitReadLock();
            return result;
        }

        /// <summary>
        /// 清除历史数据
        /// </summary>
        /// <returns></returns>
        public bool ClearHistoryActive()
        {
            //lock (_lockObj)
            //{
            _rwLock.EnterWriteLock();
            historyActiveObjects.Clear();
            _rwLock.ExitWriteLock();
            return true;
            //}
        }

        /// <summary>
        /// 开启识别
        /// </summary>
        public void StartIdentifyFuntion(int ImaageWidth)
        {
            UpdateIdentifyImageWidth(ImaageWidth);
            InitChannel();
            try
            {
                // 标志位置位true
                IsIdentify = true;
                // 打开识别线程
                IdentifyImageProcessThread = new Thread(IdentifyImageProcess)
                {
                    Priority = ThreadPriority.Highest
                };
                IdentifyImageProcessThread.Start();
                SystemAlarm.AlarmCancel(AlarmMessageList.识别线程启动失败);
            }
            catch (Exception ex)
            {
                SystemAlarm.AlarmAlert(AlarmMessageList.识别线程启动失败, "Start thread failed!, " + ex.Message, "DLL:ShuLiClass-StartIdentifyFuntion");
                //FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 关闭识别
        /// </summary>
        public void StopIdentifyFuntion()
        {
            try
            {
                // 标志位设为false
                IsIdentify = false;
                if (IdentifyImageProcessThread != null && IdentifyImageProcessThread.IsAlive)
                    IdentifyImageProcessThread.Join();
                SystemAlarm.AlarmCancel(AlarmMessageList.识别线程停止失败);
            }
            catch (Exception ex)
            {
                //FaultLog.RecordErrorMessage("Stop thread failed!, " + ex.Message);
                SystemAlarm.AlarmAlert(AlarmMessageList.识别线程停止失败, "Stop thread failed!, " + ex.Message, "DLL:ShuLiClass-StopIdentifyFuntion");
                throw;
            }
        }

        /// <summary>
        /// 向识别队列添加一个数据
        /// </summary>
        /// <param name="items"></param>
        public void SetOnceIdentifyImageData(IImage items)
        {
            IFrameDatas.Enqueue(items.Clone() as IImage);
        }

        /// <summary>
        /// 保存参数
        /// </summary>
        public void SaveConfig()
        {
            if (!Directory.Exists(".\\Config\\")) Directory.CreateDirectory(".\\Config\\");
            XmlStorage.SerializeToXml(shuLiConfig, ".\\Config\\ShuLiConfig.xml");
        }

        /// <summary>
        /// 更新检测宽度信息
        /// </summary>
        /// <param name="Width"></param>
        public void UpdateIdentifyImageWidth(int Width)
        {
            IdentifyImageWidth = Width;
        }

        /// <summary>
        /// 初始化通道划分
        /// </summary>
        /// <param name="ImageWidth"></param>
        public void InitChannel()
        {
            _ChannelsRoi.Clear();
            shuLiConfig.ImageWidth = IdentifyImageWidth == -1 ? shuLiConfig.ImageWidth : IdentifyImageWidth;
            if (shuLiConfig.Channel > 0)
            {
                if (shuLiConfig.IsIdentifyRoiOpen)
                {
                    ChannelWidth = (shuLiConfig.IdentifyStopX - shuLiConfig.IdentifyStartX) / shuLiConfig.Channel;
                }
                else
                {
                    ChannelWidth = shuLiConfig.ImageWidth / shuLiConfig.Channel;
                }
                for (int i = 0; i < shuLiConfig.Channel; i++)
                {
                    _ChannelsRoi.Add(ChannelWidth + i * ChannelWidth);
                }
            }
        }

        /// <summary>
        /// 获取配置信息
        /// </summary>
        /// <returns></returns>
        public ShuLiConfigClass GetConfigValue()
        {
            ShuLiConfigClass result = shuLiConfig;

            return result;
        }

        public int GetConfigImageWidth()
        {
            int result = -1;
            if (shuLiConfig != null)
                result = shuLiConfig.ImageWidth;
            return result;
        }

        /// <summary>
        /// 获取坐标转换系数
        /// </summary>
        /// <param name="XCoefficient"></param>
        /// <param name="YCoefficient"></param>
        public void GetXYCoefficient(out double XCoefficient, out double YCoefficient)
        {
            XCoefficient = this.XCoefficient;
            YCoefficient = this.YCoefficient;
        }

        /// <summary>
        /// 设置坐标转换X系数
        /// </summary>
        /// <param name="XCoefficient"></param>
        public void SetXCoefficient(double XCoefficient)
        {
            this.XCoefficient = XCoefficient;
        }

        /// <summary>
        /// 设置坐标转换Y系数
        /// </summary>
        public void SetYCoefficient(double YCoefficient)
        {
            this.YCoefficient = YCoefficient;
        }
        #endregion

        #region 私有方法

        /// <summary>
        /// 对外通知事件
        /// </summary>
        private void OnWorkCompleted(List<ActiveObjectClass> activeObject)
        {
            if(activeObject == null) return;
            ActiveObjectEventArgsClass activeObjectEventArgs = new ActiveObjectEventArgsClass(activeObject);
            // 触发事件
            WorkCompleted?.Invoke(this, activeObjectEventArgs);
        }

        private bool IsPrintLightOnError = false;

        /// <summary>
        /// 处理单行像素数据
        /// 返回值为false的时候无活跃物体转变为历史物体
        /// 返回值为true的时候有活跃物体转变为历史物体
        /// </summary>
        /// <param name="image">当前行像素数组</param>
        private bool ProcessLine(IImage imagedata, int RowNo)
        {
            //Stopwatch stopwatch = Stopwatch.StartNew();
            bool result = false;
            // 步骤1：检测当前行的有效区域
            var currentRegions = FindValidRegions(imagedata, RowNo);

            if (currentRegions.Count == 1)
            {
                if (currentRegions[0].End - (currentRegions[0]).Start + 1 == imagedata.Width)
                {
                    if (!IsPrintLightOnError)
                    {
                        FaultLog.RecordLogMessage("当前行有效区域为整行,检查视野和光源", 5);
                        IsPrintLightOnError = true;
                    }
                    return false;
                }
            }
            IsPrintLightOnError = false;
            //stopwatch.Stop();
            //if (stopwatch.ElapsedMilliseconds > 1)
            //{
            //    FaultLog.RecordErrorMessage($"ShuLiClass-ProcessLine:图像连通域检测超时，此次识别耗时：{stopwatch.Elapsed}");
            //}
            //stopwatch.Restart();
            foreach (var region in currentRegions)
            {

                // 查找全部可合并的活跃物体（有重叠+在允许间隔内）
                _rwLock.EnterReadLock();
                var matcheds = activeObjects.Where(o =>
                    IsOverlapping(o, region) &&
                    (currentLine - o.LastSeenLine - 1) <= shuLiConfig.MAX_GAP).ToList();
                _rwLock.ExitReadLock();
                //当有多个可合并的活跃物体时，将多个物体合并
                if (matcheds.Count >= 2)
                {
                    // 合并有效区域队列
                    var CopeRowsData = new List<RowStartEndCol>();
                    matcheds.ForEach(o => CopeRowsData = CopeRowsData.Concat(o.RowsData).ToList());
                    // 合并有效区域并保存在新的区域中
                    var MergeMatched = new ActiveObjectClass
                    {
                        MinStartCol = matcheds.Min(o => o.MinStartCol),
                        MaxEndCol = matcheds.Max(o => o.MaxEndCol),
                        StartLine = matcheds.Min(o => o.StartLine),
                        LastSeenLine = matcheds.Max(o => o.LastSeenLine),
                        LastSeenLineStartCol = matcheds.Min(o => o.LastSeenLineStartCol),
                        LastSeenLineEndCol = matcheds.Max(o => o.LastSeenLineEndCol),
                        StartCheckTime = matcheds.Min(o => o.StartCheckTime),
                        EndCheckTime = matcheds.Max(o => o.EndCheckTime),
                        Area = matcheds.Sum(o => o.Area),
                        RowsData = CopeRowsData,
                        ImageWidth = matcheds.FirstOrDefault().ImageWidth,
                        StateCode = 8
                    };
                    _rwLock.EnterWriteLock();
                    // 从活跃区域中删除被合并的区域
                    matcheds.ForEach(o => activeObjects.Remove(o));
                    // 保存新的区域到活跃区域中
                    activeObjects.Add(MergeMatched);
                    _rwLock.ExitWriteLock();
                }
                _rwLock.EnterReadLock();
                // 搜获可用且可合并的活跃区域
                var matched = activeObjects.FirstOrDefault(o =>
                    IsOverlapping(o, region) &&
                    (currentLine - o.LastSeenLine - 1) <= shuLiConfig.MAX_GAP);
                _rwLock.ExitReadLock();
                if (matched != null)
                {
                    // 合并区域：扩展物体边界并更新状态
                    matched.MinStartCol = Math.Min(matched.MinStartCol, region.Start);
                    matched.MaxEndCol = Math.Max(matched.MaxEndCol, region.End);
                    matched.Area += region.End - region.Start + 1;
                    matched.LastSeenLine = currentLine;
                    matched.RowsData.Add(new RowStartEndCol
                    {
                        StartCol = region.Start,
                        EndCol = region.End,
                        RowsCol = currentLine,
                    });
                    matched.LastSeenLineStartCol = region.Start;
                    matched.LastSeenLineEndCol = region.End;
                }
                else
                {
                    _rwLock.EnterWriteLock();
                    // 创建新物体（首次出现的区域）
                    activeObjects.Add(new ActiveObjectClass
                    {
                        MinStartCol = region.Start,
                        MaxEndCol = region.End,
                        StartLine = currentLine,
                        LastSeenLine = currentLine,
                        LastSeenLineStartCol = region.Start,
                        LastSeenLineEndCol = region.End,
                        StartCheckTime = DateTime.Now,
                        Area = region.End - region.Start + 1,
                        ImageWidth = IdentifyImageWidth,
                        RowsData = new List<RowStartEndCol> {
                            new RowStartEndCol {
                                StartCol = region.Start,
                                EndCol = region.End,
                                RowsCol = currentLine,
                            }
                        }
                    });
                    _rwLock.ExitWriteLock();
                }
            }

            //stopwatch.Stop();
            //if (stopwatch.ElapsedMilliseconds > 1)
            //{
            //    FaultLog.RecordErrorMessage($"ShuLiClass-ProcessLine:图像区域合并超时，此次识别耗时：{stopwatch.Elapsed}");
            //}
            currentRegions.Clear();
            
            return result;
        }
        List<ValidRegionModelClass> regions = new List<ValidRegionModelClass>();
        /// <summary>
        /// 检测有效物体区域（横向连续黑色像素段）
        /// </summary>
        /// <param name="line">当前行像素数组</param>
        /// <returns>有效区域列表（起始/结束位置）</returns>
        private List<ValidRegionModelClass> FindValidRegions(IImage image, int RowNo)
        {
            regions.Clear();
            int start = -1; // 当前区域起始标记
            int end = -1;
            // 遍历所有像素列
            if (shuLiConfig.IsIdentifyRoiOpen)
            {
                for (int i = (int)image.Width * RowNo + shuLiConfig.IdentifyStartX; i < (int)image.Width * RowNo + shuLiConfig.IdentifyStopX; i++)
                {
                    if (image.PixelData[i] < shuLiConfig.RegionThreshold) // 发现黑色像素
                    {
                        if (start == -1) start = i % (int)image.Width; // 开始新区域
                    }
                    else if (start != -1) // 遇到白色像素且存在进行中的区域
                    {
                        end = (i - 1) % (int)image.Width;
                        // 检查区域宽度是否达标
                        if (end - start >= shuLiConfig.NoiseFilter_Threshold)
                        {
                            regions.Add(new ValidRegionModelClass()
                            {
                                Start = start,
                                End = end
                            }); // 记录有效区域
                        }
                        start = -1; // 重置区域标记
                        end = -1;
                    }
                }
            }
            else
            {
                for (int i = (int)image.Width * RowNo; i < (int)image.Width * (RowNo + 1); i++)
                {
                    if (image.PixelData[i] < shuLiConfig.RegionThreshold) // 发现黑色像素
                    {
                        if (start == -1) start = i % (int)image.Width; // 开始新区域
                    }
                    else if (start != -1) // 遇到白色像素且存在进行中的区域
                    {
                        end = (i - 1) % (int)image.Width;
                        // 检查区域宽度是否达标
                        if (end - start >= shuLiConfig.NoiseFilter_Threshold)
                        {
                            regions.Add(new ValidRegionModelClass()
                            {
                                Start = start,
                                End = end
                            }); // 记录有效区域
                        }
                        start = -1; // 重置区域标记
                        end = -1;
                    }
                }
            }


            // 处理行尾未闭合的区域
            if (start != -1 && image.Width - start >= shuLiConfig.NoiseFilter_Threshold)
            {
                regions.Add(new ValidRegionModelClass()
                {
                    Start = start,
                    End = (int)image.Width - 1
                });
            }
            return regions;
        }

        /// <summary>
        /// 判断区域重叠（与活跃物体的横向坐标重叠检测）
        /// </summary>
        /// <param name="obj">活跃物体</param>
        /// <param name="region">当前区域</param>
        /// <returns>是否发生重叠</returns>
        private bool IsOverlapping(ActiveObjectClass obj, ValidRegionModelClass region)
        {
            // 判断区域是否不相交的逆条件
            return !(region.End < obj.LastSeenLineStartCol || region.Start > obj.LastSeenLineEndCol);
        }

        /// <summary>
        /// 通道区域判定
        /// </summary>
        /// <param name="activeObject"></param>
        /// <returns></returns>
        private int ActiveChannel(ActiveObjectClass activeObject)
        {
            int result = -1;
            int StartChannel = activeObject.MinStartCol / ChannelWidth;
            int EndChannel = activeObject.MaxEndCol / ChannelWidth;
            if (StartChannel == EndChannel)
            {
                result = StartChannel;
            }
            else if (EndChannel - StartChannel > 1)
            {
                Console.WriteLine("ActiveChannel-Error");
                //error
            }
            else
            {
                result = _ChannelsRoi[StartChannel] - activeObject.MinStartCol > activeObject.MaxEndCol - _ChannelsRoi[StartChannel] ? StartChannel : EndChannel;
            }
            return result;
        }

        /// <summary>
        /// 获取结果最长长边
        /// </summary>
        /// <param name="Rows"></param>
        /// <returns></returns>
        public BoundingRectangleMdoel SizeCalculation(List<RowStartEndCol> Rows)
        {
            //Stopwatch stopwatch = Stopwatch.StartNew();
            ConvexResultClass points = ConvexHullWithConcavityDetection(Rows);
            //stopwatch.Stop();
            //Console.WriteLine($"凸包计算耗时：{stopwatch.Elapsed}");
            //var test = CalculateMinimumBoundingRectangle(points); 
            var result = CoefficientCalculateMinimumBoundingRectangle(points.convexHull);
            result.hasSignificantConcavity = points.hasSignificantConcavity;
            result.concavityRatio = points.concavityRatio;
            return result;
        }

        /// <summary>
        /// 凸包点集合获取
        /// </summary>
        /// <param name="Rows"></param>
        /// <returns></returns>
        public List<Point> ConvexHull(List<RowStartEndCol> Rows)
        {
            List<Point> points = Rows.Select(o => new Point(o.StartCol, (int)o.RowsCol)).ToList();
            points.AddRange(Rows.Select(o => new Point(o.EndCol, (int)o.RowsCol)).ToList());
            points = points.OrderBy(o => o.X).ThenBy(o => o.Y).ToList();
            var lower = new List<Point>();
            foreach (var p in points)
            {
                while (lower.Count >= 2 && Cross(lower[lower.Count - 2], lower[lower.Count - 1], p) <= 0)
                    lower.RemoveAt(lower.Count - 1);
                lower.Add(p);
            }

            var upper = new List<Point>();
            for (int i = points.Count - 1; i >= 0; i--)
            {
                var p = points[i];
                while (upper.Count >= 2 && Cross(upper[upper.Count - 2], upper[upper.Count - 1], p) <= 0)
                    upper.RemoveAt(upper.Count - 1);
                upper.Add(p);
            }

            lower.RemoveAt(lower.Count - 1);
            upper.RemoveAt(upper.Count - 1);
            lower.AddRange(upper);
            return lower;
        }

        /// <summary>
        /// 凸包点集合获取,输出原点集
        /// </summary>
        /// <param name="Rows"></param>
        /// <returns></returns>
        public List<Point> ConvexHull(List<RowStartEndCol> Rows,out List<Point> points)
        {
            points = Rows.Select(o => new Point(o.StartCol, (int)o.RowsCol)).ToList();
            points.AddRange(Rows.Select(o => new Point(o.EndCol, (int)o.RowsCol)).ToList());
            points = points.OrderBy(o => o.X).ThenBy(o => o.Y).ToList();
            var lower = new List<Point>();
            foreach (var p in points)
            {
                while (lower.Count >= 2 && Cross(lower[lower.Count - 2], lower[lower.Count - 1], p) <= 0)
                    lower.RemoveAt(lower.Count - 1);
                lower.Add(p);
            }

            var upper = new List<Point>();
            for (int i = points.Count - 1; i >= 0; i--)
            {
                var p = points[i];
                while (upper.Count >= 2 && Cross(upper[upper.Count - 2], upper[upper.Count - 1], p) <= 0)
                    upper.RemoveAt(upper.Count - 1);
                upper.Add(p);
            }

            lower.RemoveAt(lower.Count - 1);
            upper.RemoveAt(upper.Count - 1);
            lower.AddRange(upper);
            return lower;
        }

        /// <summary>
        /// 凸包点集合获取，同时检测较大的内凹
        /// </summary>
        /// <param name="Rows"></param>
        /// <returns>返回凸包点集</returns>
        public ConvexResultClass ConvexHullWithConcavityDetection(List<RowStartEndCol> Rows)
        {
            ConvexResultClass result = null;
            // 构建原始点集
            var lower = ConvexHull(Rows, out List<Point> originalPoints);

            // 检测内凹
            ConvexResultClass ConvexResult = DetectConcavity(originalPoints, lower);

            return result = new ConvexResultClass()
            {
                convexHull = lower,
                hasSignificantConcavity = ConvexResult.hasSignificantConcavity,
                concavityRatio = ConvexResult.concavityRatio,
            };
        }

        /// <summary>
        /// 检测是否存在显著的内凹
        /// </summary>
        /// <param name="originalPoints">原始点集</param>
        /// <param name="convexHull">凸包点集</param>
        /// <returns>是否存在显著内凹和程度比值</returns>
        private ConvexResultClass DetectConcavity(List<Point> originalPoints, List<Point> convexHull)
        {
            if (convexHull.Count < 3) return new ConvexResultClass()
            {
                hasSignificantConcavity = false,
                concavityRatio = 0,
            };

            // 检查原始点集中有多少点在凸包内部（即非凸包顶点）
            HashSet<Point> hullPoints = new HashSet<Point>(convexHull);
            var internalPoints = originalPoints.Where(p => !hullPoints.Contains(p)).ToList();

            if (internalPoints.Count == 0)
            {
                // 所有点都在凸包上，没有内凹
                return new ConvexResultClass()
                {
                    hasSignificantConcavity = false,
                    concavityRatio = 0,
                };
            }

            // 计算凸包面积
            double convexHullArea = CalculatePolygonArea(convexHull);

            double PointsArea = CalculatePolygonArea(SortPointsByNearestNeighbor(originalPoints));

            var concavityMeasure = (convexHullArea - PointsArea) / convexHullArea;


            // 判断是否存在显著内凹（可以根据实际需求调整阈值）
            bool hasSignificantConcavity = concavityMeasure > 0.3;

            return new ConvexResultClass()
            {
                hasSignificantConcavity = hasSignificantConcavity,
                concavityRatio = concavityMeasure,
            }; 
        }

        /// <summary>
        /// 计算封闭多边形的面积（鞋带公式）
        /// </summary>
        /// <param name="polygon">多边形顶点（必须是封闭的）</param>
        /// <returns>面积</returns>
        private double CalculatePolygonArea(List<Point> polygon)
        {
            if (polygon.Count < 3) return 0;

            // 确保多边形是封闭的
            var closedPolygon = new List<Point>(polygon);
            if (closedPolygon.First() != closedPolygon.Last())
            {
                closedPolygon.Add(closedPolygon[0]);
            }

            double area = 0;
            for (int i = 0; i < closedPolygon.Count - 1; i++)
            {
                area += (double)closedPolygon[i].X * closedPolygon[i + 1].Y;
                area -= (double)closedPolygon[i].Y * closedPolygon[i + 1].X;
            }

            return Math.Abs(area) / 2.0;
        }


        /// <summary>
        /// 凸包最长边,结果通过系数计算
        /// </summary>
        /// <param name="hull"></param>
        /// <returns></returns>
        public MaxLengthModel CoefficientRotatingCalipers(List<Point> hull)
        {
            //老方法
            MaxLengthModel result = new MaxLengthModel();
            int n = hull.Count;
            if (n == 1)
            {
                result = null;
                return result;
            }
            if (n == 2)
            {
                result.MaxLength = Distance(hull[0], hull[1]);
                result.Point1Index = 0;
                result.Point1 = hull[0];
                result.Point2Index = 1;
                result.Point2 = hull[1];
                return result;
            }

            double maxDist = 0;
            int pointIndex1 = 0;
            int pointIndex2 = 0;

            for (int i = 0; i < n; i++)
            {
                for (int j = i + 1; j < n; j++)
                {
                    if (CoefficientDistance(hull[i], hull[j]) > maxDist)
                    {
                        maxDist = CoefficientDistance(hull[i], hull[j]);
                        pointIndex1 = i;
                        pointIndex2 = j;
                    }

                }
            }

            result.Point1 = hull[pointIndex1];
            result.Point1Index = pointIndex1;
            result.Point2 = hull[pointIndex2];
            result.Point2Index = pointIndex2;
            result.MaxLength = maxDist;

            return result;
        }

        /// <summary>
        /// 凸包最长边
        /// </summary>
        /// <param name="hull"></param>
        /// <returns></returns>
        public MaxLengthModel RotatingCalipers(List<Point> hull)
        {
            //老方法
            MaxLengthModel result = new MaxLengthModel();
            int n = hull.Count;
            if (n == 1)
            {
                result = null;
                return result;
            }
            if (n == 2)
            {
                result.MaxLength = Distance(hull[0], hull[1]);
                result.Point1Index = 0;
                result.Point1 = hull[0];
                result.Point2Index = 1;
                result.Point2 = hull[1];
                return result;
            }

            double maxDist = 0;
            int pointIndex1 = 0;
            int pointIndex2 = 0;

            for (int i = 0; i < n; i++)
            {
                for (int j = i + 1; j < n; j++)
                {
                    if (Distance(hull[i], hull[j]) > maxDist)
                    {
                        maxDist = Distance(hull[i], hull[j]);
                        pointIndex1 = i;
                        pointIndex2 = j;
                    }

                }
            }

            result.Point1 = hull[pointIndex1];
            result.Point1Index = pointIndex1;
            result.Point2 = hull[pointIndex2];
            result.Point2Index = pointIndex2;
            result.MaxLength = Distance(result.Point1, result.Point2);

            return result;
        }

        /// <summary>
        /// 计算凸包的最小外接矩形
        /// </summary>
        /// <param name="convexHull">凸包顶点列表（按逆时针顺序排列）</param>
        /// <returns>最小外接矩形的四个顶点</returns>
        public BoundingRectangleMdoel CalculateMinimumBoundingRectangle(List<Point> convexHull)
        {
            BoundingRectangleMdoel result = new BoundingRectangleMdoel();
            if (convexHull == null || convexHull.Count < 3)
                return null;

            double minArea = double.MaxValue;

            int n = convexHull.Count;

            // 遍历每一条边作为基准边
            for (int i = 0; i < n; i++)
            {
                Point edgeStart = convexHull[i];
                Point edgeEnd = convexHull[(i + 1) % n];

                // 计算当前边的角度
                double angle = Math.Atan2(edgeEnd.Y - edgeStart.Y, edgeEnd.X - edgeStart.X);

                // 将所有点绕原点旋转-angle角度，使当前边与x轴平行
                var rotatedPoints = convexHull.Select(p => RotatePoint(p, -angle)).ToList();

                // 找到包围盒
                int minX = rotatedPoints.Min(p => p.X);
                int maxX = rotatedPoints.Max(p => p.X);
                int minY = rotatedPoints.Min(p => p.Y);
                int maxY = rotatedPoints.Max(p => p.Y);

                // 计算面积
                double area = (maxX - minX) * (maxY - minY);

                // 如果面积更小，则更新最小矩形
                if (area < minArea)
                {
                    minArea = area;

                    // 构造矩形的四个顶点并旋转回原来的角度
                    var rectangle = new List<Point>
                    {
                         RotatePoint(new Point(minX, minY), angle),
                         RotatePoint(new Point(maxX, minY), angle),
                         RotatePoint(new Point(maxX, maxY), angle),
                         RotatePoint(new Point(minX, maxY), angle)
                    };

                    result.points = rectangle;
                    result.Angle = angle;
                    result.CenterPoint = RotatePoint(new Point((maxX + minX) / 2, (maxY + minY) / 2), angle);
                }
            }

            double l1 = Distance(result.points[0], result.points[1]);
            double l2 = Distance(result.points[1], result.points[2]);

            if (l1 < l2)
            {
                result.WidthPoints = new List<Point>
                {
                    result.points[0],
                    result.points[1],
                };
                result.HeightPoints = new List<Point>
                {
                    result.points[1],
                    result.points[2],
                };
            }
            else
            {
                result.WidthPoints = new List<Point>
                {
                    result.points[2],
                    result.points[1],
                };
                result.HeightPoints = new List<Point>
                {
                    result.points[1],
                    result.points[0],
                };
            }

            result.Height = Math.Max(l1, l2);
            result.Width = Math.Min(l1, l2);

            return result;
        }

        /// <summary>
        /// 计算凸包的最小外接矩形
        /// </summary>
        /// <param name="convexHull">凸包顶点列表（按逆时针顺序排列）</param>
        /// <returns>最小外接矩形的四个顶点</returns>
        public BoundingRectangleMdoel CoefficientCalculateMinimumBoundingRectangle(List<Point> convexHull)
        {
            BoundingRectangleMdoel result = new BoundingRectangleMdoel();
            if (convexHull == null || convexHull.Count < 3)
                return null;

            double minArea = double.MaxValue;

            int n = convexHull.Count;

            // 遍历每一条边作为基准边
            for (int i = 0; i < n; i++)
            {
                Point edgeStart = convexHull[i];
                Point edgeEnd = convexHull[(i + 1) % n];

                // 计算当前边的角度
                double angle = Math.Atan2(edgeEnd.Y - edgeStart.Y, edgeEnd.X - edgeStart.X);

                // 将所有点绕原点旋转-angle角度，使当前边与x轴平行
                var rotatedPoints = convexHull.Select(p => RotatePoint(p, -angle)).ToList();

                // 找到包围盒
                int minX = rotatedPoints.Min(p => p.X);
                int maxX = rotatedPoints.Max(p => p.X);
                int minY = rotatedPoints.Min(p => p.Y);
                int maxY = rotatedPoints.Max(p => p.Y);

                // 计算面积
                double area = (maxX - minX) * (maxY - minY);

                // 如果面积更小，则更新最小矩形
                if (area < minArea)
                {
                    minArea = area;

                    // 构造矩形的四个顶点并旋转回原来的角度
                    var rectangle = new List<Point>
                    {
                         RotatePoint(new Point(minX, minY), angle),
                         RotatePoint(new Point(maxX, minY), angle),
                         RotatePoint(new Point(maxX, maxY), angle),
                         RotatePoint(new Point(minX, maxY), angle)
                    };

                    result.points = rectangle;
                    result.Angle = angle;
                    result.CenterPoint = RotatePoint(new Point((maxX + minX) / 2, (maxY + minY) / 2), angle);
                }
            }

            double l1 = CoefficientDistance(result.points[0], result.points[1]);
            double l2 = CoefficientDistance(result.points[1], result.points[2]);

            if (l1 < l2)
            {
                result.WidthPoints = new List<Point>
                {
                    result.points[0],
                    result.points[1],
                };
                result.HeightPoints = new List<Point>
                {
                    result.points[1],
                    result.points[2],
                };
            }
            else
            {
                result.WidthPoints = new List<Point>
                {
                    result.points[2],
                    result.points[1],
                };
                result.HeightPoints = new List<Point>
                {
                    result.points[1],
                    result.points[0],
                };
            }

            result.Height = Math.Max(l1, l2);
            result.Width = Math.Min(l1, l2);

            return result;
        }

        public List<Point> SortPointsByNearestNeighbor(List<Point> points)
        {
            if (points.Count <= 1) return points;

            var sorted = new List<Point>();
            var remaining = new HashSet<Point>(points);

            // 选择起始点（例如最左边的点）
            var current = remaining.OrderBy(p => p.X).First();
            sorted.Add(current);
            remaining.Remove(current);

            while (remaining.Any())
            {
                // 找到最近的点
                var nearest = remaining.OrderBy(p => Distance(current, p)).First();
                sorted.Add(nearest);
                remaining.Remove(nearest);
                current = nearest;
            }

            return sorted;
        }

        /// <summary>
        /// 绕原点旋转点
        /// </summary>
        /// <param name="point">待旋转的点</param>
        /// <param name="angle">旋转角度（弧度）</param>
        /// <returns>旋转后的点</returns>
        private static Point RotatePoint(Point point, double angle)
        {
            double cos = Math.Cos(angle);
            double sin = Math.Sin(angle);

            return new Point(
                (int)(point.X * cos - point.Y * sin),
                (int)(point.X * sin + point.Y * cos)
            );
        }

        /// <summary>
        /// 计算点到线段的距离
        /// </summary>
        /// <param name="a">线段点1</param>
        /// <param name="b">线段点2</param>
        /// <param name="c">点三</param>
        /// <returns></returns>
        private double DistanceToLine(Point a, Point b, Point c)
        {
            double area = Math.Abs(Area2(a, b, c));
            double baseLength = Distance(a, b);
            return area / baseLength;
        }

        // 计算向量叉积
        private int Cross(Point o, Point a, Point b) =>
            (a.X - o.X) * (b.Y - o.Y) - (a.Y - o.Y) * (b.X - o.X);

        // 计算三角形面积的两倍
        private int Area2(Point a, Point b, Point c) =>
            (b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X);

        // 计算两点间距离
        private double Distance(Point a, Point b)
        {
            int dx = a.X - b.X;
            int dy = a.Y - b.Y;
            return Math.Sqrt((dx * dx) + (dy * dy));
        }

        private double CoefficientDistance(Point a,Point b)
        {
            double dx = (a.X - b.X) * XCoefficient;
            double dy = (a.Y - b.Y) * YCoefficient;
            return Math.Sqrt((dx * dx) + (dy * dy));
        }

        private bool TryAdd(List<ActiveObjectClass> list, ActiveObjectClass item, int maxSize)
        {
            list.Add(item);
            if (list.Count > maxSize)
            {
                list[list.Count - maxSize].RowsData.Clear();
            }
            return true;
        }
        #endregion

        #region 线程方法
        /// <summary>
        /// 识别图像线程
        /// </summary>
        private void IdentifyImageProcess()
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            while (IsIdentify)
            {
                //判断队列中是否有数据
                if (IFrameDatas.Count() > 0)
                {
                    stopwatch.Restart();
                    if (IFrameDatas.Count() > 5)
                        //SystemAlarm.AlarmAlert(AlarmMessageList.待识别队列数据堆积, $"图像数据队列中数据过多，请及时处理！当前数据数量为：{IFrameDatas.Count()}", "DLL:ShuLIClass-IdentifyImageProcess");
                        FaultLog.RecordErrorMessage($"图像数据队列中数据过多，请及时处理！当前数据数量为：{IFrameDatas.Count()}");
                    //else
                        //SystemAlarm.AlarmCancel(AlarmMessageList.待识别队列数据堆积);
                    IFrameDatas.TryDequeue(out IImage IframeData);
                    stopwatch.Stop();
                    if (stopwatch.ElapsedMilliseconds > 5)
                    {
                        FaultLog.RecordErrorMessage($"ShuLiClass-IdentifyImageProcess:图像读取超时，此次识别耗时：{stopwatch.Elapsed}");
                    }
                    stopwatch.Restart();
                    //是否成功取得数据
                    if (IframeData != null)
                    {
                        //识别
                        ProcessImageSequence(IframeData);
                    }
                    else
                    {
                        Console.WriteLine("识别数据为空");
                        continue;
                    }
                    //输出耗时
                    stopwatch.Stop();
                    if(stopwatch.ElapsedMilliseconds > 5)
                    {
                        FaultLog.RecordErrorMessage($"ShuLiClass-IdentifyImageProcess:图像识别超时，此次识别耗时：{stopwatch.Elapsed}");
                    }
                    //Console.WriteLine($"识别线程识别一张图片耗时：{stopwatch.Elapsed},待识别队列剩余数量{IFrameDatas.Count()}");
                }
                else
                {
                    Thread.Sleep(1);
                }
            }
        }
        #endregion
    }
}
