private static void CreateCities(GATravellingSalesmanContoller GA, GATravellingSalesmanInput input)
        {
            GA.NumCities           = input.NumCities;
            GA.PopulationSize      = input.PopulationSize;
            GA.CrossoverPercentage = input.CrossoverPercentage;
            GA.MutationPercentage  = input.MutationPercentage;
            GA.NumIterations       = input.NumIterations;

            GA.ActualHeight = ActualHeight;
            GA.ActualWidth  = ActualWidth;

            GA.CreateRandom();
        }
        private static void DrawCities(Image canvas, GATravellingSalesmanContoller GA)
        {
            canvas.Mutate(ctx => ctx
                          .Fill(Color.White) // white background image
                          );
            for (int i = 0; i < GA.Cities.Count; i++)
            {
                var city           = GA.Cities[i];
                var dotSize        = i == 0 ? City.ClickRadius * 4 : City.ClickRadius * 2;
                var displayElement = new EllipsePolygon(city.X, city.Y, dotSize, dotSize);

                canvas.Mutate(ctx => ctx
                              .Fill(i == 0 ? Color.Red : Color.Green, displayElement));
            }
        }
        public static async Task <IActionResult> FindOptimisedPath(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "OptimisedPath")] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("Start a new optimisation job.");

            // string NumCities = req.Query["NumCities"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            var    input       = JsonConvert.DeserializeObject <GATravellingSalesmanInput>(requestBody);

            //=========run optimisation job
            var GA = new GATravellingSalesmanContoller();

            CreateCities(GA, input);
            var TraPathChosen = GA.SolveTrad();
            var GAPathChosen  = GA.SolveGA();
            //\===========
            var img = Draw();

            DrawCities(img, GA);
            DrawPath(img, GA, GAPathChosen, true);
            DrawPath(img, GA, TraPathChosen, false);
            var imgAsBase64 = "";

            using (var outputStream = new MemoryStream())
            {
                img.Save(outputStream, new JpegEncoder());
                var bytes = outputStream.ToArray();
                imgAsBase64 = Convert.ToBase64String(bytes);
            }

            var output = new GATravellingSalesmanOutput()
            {
                BestLength          = GAPathChosen.Length,
                NextNeighbourLength = TraPathChosen.Length,
                Image = imgAsBase64
            };

            return(new OkObjectResult(output));
        }
        private static void DrawPath(Image canvas, GATravellingSalesmanContoller GA, PathChosen path, bool optimised)
        {
            City firstCity = GA.Cities[0];

            PathBuilder pathBuilder = new PathBuilder();

            var points = new List <PointF>();

            points.Add(new PointF(firstCity.X, firstCity.Y));
            for (int i = 0; i < path.CityIndexes.Count; i++)
            {
                City city = GA.Cities[path.CityIndexes[i]];
                var  p    = new PointF(city.X, city.Y);
                points.Add(p);
            }

            pathBuilder.AddLines(points);
            pathBuilder.CloseFigure();
            IPath spath = pathBuilder.Build();

            canvas.Mutate(ctx => ctx
                          .Draw(optimised ? Color.Blue : Color.Gray, 3, spath));


            var font = SystemFonts.CreateFont("Arial", 39, FontStyle.Regular);
            var textGraphicsOptions = new TextGraphicsOptions(true);

            for (int i = 0; i < path.CityIndexes.Count; i++)
            {
                City city   = GA.Cities[path.CityIndexes[i]];
                var  p      = new PointF(city.X + (optimised ? -1 : 1) * City.ClickRadius * 4, city.Y);
                var  glyphs = TextBuilder.GenerateGlyphs((i + 1).ToString(), p, new RendererOptions(font, textGraphicsOptions.DpiX, textGraphicsOptions.DpiY));
                canvas.Mutate(ctx => ctx
                              .Fill((GraphicsOptions)textGraphicsOptions, optimised ? Color.Blue : Color.Gray, glyphs));
            }
        }