// Расчет натяжения спиц.
        /// <summary>
        /// Расчет натяжения спиц.
        /// </summary>
        /// <param name="dataGridView">DataGridView на котором расположены элементы с Tm1Reading.</param>
        /// <param name="groupBox">GroupBox на котором расположены элементы с Tm1Reading.</param>
        /// <param name="controlsNameTm1Reading">Имя элементов с Tm1Reading.</param>
        /// <returns>Массив натяжения спиц.</returns>
        public float[] CalculateTensionKgf(DataGridView dataGridView, GroupBox groupBox, string controlsNameTm1Reading)
        {
            // Объект FormControls.
            var formControl = new FormControls();

            // Массив натяжения спиц в кгс.
            var tensionKgf = new List <float>();

            // Значения из таблицы DataGridView.
            List <string[]> dataGridViewValues = formControl.GetDataGridViewValues(dataGridView);

            // Массив TM-1 Reading.
            List <string> tensions = formControl.GetValuesFromGroupControls(groupBox, controlsNameTm1Reading).Values.ToList();

            // Определение силы натяжения спицы по TM-1 Reading в таблице DataGridView.
            foreach (string tension in tensions)
            {
                // Найдено ли натяжение в таблице DataGridView.
                bool isFound = false;

                for (int j = 0; j < dataGridViewValues[0].Length; j++)
                {
                    // TM-1 Reading из таблицы DataGridView.
                    string tensionFromTable = dataGridViewValues[0][j];

                    // Если указанный TM-1 Reading найден в таблице DataGridView, то добавляем натяжение в кгс в массив.
                    if (tension == tensionFromTable)
                    {
                        isFound = true;
                        tensionKgf.Add(float.Parse(dataGridViewValues[1][j]));
                    }
                }

                if (!isFound)
                {
                    tensionKgf.Add(0);
                }
            }

            return(tensionKgf.ToArray());
        }
        // Определение выхода натяжения спицы за границы допустимого интервала.
        /// <summary>
        /// Определение выхода натяжения спицы за границы допустимого интервала.
        /// </summary>
        /// <param name="groupBox">GroupBox на котором размещены элементы с TensionKgf.</param>
        /// <param name="controlOffset">Элемент от которого будет произведен отступ иконки выхода натяжения спицы за границы допустимого интервала.</param>
        /// <param name="errorProvider">ErrorProvider.</param>
        /// <param name="controlsName">Имя элементов с натяжением спиц.</param>
        /// <param name="lowerTensionLimit">Нижняя граница допустимого интервала натяжения.</param>
        /// <param name="upperTensionLimit">Верхняя граница допустимого интервала натяжения.</param>
        public void SetWithinTensionLimit(
            GroupBox groupBox,
            Control controlOffset,
            ErrorProvider errorProvider,
            string controlsName,
            double lowerTensionLimit,
            double upperTensionLimit)
        {
            // Установка иконки выхода натяжения спицы за границы допустимого интервала.
            errorProvider.Icon = icons.ErrorProviderError;

            // Объект FormControls.
            FormControls formControl = new FormControls();

            // Массив натяжения спиц в кгс.
            Dictionary <Control, string> tensionsKgf = formControl.GetValuesFromGroupControls(groupBox, controlsName);

            // Иконка для отображения выхода натяжения за границы интервала.
            errorProvider.Icon = icons.ErrorProviderError;

            foreach (KeyValuePair <Control, string> tensionKgf in tensionsKgf)
            {
                // Определение допуска натяжения спиц.
                var withinTensionLimit = isWithinTensionLimit(int.Parse(tensionKgf.Value), lowerTensionLimit, upperTensionLimit);

                // Установка отступа иконки от контрола.
                errorProvider.SetIconPadding(tensionKgf.Key, +(controlOffset.Size.Width / 2));

                // Формирование сообщения об ошибке.
                var errorMessage = "";

                if (!withinTensionLimit)
                {
                    errorMessage = "Outside limit";
                }

                // Установка ошибки.
                errorProvider.SetError(tensionKgf.Key, errorMessage);
            }
        }
        // Проведение расчетов и построение графиков.
        /// <summary>
        /// Проведение расчетов и построение графиков.
        /// </summary>
        /// <param name="sender">Ссылка на элемент/объект, который вызвал это событие.</param>
        /// <param name="e">Данные события.</param>
        private void calculateButton_Click(object sender, EventArgs e)
        {
            // Получение значение количества спиц левой стороны колеса.
            var leftSideSpokeCountComboBoxSelected = leftSideSpokeCountComboBox.GetItemText(leftSideSpokeCountComboBox.SelectedItem);
            // Получение значение количества спиц ghfdjq стороны колеса.
            var rightSideSpokeCountComboBoxSelected = rightSideSpokeCountComboBox.GetItemText(rightSideSpokeCountComboBox.SelectedItem);

            // Если количество спиц не выбрано, то выводим сообщение об ошибке.
            if (String.IsNullOrEmpty(leftSideSpokeCountComboBoxSelected) || String.IsNullOrEmpty(rightSideSpokeCountComboBoxSelected))
            {
                MessageBox.Show("Number of spokes not selected!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            else
            {
                // Если количество спиц на левой и правой стороне колеса не совпадают, то выводим сообщение об ошибке.
                if (leftSideSpokeCountComboBoxSelected != rightSideSpokeCountComboBoxSelected)
                {
                    MessageBox.Show("Your wheel isn't symmetrical!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }

                // Массив TM-1 Reading спиц левой стороны колеса.
                List <float> leftSideSpokesTm1 = formControl.GetValuesFromGroupControls(
                    leftSideSpokesGroupBox,
                    "leftSideSpokesTm1ReadingNumericUpDown").Select(x => float.Parse(x.Value)).ToList();

                // Массив TM-1 Reading спиц правой стороны колеса.
                List <float> rightSideSpokesTm1 = formControl.GetValuesFromGroupControls(
                    rightSideSpokesGroupBox,
                    "rightSideSpokesTm1ReadingNumericUpDown").Select(x => float.Parse(x.Value)).ToList();

                // Углы положения спиц левой стороны колеса.
                List <float> leftSpokesAngles = parameterCalculations.CalculateSpokeAngles(byte.Parse(leftSideSpokeCountComboBox.Text));
                // Углы положения спиц правой стороны колеса.
                List <float> rightSpokesAngles = parameterCalculations.CalculateSpokeAngles(byte.Parse(rightSideSpokeCountComboBox.Text));

                // Массив силы натяжения спиц левой стороны колеса.
                float[] leftSideSpokesTensionKgf = parameterCalculations.CalculateTensionKgf(
                    conversionTableGridView,
                    leftSideSpokesGroupBox,
                    "leftSideSpokesTm1ReadingNumericUpDown");

                // Массив силы натяжения спиц правой стороны колеса.
                float[] rightSideSpokesTensionKgf = parameterCalculations.CalculateTensionKgf(
                    conversionTableGridView,
                    rightSideSpokesGroupBox,
                    "rightSideSpokesTm1ReadingNumericUpDown");

                // Очистка диаграммы.
                spokeTensionChart.Series.Clear();

                // Расчет масштаба графика.
                spokeTensionChart.ChartAreas["ChartArea"].AxisY.Maximum = new List <float> {
                    leftSideSpokesTm1.Max(), rightSideSpokesTm1.Max()
                }.Max() * 2.0;

                // Установка рассчитанного натяжения спиц левой стороны колеса.
                formControl.SetValuesToGroupControlsText(
                    leftSideSpokesGroupBox,
                    "leftSideSpokesTensionTextBox",
                    leftSideSpokesTensionKgf.Select(x => x.ToString()).ToArray());

                // Установка рассчитанного натяжения спиц правой стороны колеса.
                formControl.SetValuesToGroupControlsText(
                    rightSideSpokesGroupBox,
                    "rightSideSpokesTensionTextBox",
                    rightSideSpokesTensionKgf.Select(x => x.ToString()).ToArray());

                // Отрисовка графика.
                tensionChart.DrawTension(spokeTensionChart, "Left Side Spokes", leftSpokesAngles, leftSideSpokesTm1);
                tensionChart.DrawTension(spokeTensionChart, "Right Side Spokes", rightSpokesAngles, rightSideSpokesTm1);

                // Расчет среднего натяжения спиц всего колеса.
                string averageWheelSpokeTension = Math.Round(leftSideSpokesTensionKgf.Concat(rightSideSpokesTensionKgf).ToArray().Average(), 2).ToString();

                averageWheelSpokeTensionLeftTextBox.Text  = averageWheelSpokeTension;
                averageWheelSpokeTensionRightTextBox.Text = averageWheelSpokeTension;

                // Расчет стандартного отклонения натяжения спиц.
                standartDevLeftSpokesTensionTextBox.Text  = Math.Round(parameterCalculations.StdDev(leftSideSpokesTensionKgf.ToList()), 2).ToString();
                standartDevRightSpokesTensionTextBox.Text = Math.Round(parameterCalculations.StdDev(rightSideSpokesTensionKgf.ToList()), 2).ToString();

                // Расчет среднего натяжения спиц.
                averageLeftSpokesTensionTextBox.Text  = Math.Round(leftSideSpokesTensionKgf.Average(), 2).ToString();
                averageRightSpokesTensionTextBox.Text = Math.Round(rightSideSpokesTensionKgf.Average(), 2).ToString();

                // Допустимое натяжение спиц.
                int variance = varianceTrackBar.Value;

                // Расчет границ натяжения спиц.
                leftSpokesLowerTensionLimitTextBox.Text = Math.Round(parameterCalculations.TensionLimit(
                                                                         double.Parse(averageLeftSpokesTensionTextBox.Text), variance, true), 2).ToString();

                leftSpokesUpperTensionLimitTextBox.Text = Math.Round(parameterCalculations.TensionLimit(
                                                                         double.Parse(averageLeftSpokesTensionTextBox.Text), variance, false), 2).ToString();

                rightSpokesLowerTensionLimitTextBox.Text = Math.Round(parameterCalculations.TensionLimit(
                                                                          double.Parse(averageRightSpokesTensionTextBox.Text), variance, true), 2).ToString();

                rightSpokesUpperTensionLimitTextBox.Text = Math.Round(parameterCalculations.TensionLimit(
                                                                          double.Parse(averageRightSpokesTensionTextBox.Text), variance, false), 2).ToString();

                // Нижняя граница силы натяжения спиц левой стороны колеса.
                var leftSpokesLowerTensionLimit = double.Parse(leftSpokesLowerTensionLimitTextBox.Text);
                // Верхняя граница силы натяжения спиц левой стороны колеса.
                var leftSpokesUpperTensionLimit = double.Parse(leftSpokesUpperTensionLimitTextBox.Text);
                // Нижняя граница силы натяжения спиц правой стороны колеса.
                var rightSpokesLowerTensionLimit = double.Parse(rightSpokesLowerTensionLimitTextBox.Text);
                // Верхняя граница силы натяжения спиц правой стороны колеса.
                var rightSpokesUpperTensionLimit = double.Parse(rightSpokesUpperTensionLimitTextBox.Text);

                // Определение выхода силы натяжения за границы допустимого интервала спиц левой стороны колеса.
                parameterCalculations.SetWithinTensionLimit(
                    leftSideSpokesGroupBox,
                    withinTensionLimitLeftSpokesLabel,
                    errorProviderTensionLimitError,
                    "leftSideSpokesTensionTextBox",
                    leftSpokesLowerTensionLimit,
                    leftSpokesUpperTensionLimit);

                // Определение выхода силы натяжения за границы допустимого интервала спиц правой стороны колеса.
                parameterCalculations.SetWithinTensionLimit(
                    rightSideSpokesGroupBox,
                    withinTensionLimitRightSpokesLabel,
                    errorProviderTensionLimitError,
                    "rightSideSpokesTensionTextBox",
                    rightSpokesLowerTensionLimit,
                    rightSpokesUpperTensionLimit);
            }
        }