Esempio n. 1
0
        private void formRepairRange_Shown(object sender, EventArgs e)
        {
            comboBoxInterpolateMethod.SelectedIndex = 0;
            comboBoxRepairInterval.SelectedIndex    = 0;

            rangeQuality = Qualifier.ProcessRange(range);
            if (rangeQuality == null)
            {
                _ = MessageBox.Show(this, "Произошла ошибка при открытии ряда. Возможно, ряд слишком короткий", "Открытие ряда", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                this.Close();
                return;
            }

            labelCompletness.Text   = "Полнота ряда: " + (rangeQuality.Completeness * 100).ToString("0.00") + "%";
            labelMaxEmptySpace.Text = "Максимальный перерыв в измерениях: " + rangeQuality.MaxEmptySpace.TotalDays.ToString("0.000") + " дней";
            labelRangeLength.Text   = "Длительность ряда: " + range.Length.ToText();

            string dt;

            if (rangeQuality.Intervals.Count > 1)
            {
                StandartIntervals min = rangeQuality.Intervals.Min <RangeInterval, StandartIntervals>((i) => i.Interval);
                StandartIntervals max = rangeQuality.Intervals.Max <RangeInterval, StandartIntervals>((i) => i.Interval);
                dt = $"минимальный: {min.Description()}, максимальный: {max.Description()}";
            }
            else
            {
                dt = rangeQuality.Intervals[0].Interval.Description();
            }
            labelInterval.Text = "Δt: " + dt;
        }
Esempio n. 2
0
        /// <summary>
        /// объединяет два диапазона. Началом становится начало диапазона 1, а концом конец диапазона 2. За интервал принимается минимальный из двух
        /// </summary>
        /// <param name="rangeInterval1"></param>
        /// <param name="rangeInterval2"></param>
        /// <returns></returns>
        private static RangeInterval combineIntervals(RangeInterval rangeInterval1, RangeInterval rangeInterval2)
        {
            int i1 = (int)rangeInterval1.Interval;
            int i2 = (int)rangeInterval2.Interval;
            StandartIntervals inter = (StandartIntervals)Math.Min(i1, i2);

            return(new RangeInterval()
            {
                Diapason = new Diapason <DateTime>(rangeInterval1.Diapason.From, rangeInterval2.Diapason.To), Interval = inter
            });
        }
Esempio n. 3
0
        /// <summary>
        /// обработать ряд и получить сведения о полноте, интервалах, количестве ошибок
        /// </summary>
        /// <returns></returns>
        public static QualityInfo ProcessRange2(RawRange Range)
        {
            if (Range.Count < Vars.Options.QualifierSectionLength * 1.5)
            {
                return(null);
            }

            TimeSpan maxemptyspace = TimeSpan.MinValue;
            TimeSpan tmp;

            //поиск наибольшего пустого пропуска
            for (int i = 1; i < Range.Count; i++)
            {
                tmp = Range[i].Date - Range[i - 1].Date;
                if (tmp > maxemptyspace)
                {
                    maxemptyspace = tmp;
                }
            }

            //поиск всех интервалов измерений
            //весь ряд делится на отрезки по 10 измерений.
            //на каждом отрезке ищется минимальный интервал, он принимается основным для этого отрезка
            //если в ряде встречаются только такие интервалы, то весь ряд заносится в результат с одним интервалом
            //иначе границей раздела интервалов берётся гранича разделов отрезков с разными интервалами

            List <RawItem> range = new List <RawItem>(Range);

            range.Sort(new DateTimeComparerRawItem());

            //делим ряд по 10 измерений и для каждого отрезка находим минимальный интервал
            List <Diapason <int> >   diapasons = new List <Diapason <int> >();
            List <StandartIntervals> intervals = new List <StandartIntervals>();

            //int k = 0;
            for (int i = 0; i < range.Count - Vars.Options.QualifierSectionLength; i += Vars.Options.QualifierSectionLength)
            {
                Diapason <int> d       = new Diapason <int>(i, i + Vars.Options.QualifierSectionLength);
                TimeSpan       minSpan = TimeSpan.MaxValue;
                for (int j = i; j < i + Vars.Options.QualifierSectionLength; j++)
                {
                    // k++;
                    TimeSpan nsp = range[j].Date > range[j + 1].Date ? range[j].Date - range[j + 1].Date : range[j + 1].Date - range[j].Date;
                    if (nsp.TotalMinutes == 0)
                    {
                        continue;
                    }
                    if (nsp < minSpan && Enum.IsDefined(typeof(StandartIntervals), (int)nsp.TotalMinutes))
                    {
                        minSpan = nsp;
                    }
                }
                int minutes = (int)minSpan.TotalMinutes;
                StandartIntervals interval = (StandartIntervals)minutes;
                diapasons.Add(d);
                intervals.Add(interval);
            }

            //поиск изменений в интервалах
            //все диапазоны дат, которые меньше Vars.Options.QualifierDaysToNewInterval присоединяются к левой части ряда
            List <RangeInterval> rangeIntervals = new List <RangeInterval>();
            int s1 = 0, s2 = 0; //указатели на элементы в массиве intervals[] (начала первого и второго отрезка)

            for (int i = 0; i < intervals.Count - 1; i++)
            {
                if (intervals[i] != intervals[i + 1])
                {
                    int s2_min = (int)range[diapasons[s2].From].DateArgument;
                    int s1_min = (int)range[diapasons[s1].To].DateArgument;
                    int a1     = s1_min - s2_min; //длина первого отрезк в минутах

                    int si_min = (int)range[diapasons[i].To].DateArgument;
                    int a2     = si_min - s2_min;                                    //длина второго отрезк в минутах

                    int minimal = Vars.Options.QualifierDaysToNewInterval * 24 * 60; // длина минимального отрезка в минутах

                    if (s1 == s2)
                    {
                        s2 = i + 1;
                        continue;
                    }

                    if (a2 < minimal)
                    {
                        s2 = i + 1;
                        continue;
                    }



                    if (a2 > minimal && a1 > minimal) //если первый и второй отрезок больше минимального
                    {
                        //добавление первого отрезка (от s1 до s2)
                        DateTime          sd    = range[diapasons[s1].From].Date;
                        DateTime          ed    = range[diapasons[s2].To].Date;
                        StandartIntervals inter = intervals[s1];
                        //bool f = intervals[s1] == intervals[s2];
                        rangeIntervals.Add(new RangeInterval()
                        {
                            Diapason = new Diapason <DateTime>(sd, ed), Interval = inter
                        });
                        s1 = s2;
                        s2 = i + 1;
                    }
                    else //если второй отрезок меньше минимального, то переставляем начало второго отрезка (присоединяем второй отрезок к первому)
                    {
                        s2 = i + 1;
                    }
                }
            }

            //добавление последнего
            DateTime end = range.Last().Date; //конец диапазона
            DateTime start;

            if (rangeIntervals.Count > 0)
            {
                start = rangeIntervals.Last().Diapason.To;

                // если последний диапазон с таким же интервалом, как предпоследний, то обновляем последний добавленный интервал
                if (intervals.Last() == rangeIntervals.Last().Interval)
                {
                    rangeIntervals.Last().Diapason = new Diapason <DateTime>(start, end);
                }
                else
                {
                    rangeIntervals.Add(new RangeInterval()
                    {
                        Diapason = new Diapason <DateTime>(start, end), Interval = intervals.Last()
                    });                                                                                                                     // добавление диапазона
                }
            }
            else
            {
                start = range[0].Date;
                rangeIntervals.Add(new RangeInterval()
                {
                    Diapason = new Diapason <DateTime>(start, end), Interval = intervals.Last()
                });                                                                                                                     // добавление диапазона
            }

            QualityInfo res = new QualityInfo(rangeIntervals, maxemptyspace, range.Count);

            return(res);
        }
Esempio n. 4
0
        /// <summary>
        /// обработать ряд и получить сведения о полноте, интервалах, количестве ошибок
        /// </summary>
        /// <returns></returns>
        public static QualityInfo ProcessRange(RawRange Range)
        {
            if (Range.Count < Vars.Options.QualifierSectionLength * 1.5)
            {
                return(null);
            }

            TimeSpan maxemptyspace = TimeSpan.MinValue;
            TimeSpan tmp;

            //поиск наибольшего пустого пропуска
            for (int i = 1; i < Range.Count; i++)
            {
                tmp = Range[i].Date - Range[i - 1].Date;
                if (tmp > maxemptyspace)
                {
                    maxemptyspace = tmp;
                }
            }

            //поиск всех интервалов измерений
            //весь ряд делится на отрезки по 10 измерений.
            //на каждом отрезке ищется минимальный интервал, он принимается основным для этого отрезка
            //если в ряде встречаются только такие интервалы, то весь ряд заносится в результат с одним интервалом
            //иначе границей раздела интервалов берётся гранича разделов отрезков с разными интервалами

            List <RawItem> range = new List <RawItem>(Range);

            range.Sort(new DateTimeComparerRawItem());

            //делим ряд по 10 измерений и для каждого отрезка находим минимальный интервал
            List <Diapason <int> >   diapasons = new List <Diapason <int> >();
            List <StandartIntervals> intervals = new List <StandartIntervals>();

            //int k = 0;
            for (int i = 0; i < range.Count - Vars.Options.QualifierSectionLength; i += Vars.Options.QualifierSectionLength)
            {
                Diapason <int> d       = new Diapason <int>(i, i + Vars.Options.QualifierSectionLength);
                TimeSpan       minSpan = TimeSpan.MaxValue;
                for (int j = i; j < i + Vars.Options.QualifierSectionLength; j++)
                {
                    // k++;
                    TimeSpan nsp = range[j].Date > range[j + 1].Date ? range[j].Date - range[j + 1].Date : range[j + 1].Date - range[j].Date;
                    if (nsp.TotalMinutes == 0)
                    {
                        continue;
                    }
                    if (nsp < minSpan && Enum.IsDefined(typeof(StandartIntervals), (int)nsp.TotalMinutes))
                    {
                        minSpan = nsp;
                    }
                    if (nsp.TotalDays > Vars.Options.QualifierDaysToBeginMissing)
                    {
                        minSpan = TimeSpan.MaxValue;
                        break;
                    }
                }
                StandartIntervals interval;
                if (minSpan == TimeSpan.MaxValue)
                {
                    interval = StandartIntervals.Missing;
                }
                else
                {
                    int minutes = (int)minSpan.TotalMinutes;
                    interval = (StandartIntervals)minutes;
                }
                diapasons.Add(d);
                intervals.Add(interval);
            }

            //поиск изменений в интервалах и добавление в общий список
            List <RangeInterval> rangeIntervals = new List <RangeInterval>();
            int s1 = 0;

            for (int i = 0; i < intervals.Count - 1; i++)
            {
                if (intervals[i] != intervals[i + 1])
                {
                    DateTime          sd    = range[diapasons[s1].From].Date;
                    DateTime          ed    = range[diapasons[i].To].Date;
                    StandartIntervals inter = intervals[s1];
                    rangeIntervals.Add(new RangeInterval()
                    {
                        Diapason = new Diapason <DateTime>(sd, ed), Interval = inter
                    });
                    s1 = i + 1;
                }
            }

            //добавление последнего
            DateTime end = range.Last().Date; //конец диапазона
            DateTime start;

            if (rangeIntervals.Count > 0)
            {
                start = rangeIntervals.Last().Diapason.To;
            }
            else
            {
                start = range[0].Date;
            }
            rangeIntervals.Add(new RangeInterval()
            {
                Diapason = new Diapason <DateTime>(start, end), Interval = intervals.Last()
            });                                                                                                                     // добавление диапазона


            //обход всех найденных диапазонов и объединение маленьких или одинаковых до тех пор, пока будет совершено хоть одно объединение
            int  minimal  = Vars.Options.QualifierDaysToNewInterval * 24 * 60;
            bool hasCompl = true;

            while (hasCompl)
            {
                //если диапазонов нет или один, то выходим
                if (rangeIntervals.Count == 0 || rangeIntervals.Count == 1)
                {
                    break;
                }

                //если диапазонов два, то ищем маленький диапазон в конце и в начале
                if (rangeIntervals.Count == 2)
                {
                    if (rangeIntervals[0].LengthMinutes < minimal || rangeIntervals[1].LengthMinutes < minimal) //объединяем диапазоны и выходим
                    {
                        RangeInterval ri = combineIntervals(rangeIntervals[0], rangeIntervals[1]);
                        rangeIntervals.Clear();
                        rangeIntervals.Add(ri);
                        hasCompl = true;
                        continue;
                    }
                    break;
                }

                //если больше двух диапазонов, то пробуем объединить все маленькие диапазоны
                hasCompl = false;
                for (int i = 1; i < rangeIntervals.Count - 1; i++)
                {
                    RangeInterval r1 = rangeIntervals[i - 1];
                    RangeInterval ri = rangeIntervals[i];
                    RangeInterval r2 = rangeIntervals[i + 1];

                    int i1 = (int)r1.Interval;
                    int ii = (int)ri.Interval;
                    int i2 = (int)r2.Interval;

                    int l1 = r1.LengthMinutes;
                    int li = ri.LengthMinutes;
                    int l2 = r2.LengthMinutes;

                    #region объединение диапазонов с одинаковым интервалом

                    if (i1 == ii) //если у левого и среднего диапазона интервалы одинаковые
                    {
                        RangeInterval rr = combineIntervals(r1, ri);
                        rangeIntervals.Remove(ri);
                        rangeIntervals.Remove(r1);
                        rangeIntervals.Insert(i - 1, rr);
                        hasCompl = true;
                        break;
                    }

                    if (ii == i2) //если у правого и среднего диапазона интервалы одинаковые
                    {
                        RangeInterval rr = combineIntervals(ri, r2);
                        rangeIntervals.Remove(ri);
                        rangeIntervals.Remove(r2);
                        rangeIntervals.Insert(i - 1, rr);
                        hasCompl = true;
                        break;
                    }

                    #endregion

                    #region объединение диапазонов, меньших, чем минимальный

                    if (l1 < minimal) //если левый меньше минимального, то объединяем с средним
                    {
                        RangeInterval rr = combineIntervals(r1, ri);
                        rangeIntervals.Remove(ri);
                        rangeIntervals.Remove(r1);
                        rangeIntervals.Insert(i - 1, rr);
                        hasCompl = true;
                        break;
                    }

                    if (li < minimal) //если средний меньше минимального, то объединяем с тем, у кого меньше интервал
                    {
                        if (i1 < i2)  //если левый интервал меньше правого
                        {
                            RangeInterval rr = combineIntervals(r1, ri);
                            rangeIntervals.Remove(ri);
                            rangeIntervals.Remove(r1);
                            rangeIntervals.Insert(i - 1, rr);
                            hasCompl = true;
                            break;
                        }
                        if (i1 > i2) //если правый интервал меньше правого
                        {
                            RangeInterval rr = combineIntervals(ri, r2);
                            rangeIntervals.Remove(ri);
                            rangeIntervals.Remove(r2);
                            rangeIntervals.Insert(i - 1, rr);
                            hasCompl = true;
                            break;
                        }
                        if (i1 == i2)//если интервалы равны, то объединяем всех троих
                        {
                            RangeInterval rr = combineIntervals(r1, r2);
                            rangeIntervals.Remove(r1);
                            rangeIntervals.Remove(ri);
                            rangeIntervals.Remove(r2);
                            rangeIntervals.Insert(i - 1, rr);
                            hasCompl = true;
                            break;
                        }
                    }

                    if (l2 < minimal && i == rangeIntervals.Count - 1) //если правый меньше минимального и это последний элемент, то объединяем с средним
                    {
                        RangeInterval rr = combineIntervals(ri, r2);
                        rangeIntervals.Remove(ri);
                        rangeIntervals.Remove(r2);
                        rangeIntervals.Insert(i - 1, rr);
                        hasCompl = true;
                        break;
                    }

                    #endregion
                }
            }



            QualityInfo res = new QualityInfo(rangeIntervals, maxemptyspace, range.Count);
            return(res);
        }
Esempio n. 5
0
 protected BaseInterpolateMethod(StandartIntervals from, StandartIntervals to)
 {
     FromInterval = from;
     ToInterval   = to;
 }
Esempio n. 6
0
        /// <summary>
        /// восстановить ряд до нужного интревала наблюдений
        /// </summary>
        /// <param name="range">Ряд для восстановления</param>
        /// <param name="param">параметры восстановления</param>
        /// <param name="actionPercent">изменение процента выполнения</param>
        /// <param name="actionAfter">действие после обработки</param>
        /// <returns></returns>
        public Task <RawRange> ProcessRange(RawRange range, RestorerParameters param, Action <int, string> actionPercent, Action <RawRange, RawRange, double> actionAfter)
        {
            RawRange baseRange = null;//ряд, на основе которого будет идти восстановление

            range.PerformRefreshQuality();
            Range              = new RawRange(range.OrderBy(x => x.Date).ToList());
            this.param         = param;
            this.actionPercent = actionPercent;
            prepareIterpolators();


            //расчет каждого значения
            Task <RawRange> tsk = new Task <RawRange>(() =>
            {
                ConcurrentBag <RawItem> resultCollection = new ConcurrentBag <RawItem>();
                Parallel.ForEach(newRangeX, (p) =>
                {
                    incrementCounter();

                    StandartIntervals currentInterval = getIntervalOfDateArgument(p, range);
                    if (currentInterval == StandartIntervals.None)
                    {
                        throw new WindEnergyException("Что-то не так. Не удалось найти интервал наблюдений");
                    }

                    double speed, direct, temp, wet, press;
                    //если целевой интервал меньше текущего, то интерполируем как обычно
                    if ((int)currentInterval >= (int)param.Interval || param.Method == InterpolateMethods.NearestMeteostation)
                    {
                        speed  = methodSpeeds.GetValue(p);
                        direct = methodDirects.GetValue(p);
                        temp   = methodTemp.GetValue(p);
                        wet    = methodWet.GetValue(p);
                        press  = methodPress.GetValue(p);
                    }
                    else         //Если целевой интервал больше текущего, то надо осреднять значения за целевой интервал
                    {
                        DateTime from = new DateTime().AddMinutes(p - (int)param.Interval);
                        DateTime to   = new DateTime().AddMinutes(p);
                        RawRange part = range.GetRange(true, false, from, to, null, null);
                        if (part.Count == 0)
                        {
                            speed  = methodSpeeds.GetValue(p);
                            direct = methodDirects.GetValue(p);
                            temp   = methodTemp.GetValue(p);
                            wet    = methodWet.GetValue(p);
                            press  = methodPress.GetValue(p);
                        }
                        else
                        {
                            speed  = part.Average(item => item.Speed);
                            direct = part.Average(item => item.Direction > 0 ? item.Direction : 0);
                            temp   = part.Average(item => item.Temperature);
                            wet    = part.Average(item => item.Wetness);
                            press  = part.Average(item => item.Pressure);
                        }
                    }
                    if (double.IsNaN(speed))
                    {
                        return;
                    }
                    if (speed < 0)
                    {
                        speed = 0;
                    }

                    resultCollection.Add(new RawItem(p, speed, direct, temp, wet, press));
                });

                RawRange res     = new RawRange(resultCollection.OrderBy(item => item.DateArgument));
                res.Position     = range.Position;
                res.Meteostation = range.Meteostation;
                res.Height       = range.Height;
                if (actionAfter != null)
                {
                    actionAfter.Invoke(res, baseRange, r);
                }
                return(res);
            });

            tsk.Start();
            return(tsk);
        }
Esempio n. 7
0
        /// <summary>
        /// кнопка восстановить ряд
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonRepairRange_Click(object sender, EventArgs e)
        {
            Cursor = Cursors.WaitCursor;
            InterpolateMethods   method   = (InterpolateMethods)(new EnumTypeConverter <InterpolateMethods>().ConvertFrom(comboBoxInterpolateMethod.SelectedItem));
            StandartIntervals    interval = (StandartIntervals)(new EnumTypeConverter <StandartIntervals>().ConvertFrom(comboBoxRepairInterval.SelectedItem));
            Action <int, string> action   = new Action <int, string>((percent, text) =>
            {
                try
                {
                    if (this.InvokeRequired)
                    {
                        _ = Invoke(new Action(() =>
                        {
                            progressBarStatus.Value = percent;
                        }));
                    }
                    else
                    {
                        progressBarStatus.Value = percent;
                    }
                }
                catch (Exception) { }
            });

            Action <RawRange, RawRange, double> actionAfter = new Action <RawRange, RawRange, double>((resultRange, baseRange, r) =>
            {
                _ = this.Invoke(new Action(() =>
                {
                    string additionalText = "";

                    if (method == InterpolateMethods.NearestMeteostation)     //для восстановления ряда выводим доп. информацию
                    {
                        //Информация о коэфф корреляции и базовом ряде
                        if (double.IsNaN(r))
                        {
                            additionalText += "Восстановление проводилось на основе ряда наблюдений, заданного пользователем\r\n";
                        }
                        else
                        {
                            additionalText += $"Восстановление проводилось на основе ряда наблюдений {(baseRange.Meteostation != null ? $" на МС {baseRange.Meteostation.Name} " : "")}с коэффициентом корреляции {r:0.00} \r\n";
                        }
                        //предупреждение, что не все данные восстановлены
                        RangeInterval baseInterval = baseRange.Quality.Intervals.OrderByDescending((i) => i.LengthMinutes).First(); //выбираем самый длинный интервал наблюдений в базовом ряде
                        if (baseInterval.LengthMinutes > (int)interval)                                                             //если максимальный интервал базового ряда больше, чем требуемый интервал восстановления
                        {
                            additionalText += $"\r\nВнимание!! Интервал наблюдений ряда, на основе которого производилось восстановление ({baseInterval.Interval.Description()}), больше, чем требуемый интервал. Поэтому не удалось восстановить все значения ряда до {interval.Description()}\r\n";
                        }
                    }

                    resultRange.Name = "Восстановленный ряд до интервала" + interval.Description();
                    _ = MessageBox.Show(this, $"Ряд восстановлен до интервала {interval.Description()}\r\n{additionalText}", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);

                    if (resultRange == null)
                    {
                        DialogResult = DialogResult.Cancel;
                    }
                    else
                    {
                        DialogResult = DialogResult.OK;
                        Result       = resultRange;
                    }
                    Cursor = Cursors.Arrow;
                    Result = resultRange;
                    Close();
                }));
            });

            try
            {
                //если выбрана ступенчатый метод или линейная интерполяция и в ряде есть пропуски больше, чем 1 интервал, то надо уточнить у пользователя
                if ((method == InterpolateMethods.Linear || method == InterpolateMethods.Stepwise) && rangeQuality.MaxEmptySpace.TotalMinutes > ((int)interval))
                {
                    if (MessageBox.Show(this, "Ряд содержит пропуски данных больше, чем один выбранный интервал наблюдений.\r\nВ таком случае не рекомендуется использовать линейную интерполяцию и ступенчатое восстановление.\r\nВы уверены, что хотите продолжить восстановление?", "Восстановление ряда", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                    {
                        return;
                    }
                }

                RawRange baseRange = null;
                if (method == InterpolateMethods.NearestMeteostation)
                {
                    if (radioButtonSelPoint.Checked)
                    {
                        if (range.Position.IsEmpty)
                        {
                            FormSelectMapPointDialog fsp = new FormSelectMapPointDialog("Выберите координаты ряда " + range.Name, PointLatLng.Empty, Vars.Options.CacheFolder, Resources.rp5_marker, Vars.Options.MapProvider);
                            if (fsp.ShowDialog(this) == DialogResult.OK)
                            {
                                range.Position = fsp.Result;
                            }
                            else
                            {
                                Cursor = Cursors.Arrow;
                                return;
                            }
                        }
                    }
                    else
                    {
                        baseRange = Program.winMain.mainHelper.OpenFile(this);
                        if (baseRange == null)
                        {
                            Cursor = Cursors.Arrow;
                            return;
                        }
                    }
                }
                _ = new Restorer().ProcessRange(range, new RestorerParameters()
                {
                    Interval    = interval,
                    Method      = method,
                    Coordinates = range.Position,
                    BaseRange   = baseRange,
                    ReplaceExistMeasurements = checkBoxReplaceExist.Checked
                }, action, actionAfter);
            }
            catch (WebException exc)
            {
                Cursor       = Cursors.Arrow;
                _            = MessageBox.Show(this, exc.Message, "Восстановление ряда", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                DialogResult = DialogResult.Cancel;
            }
            catch (WindEnergyException wex)
            {
                Cursor       = Cursors.Arrow;
                _            = MessageBox.Show(this, wex.Message, "Восстановление ряда", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                DialogResult = DialogResult.Cancel;
            }
            catch (ApplicationException exc)
            {
                Cursor       = Cursors.Arrow;
                _            = MessageBox.Show(this, exc.Message + "\r\nПопробуйте уменьшить длину ряда", "Восстановление ряда", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                DialogResult = DialogResult.Cancel;
            }
        }