// getTb:读数据库的sql
        // flag:false--操作tbGridPathloss, true--操作tbBuildingGridPathloss
        // 只有半径比较大的时候才会用到,因为一次算不完
        private void mergePwr1(double EIRP, string getTb, bool flag, int eNodeB, int CI)
        {
            Hashtable ht = new Hashtable();

            ht["CI"]     = CI;
            ht["eNodeB"] = eNodeB;
            DataTable tb = IbatisHelper.ExecuteQueryForDataTable(getTb, ht);

            GridCover gc = GridCover.getInstance();

            if (flag)
            {
                gc.deleteBuildingCover(ht);
            }
            else
            {
                gc.deleteGroundCover(ht);
            }

            Dictionary <string, GridStrength> gridStrengths = new Dictionary <string, GridStrength>();

            foreach (DataRow dataRow in tb.Rows)
            {
                #region 读入数据,按栅格分组,合并
                int GXID = int.Parse(dataRow["GXID"].ToString());
                int GYID = int.Parse(dataRow["GYID"].ToString());
                int GZID = 0;
                if (flag)
                {
                    GZID = int.Parse(dataRow["Level"].ToString());
                }

                string key = String.Format("{0},{1},{2}", GXID, GYID, GZID);

                if (!gridStrengths.ContainsKey(key))
                {
                    GridStrength gs = new GridStrength();
                    gs.GXID   = GXID;
                    gs.GYID   = GYID;
                    gs.Level  = GZID;
                    gs.eNodeB = int.Parse(dataRow["eNodeB"].ToString());
                    gs.CI     = int.Parse(dataRow["CI"].ToString());
                    if (dataRow["FieldIntensity"].ToString() != "")
                    {
                        gs.FieldIntensity = double.Parse(dataRow["FieldIntensity"].ToString());
                    }
                    gs.DirectNum       = int.Parse(dataRow["DirectPwrNum"].ToString());
                    gs.DirectPwrW      = double.Parse(dataRow["DirectPwrW"].ToString());
                    gs.MaxDirectPwrW   = double.Parse(dataRow["MaxDirectPwrW"].ToString());
                    gs.RefNum          = int.Parse(dataRow["RefPwrNum"].ToString());
                    gs.RefPwrW         = double.Parse(dataRow["RefPwrW"].ToString());
                    gs.MaxRefPwrW      = double.Parse(dataRow["MaxRefPwrW"].ToString());
                    gs.RefBuildingID   = dataRow["RefBuildingID"].ToString();
                    gs.DiffNum         = int.Parse(dataRow["DiffNum"].ToString());
                    gs.DiffPwrW        = double.Parse(dataRow["DiffPwrW"].ToString());
                    gs.MaxDiffPwrW     = double.Parse(dataRow["MaxDiffPwrW"].ToString());
                    gs.DiffBuildingID  = dataRow["DiffBuildingID"].ToString();
                    gs.BTSGridDistance = double.Parse(dataRow["BTSGridDistance"].ToString());
                    //gs.ReceivedPowerW = double.Parse(dataRow["ReceivedPowerW"].ToString());
                    //gs.ReceivedPowerdbm = double.Parse(dataRow["ReceivedPowerdbm"].ToString());
                    //gs.PathLoss = double.Parse(dataRow["PathLoss"].ToString());
                    if (flag)
                    {
                        gs.TransNum           = int.Parse(dataRow["TransNum"].ToString());
                        gs.TransPwrW          = double.Parse(dataRow["TransPwrW"].ToString());
                        gs.MaxTransPwrW       = double.Parse(dataRow["MaxTransPwrW"].ToString());
                        gs.TransmitBuildingID = dataRow["TransmitBuildingID"].ToString();
                    }
                    else
                    {
                        gs.TransNum           = 0;
                        gs.TransPwrW          = 0;
                        gs.MaxTransPwrW       = 0;
                        gs.TransmitBuildingID = "";
                    }
                    gridStrengths.Add(key, gs);
                }
                else
                {
                    GridStrength ogs = gridStrengths[key];

                    ogs.DirectNum += int.Parse(dataRow["DirectPwrNum"].ToString());
                    double pwr = double.Parse(dataRow["DirectPwrW"].ToString());
                    ogs.DirectPwrW += double.Parse(dataRow["DirectPwrW"].ToString());
                    if (ogs.MaxDirectPwrW < double.Parse(dataRow["MaxDirectPwrW"].ToString()))
                    {
                        ogs.MaxDirectPwrW = double.Parse(dataRow["MaxDirectPwrW"].ToString());
                    }

                    ogs.RefBuildingID += dataRow["RefBuildingID"].ToString();
                    ogs.RefNum        += int.Parse(dataRow["RefPwrNum"].ToString());
                    ogs.RefPwrW       += double.Parse(dataRow["RefPwrW"].ToString());
                    if (ogs.MaxRefPwrW < double.Parse(dataRow["MaxRefPwrW"].ToString()))
                    {
                        ogs.MaxRefPwrW = double.Parse(dataRow["MaxRefPwrW"].ToString());
                    }

                    ogs.DiffNum        += int.Parse(dataRow["DiffNum"].ToString());
                    ogs.DiffPwrW       += double.Parse(dataRow["DiffPwrW"].ToString());
                    ogs.DiffBuildingID += dataRow["DiffBuildingID"].ToString();
                    if (ogs.MaxDiffPwrW < double.Parse(dataRow["MaxDiffPwrW"].ToString()))
                    {
                        ogs.MaxDiffPwrW = double.Parse(dataRow["MaxDiffPwrW"].ToString());
                    }

                    if (flag)
                    {
                        ogs.TransNum           += int.Parse(dataRow["TransNum"].ToString());
                        ogs.TransPwrW          += double.Parse(dataRow["TransPwrW"].ToString());
                        ogs.TransmitBuildingID += dataRow["TransmitBuildingID"].ToString();
                        if (ogs.MaxTransPwrW < double.Parse(dataRow["MaxTransPwrW"].ToString()))
                        {
                            ogs.MaxTransPwrW = double.Parse(dataRow["MaxTransPwrW"].ToString());
                        }
                    }

                    //dictionary不能自动更新
                    gridStrengths[key] = ogs;
                }
                #endregion

                if (gridStrengths.Count > 30000)
                {
                    # region 计算栅格最终功率
                    foreach (var k in gridStrengths.Keys.ToArray())
                    {
                        GridStrength ogs = gridStrengths[k];
                        double       p   = ogs.DirectPwrW + ogs.DiffPwrW + ogs.RefPwrW + ogs.TransPwrW;
                        if (p > 0)
                        {
                            ogs.ReceivedPowerW = p;
                        }

                        ogs.ReceivedPowerdbm = convertw2dbm(ogs.ReceivedPowerW);
                        ogs.PathLoss         = EIRP - ogs.ReceivedPowerdbm;

                        //反射、绕射建筑物id去重
                        ogs.RefBuildingID      = DistinctStringArray(ogs.RefBuildingID.Split(';'));
                        ogs.DiffBuildingID     = DistinctStringArray(ogs.DiffBuildingID.Split(';'));
                        ogs.TransmitBuildingID = DistinctStringArray(ogs.TransmitBuildingID.Split(';'));

                        //dictionary 不能自动更新
                        gridStrengths[k] = ogs;
                    }
                    #endregion

                    #region   写入数据库
                    gc.convertToDt(gridStrengths);

                    if (flag)
                    {
                        gc.writeBuildingCover(ht);
                        gc.clearBuilding();
                    }
                    else
                    {
                        gc.wirteGroundCover(ht);
                        gc.clearGround();
                    }
                    #endregion

                    gridStrengths.Clear();
                }
            }
        /// <summary>
        /// 如果数据库表 tbAdjCoefficient 中有校正系数时,则界面中的校正系数仅仅被传入,而不会在计算场强中用到
        /// </summary>
        /// <returns></returns>
        public Result calc(bool loadInfo = false)
        {
            int    eNodeB = 0, CI = 0;
            string cellType = "";

            Result rt = validateCell(ref eNodeB, ref CI, ref cellType);

            if (!rt.ok)
            {
                return(rt);
            }

            CellInfo cellInfo = new CellInfo(this.cellName, eNodeB, CI, this.directCoeff, this.reflectCoeff, this.diffractCoeff, this.diffractCoeff2);

            double fromAngle = cellInfo.Azimuth - this.incrementAngle;
            double toAngle   = cellInfo.Azimuth + this.incrementAngle;

            ////指定最大覆盖半径
            //int maxCoverageRadius = 15000;
            //this.distance = Math.Min(this.distance, maxCoverageRadius);

            // 删除旧的接收功率数据
            Hashtable ht = new Hashtable();

            ht["CI"]     = CI;
            ht["eNodeB"] = eNodeB;
            GridCover gc = GridCover.getInstance();

            gc.deleteBuildingCover(ht);
            gc.deleteGroundCover(ht);

            // 计算方案
            int  threadCnt = 0, batchNum = 0, flag = 0;
            bool ok = howCalc(fromAngle, toAngle, ref threadCnt, ref batchNum, ref flag);

            this.threadNum = 2; threadCnt = 2;

            // 不需要分批计算
            if (ok)
            {
                List <ProcessArgs> paList = new List <ProcessArgs>();
                bool reRay       = false; // 是否需要进行二次投射,即读取前一批覆盖计算中出界的射线,并对其进行射线跟踪
                bool recordReRay = false; // 是否需要记录当前批的出界射线

                if (loadInfo)
                {
                    return(parallelComputing(ref cellInfo, fromAngle, toAngle, eNodeB, CI, ref paList, reRay, recordReRay, false, false, LoadInfo.UserId.Value, LoadInfo.taskName.Value));
                }
                else
                {
                    return(parallelComputing(ref cellInfo, fromAngle, toAngle, eNodeB, CI, ref paList, reRay, recordReRay, false, false, -1, "default"));
                }
                // 小区覆盖计算
            }
            // 需要分批计算
            else
            {
                IbatisHelper.ExecuteDelete("deleteSpecifiedReRay", ht);

                // 建议计算方案:线程数:threadCnt, 批数 batchNum
                if (flag == 2)
                {
                    this.threadNum = threadCnt;
                    //double delta = (toAngle - fromAngle + 360) % 360 / batchNum;

                    double delta = (toAngle - fromAngle) / batchNum;

                    double startAngle = fromAngle;

                    for (int currBatch = 1; currBatch <= batchNum; currBatch++)
                    {
                        //var batchTaskName = taskName + batchNum;

                        fromAngle = (startAngle + (currBatch - 1) * delta + 360) % 360;
                        toAngle   = (fromAngle + delta + 360) % 360;

                        List <ProcessArgs> paList = new List <ProcessArgs>();

                        bool reRay = false; // 是否需要进行二次投射,即读取前一批覆盖计算中出界的射线,并对其进行射线跟踪
                        if (currBatch > 1)  // 当前不是第一批,就需要进行二次投射
                        {
                            reRay = true;
                        }

                        bool recordReRay = false;  // 是否需要记录当前批的出界射线
                        if (currBatch < batchNum)  // 前批不是最后一批,则需记录当前批的出界射线,供下批二次投射
                        {
                            recordReRay = true;
                        }

                        // 小区覆盖计算
                        Result result = parallelComputing(ref cellInfo, fromAngle, toAngle, eNodeB, CI, ref paList, reRay, recordReRay, false, false, LoadInfo.UserId.Value, LoadInfo.taskName.Value);
                        if (!result.ok)
                        {
                            return(result);
                        }

                        // 分批计算的最后一批,需要对相同小区、相同栅格的功率进行合并
                        if (currBatch == batchNum)
                        {
                            mergePwr1(cellInfo.EIRP, "getPwrGround", false, eNodeB, CI);
                            mergePwr1(cellInfo.EIRP, "getPwrBuilding", true, eNodeB, CI);
                        }
                    }
                    return(new Result(true));
                }
                // 建议计算方案:线程数:threadCnt
                else
                {
                    this.threadNum = threadCnt;
                    List <ProcessArgs> paList = new List <ProcessArgs>();
                    bool reRay       = false; // 是否需要进行二次投射,即读取前一批覆盖计算中出界的射线,并对其进行射线跟踪
                    bool recordReRay = false; // 是否需要记录当前批的出界射线

                    return(parallelComputing(ref cellInfo, fromAngle, toAngle, eNodeB, CI, ref paList, reRay, recordReRay, false, false, LoadInfo.UserId.Value, LoadInfo.taskName.Value));
                }
            }
        }