private double GetDifferenceForTarget(MosaicTileColour tileColor, int i, Target target)
        {
            if (target == Target.Whole)
            {
                return(GetLibraryTileDifference(tileColor, i));
            }
            else
            {
                switch (target)
                {
                case Target.TL:
                    return(tileColor.AverageWhole.GetDifference(library[i].AverageTL));

                case Target.TR:
                    return(tileColor.AverageWhole.GetDifference(library[i].AverageTR));

                case Target.BL:
                    return(tileColor.AverageWhole.GetDifference(library[i].AverageBL));

                case Target.BR:
                    return(tileColor.AverageWhole.GetDifference(library[i].AverageBR));

                default:
                    return(GetLibraryTileDifference(tileColor, i));
                }
            }
        }
        public MosaicTileColour[,] CreateMap(Bitmap img)
        {
            int horizontalTiles = (int)img.Width / tileSize.Width;
            int verticalTiles   = (int)img.Height / tileSize.Height;

            var colorMap = new MosaicTileColour[horizontalTiles, verticalTiles];

            int tileWidth  = (img.Width - img.Width % horizontalTiles) / horizontalTiles;
            int tileHeight = (img.Height - img.Height % verticalTiles) / verticalTiles;

            // Explore option of making this a parallel for loop
            for (int x = 0; x < horizontalTiles; x++)
            {
                for (int y = 0; y < verticalTiles; y++)
                {
                    var xstart     = tileWidth * x;
                    var ystart     = tileHeight * y;
                    var tileColour = new MosaicTileColour();

                    // These are the opertaions to perform if we want to subdivide tile
                    tileColour.AverageTL    = getAverageTileColor(CreateQuadrantRectangle(xstart, ystart, tileWidth, tileHeight, Target.TL), img, quality);
                    tileColour.AverageTR    = getAverageTileColor(CreateQuadrantRectangle(xstart, ystart, tileWidth, tileHeight, Target.TR), img, quality);
                    tileColour.AverageBL    = getAverageTileColor(CreateQuadrantRectangle(xstart, ystart, tileWidth, tileHeight, Target.BL), img, quality);
                    tileColour.AverageBR    = getAverageTileColor(CreateQuadrantRectangle(xstart, ystart, tileWidth, tileHeight, Target.BR), img, quality);
                    tileColour.AverageWhole = getAverageTileColor(CreateQuadrantRectangle(xstart, ystart, tileWidth, tileHeight, Target.Whole), img, quality);
                    colorMap[x, y]          = tileColour;
                }
            }
            return(colorMap);
        }
        private double GetLibraryTileDifference(MosaicTileColour color, int i)
        {
            var differenceTL = color.AverageTL.GetDifference(library[i].AverageTL);
            var differenceTR = color.AverageTR.GetDifference(library[i].AverageTR);
            var differenceBL = color.AverageBL.GetDifference(library[i].AverageBL);
            var differenceBR = color.AverageBR.GetDifference(library[i].AverageBR);

            return(differenceTL + differenceTR + differenceBL + differenceBR);
        }
        // Passes the colour value for the current tile being analysed
        // Uses library which contains the average colour for all of the tile images
        private int GetBestImageIndex(MosaicTileColour tileColor, int x, int y, bool random, Target target)
        {
            double bestPercent = double.MaxValue;
            var    bestIndexes = new Dictionary <int, double>();

            bestIndexes.Add(-1, bestPercent);
            const byte offset = 7;
            double     difference;

            for (int i = 0; i < library.Count(); i++)
            {
                difference = GetDifferenceForTarget(tileColor, i, target);

                // as well as best diff store the 10th best diff and replace that item when necessary
                if (difference < bestPercent)
                {
                    Point point = new Point();

                    if (library[i].Data.Count > 0 && library[i].Data[0] != null)
                    {
                        point = (Point)library[i].Data[0];
                    }
                    if (point.IsEmpty)
                    {
                        bestIndexes.Add(i, difference);
                    }
                    else if (point.X + offset <= x && point.Y + offset > y && point.Y - offset < y)
                    {
                        bestIndexes.Add(i, difference);
                    }

                    // if length of dictionary is > 10 remove the largest value entry
                    if (bestIndexes.Count() > 10)
                    {
                        var maxValue = bestIndexes.Values.Max();
                        var maxKey   = bestIndexes.FirstOrDefault(v => v.Value == maxValue).Key;
                        bestIndexes.Remove(maxKey);
                    }

                    // update best percent to largest value in dictionary
                    bestPercent = bestIndexes.Values.Max();
                }
            }

            // Will remove the inital entry if still present
            if (bestIndexes.ContainsKey(-1))
            {
                bestIndexes.Remove(-1);
            }

            int index;

            if (random)
            {
                // Randomly select one of the best fit indexes
                index = bestIndexes.ElementAt(new Random().Next(0, bestIndexes.Count - 1)).Key;
            }
            else
            {
                var min = bestIndexes.Values.Min();
                index = bestIndexes.FirstOrDefault(v => v.Value == min).Key;
            }

            library[index].Data.Add(new Point(x, y));
            library[index].Difference = bestIndexes.GetValueOrDefault(index);
            return(index);
        }