private void GenerateGraph(object sender, RoutedEventArgs e)
        {
            Start.IsEnabled = true;

            //Generujemy basic graf, który później nie będzie już zupełnie modyfikowany
            GraphGenerationMethods graphGenerator = new GraphGenerationMethods(_parameters);

            graphGenerator.GenerateBasicGraph();

            //Reset pareto, triangulation graph
            ParetoChart.ResetAll();
            _parameters.TriangulationOfGraph = new Graph(true);

            ResetZoomControl(BasicGraphZoomControl);
        }
        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 0; i < Pop_Size; i++)
            {
                Thread.Sleep((int)(Sleeper * 100));
                _parameters.ListOfPoints.Add(new ObservablePoint(trandom.NextDouble(F1LeftConstraint, F1RightConstraint),
                                                                 trandom.NextDouble(F2LeftConstraint, F2RightConstraint)
                                                                 ));
                DomainChart.EditBSeriesCollection(_parameters.ListOfPoints);
            }



            while (_parameters.IterationNumber < _parameters.IterationLimit && !_Stop)
            {
                // inicjalizacja tablic
                InitializePopulation(ref PopulationAfterSelection, Pop_Size / 2);
                InitializePopulation(ref PopulationAfterMutation, Pop_Size / 2);
                InitializePopulation(ref PopulationAfterCrossing, Pop_Size / 4);

                InitializePopulation(ref PopulationFunctionValue, Pop_Size);
                InitializePopulation(ref PopulationFunctionValueAfterSelection, Pop_Size / 2);
                InitializePopulation(ref PopulationFunctionValueAfterCrossing, Pop_Size / 4);

                // czas na obserwacje popsize'a i wykresu wartosci funkcji

                // wszystkie operacje wykonujemy na tablicy znajdujacej sie w Parameters   public double[][][] Population; // [2][popsize][popsize]

                FillRandomValues(ref Population);

                // operacja selekcji

                // 2 warianty i tutaj trzeba zrobic ze na zasadzie losowej jest wybierana metoda selekcji

                // selekcja turniejowa --> losujemy 2 punkty z populacji i wygrywa lepszy (o mniejszej wartosci),
                // dzielimy popsize na 2 rowne zbiory i jeden zbior jest porownywany wzgledem f1 a drugi wzgledem f2



                Selection(Population, ref PopulationAfterSelection);

                // parametr, aby w nastepnej iteracji uzupelnic brakujace osobniki w populacji
                refill = true;


                Function2ValueCountForAllPopulation(PopulationAfterSelection, ref PopulationFunctionValueAfterSelection);



                // selekcja ruletkowa --> obliczamy fitness, jaki to jest procent z calosci dla danego osobnika, obliczamy dystrybuante,
                // generujemy liczby losowe i szeregujemy okreslajac ktore elementy maja przetrwac

                // mozna tutaj juz wrzucic te osobniki na wykres dziedziny



                _parameters.RewriteThePoints(PopulationAfterSelection);

                DomainChart.EditASeriesCollection(_parameters.ListOfPoints);

                CheckDomain(ref PopulationOutsideTheDomain, PopulationAfterSelection);
                _parameters.RewriteThePoints(PopulationOutsideTheDomain);
                DomainChart.SetPointsOutsideTheDomain(_parameters.ListOfPoints);


                _parameters.RewriteThePoints(PopulationFunctionValueAfterSelection);
                ParetoChart.EditSeriesCollection(_parameters.ListOfPoints);

                ParetoChart.MakeParetoFunctions(FindMinAndMax(PopulationFunctionValueAfterSelection));

                CheckParetoDomain(ref PopulationOutsideTheDomain, PopulationFunctionValueAfterSelection);
                _parameters.RewriteThePoints(PopulationOutsideTheDomain);

                ParetoChart.SetPointsOutsideTheDomain(_parameters.ListOfPoints);



                MainChart.EditSeriesCollection(PopulationFunctionValueAfterSelection, _parameters.IterationNumber);

                // operacja
                Mutation(PopulationAfterSelection, ref PopulationAfterMutation);


                // losujemy ktore punkty zostana poddane mutacji (sprawdzamy wszystkie pod wzgledem prawdopodobienstwa) (prawdopodobienstwo mutacji dla kazdego osobnika)
                // jezeli wylosowano osobnika to losujemy kat oraz dlugosc wektora
                // sprawdzamy czy zmutowany osobnik znajduje sie w dziedzinie
                // jezeli nie wykorzystujemy funkcje kary aby zwiekszyc wartosc osobnika

                // mozna tutaj juz wrzucic te osobniki na wykres dziedziny


                // operacja krzyzowania
                // to jest chyba najtrudniejsza operacja, duzo pierdolenia z przeksztalceniami
                // ogolnie to staramy sie tak skrzyzowac aby np calkowicie odbic jeden punkt
                // do dyskusji jak to robimy

                Crossing(PopulationAfterMutation, ref PopulationAfterCrossing);

                // mozna tutaj juz wrzucic te osobniki na wykres dziedziny


                // obliczenie minimum
                SearchForMinValue(PopulationFunctionValueAfterSelection, ref MinF1, ref MinF2);

                _parameters.Minimum = $"{{{Math.Round(MinF1,2)};{Math.Round(MinF2,2)}}}";

                // przepisywanie tablicy PopulationAfterCrossing do Population

                Array.Clear(Population, 0, Population.Length);
                Array.Copy(PopulationAfterCrossing, Population, PopulationAfterCrossing.Length);

                // przepisywanie tablicy PopulationFunctionValueAfterCrossing do PopulationFunctionValue
                Array.Clear(PopulationFunctionValue, 0, PopulationFunctionValue.Length);
                Array.Copy(PopulationFunctionValueAfterCrossing, PopulationFunctionValue, PopulationFunctionValueAfterCrossing.Length);

                // czyszczenie tablic
                Array.Clear(PopulationAfterSelection, 0, PopulationAfterSelection.Length);
                Array.Clear(PopulationAfterMutation, 0, PopulationAfterMutation.Length);
                Array.Clear(PopulationAfterCrossing, 0, PopulationAfterCrossing.Length);

                Array.Clear(PopulationFunctionValueAfterSelection, 0, PopulationFunctionValueAfterSelection.Length);
                Array.Clear(PopulationFunctionValueAfterCrossing, 0, PopulationFunctionValueAfterCrossing.Length);

                // finalne utworzenie wykresu dziedziny oraz pareto frontu a takze wykresu wartosci poszczegolnych funkcji

                // jezeli przez 5 iteracji nie ma poprawy minimum zatrzymujemy algorytm

                // musimy obliczyc jeszcze to spierdolone odchylenie
                // suma po wszystkich punktach w populacji (od i do licznosci pareto frontu) |f(f1) - f2|

                _parameters.IterationNumber++;
                e.Cancel = true;
                Thread.Sleep(4000);
            }
        }