Example #1
0
 public static bool IsInRange <T>(this T[,] array, Vector2i pos)
 {
     return(pos.x >= 0 && pos.y >= 0 &&
            pos.x < array.GetLength(0) && pos.y < array.GetLength(1));
 }
Example #2
0
 public static void Set <T>(this T[,] array, Vector2i pos, T newVal)
 {
     array[pos.x, pos.y] = newVal;
 }
Example #3
0
 public static T Get <T>(this T[,] array, Vector2i pos)
 {
     return(array[pos.x, pos.y]);
 }
Example #4
0
        /// <summary>
        /// For every output pixel in the given region that isn't set yet,
        ///     this method recalculates that pixel's
        ///     "ApplicableColorFrequencies" and "VisualizedColor" fields.
        /// </summary>
        public void RecalculatePixelChances(Vector2i startAreaInclusive, Vector2i endAreaExclusive)
        {
            var outputPosFilter   = OutputPosFilter;
            var outputColorGetter = OutputColorGetter;

            foreach (Vector2i _pixelPos in new Vector2i.Iterator(startAreaInclusive,
                                                                 endAreaExclusive))
            {
                Vector2i pixelPos = outputPosFilter(_pixelPos);

                //If the position is outside the output, or the pixel is already set, don't bother.
                if (!Output.IsInRange(pixelPos) || Output.Get(pixelPos).FinalValue.HasValue)
                {
                    continue;
                }

                var pixel = Output.Get(pixelPos);

                //Find any colors that, if placed here, would cause a violation of the WFC constraint.
                HashSet <Color> badColors = new HashSet <Color>();
                foreach (Color color in Input.ColorFrequencies.Keys)
                {
                    //Assume that the color is placed.
                    Func <Vector2i, Color?> newOutputColorGetter = (outputPos) =>
                    {
                        Vector2i filteredOutputPos = outputPosFilter(outputPos);
                        if (filteredOutputPos == pixelPos)
                        {
                            return(color);
                        }
                        else if (Output.IsInRange(filteredOutputPos))
                        {
                            return(Output.Get(filteredOutputPos).FinalValue);
                        }
                        else
                        {
                            return(null);
                        }
                    };

                    //Test the constraint: any NxM pattern in the output
                    //    appears at least once in the input.
                    Vector2i minNearbyPixelPos = pixelPos - Input.MaxPatternSize + 1,
                             maxNearbyPixelPos = pixelPos;
                    foreach (Vector2i nearbyAffectedPixelPos in new Vector2i.Iterator(minNearbyPixelPos,
                                                                                      maxNearbyPixelPos + 1))
                    {
                        if (!Input.Patterns.Any(pattern => pattern.DoesFit(nearbyAffectedPixelPos,
                                                                           newOutputColorGetter)))
                        {
                            badColors.Add(color);
                            break;
                        }
                    }
                }

                //Check which patterns can be applied at which positions around this pixel.
                pixel.ApplicableColorFrequencies.Clear();
                foreach (Pattern pattern in Input.Patterns)
                {
                    Vector2i patternSize  = pattern.Values.SizeXY();
                    var      patternPoses = new Vector2i.Iterator(pixelPos - patternSize + 1,
                                                                  pixelPos + 1);
                    foreach (Vector2i patternMinCornerPos in patternPoses)
                    {
                        //See if the pattern can be placed here
                        //    (and the color this pixel would become isn't blacklisted).

                        Vector2i pixelPatternPos   = pixelPos - patternMinCornerPos;
                        Color    pixelPatternColor = pattern[pixelPatternPos];

                        if (!badColors.Contains(pixelPatternColor) &&
                            pattern.DoesFit(patternMinCornerPos, outputColorGetter))
                        {
                            if (!pixel.ApplicableColorFrequencies.ContainsKey(pixelPatternColor))
                            {
                                pixel.ApplicableColorFrequencies.Add(pixelPatternColor, 0);
                            }
                            pixel.ApplicableColorFrequencies[pixelPatternColor] += pattern.Frequency;
                        }
                    }
                }

                //Now update the visualized color of that pixel.
                //To do that, average together every color the pixel COULD be.
                if (!UpdateVisualizationAfterIteration)
                {
                    continue;
                }
                float sumR = 0.0f,
                      sumG = 0.0f,
                      sumB = 0.0f;
                foreach (var colorAndFrequency in pixel.ApplicableColorFrequencies)
                {
                    sumR += colorAndFrequency.Key.R * colorAndFrequency.Value;
                    sumG += colorAndFrequency.Key.G * colorAndFrequency.Value;
                    sumB += colorAndFrequency.Key.B * colorAndFrequency.Value;
                }
                float invN = 1.0f / pixel.ApplicableColorFrequencies.Values.Sum(u => (float)u);
                pixel.VisualizedValue = Color.FromArgb((byte)Math.Max(0, Math.Min(255, (int)(sumR * invN))),
                                                       (byte)Math.Max(0, Math.Min(255, (int)(sumG * invN))),
                                                       (byte)Math.Max(0, Math.Min(255, (int)(sumB * invN))));
            }
        }
Example #5
0
 public bool IsInside(Vector2i inputPos)
 {
     return(inputPos.x >= 0 && inputPos.y >= 0 &&
            inputPos.x < Size.x && inputPos.y < Size.y);
 }
Example #6
0
        public Input(Color[,] _data, Vector2i patternSize, bool periodicX, bool periodicY,
                     bool useRotations, bool useReflections)
        {
            PeriodicX           = periodicX;
            PeriodicY           = periodicY;
            OriginalPatternSize = patternSize;

            //Copy the color data.
            data = new Color[_data.GetLength(0), _data.GetLength(1)];
            foreach (Vector2i pos in data.AllIndices())
            {
                this[pos] = _data.Get(pos);
            }

            //Compute the average color.
            float sumR = 0.0f,
                  sumG = 0.0f,
                  sumB = 0.0f;

            foreach (Vector2i pos in data.AllIndices())
            {
                Color color = data.Get(pos);

                sumR += color.R;
                sumG += color.G;
                sumB += color.B;
            }
            float invN = 1.0f / (data.SizeX() * data.SizeY());

            AverageColor = Color.FromRgb((byte)Math.Max(0, Math.Min(255, (int)(sumR * invN))),
                                         (byte)Math.Max(0, Math.Min(255, (int)(sumG * invN))),
                                         (byte)Math.Max(0, Math.Min(255, (int)(sumB * invN))));

            //Get the list of transformations we'll be using on the input data.
            List <Transforms> transformations = new List <Transforms>()
            {
                Transforms.None
            };

            if (useReflections)
            {
                transformations.Add(Transforms.MirrorX);
                transformations.Add(Transforms.MirrorY);
            }
            //The use of rotations also determines our maximum pattern size along each axis.
            if (useRotations)
            {
                transformations.Add(Transforms.Rotate90CW);
                transformations.Add(Transforms.Rotate270CW);
                transformations.Add(Transforms.Rotate180);

                int maxPatternSize = Math.Max(OriginalPatternSize.x, OriginalPatternSize.y);
                MaxPatternSize = new Vector2i(maxPatternSize, maxPatternSize);
            }
            else
            {
                MaxPatternSize = OriginalPatternSize;
            }


            //For every pixel in the input, create one pattern starting from that pixel
            //    for each type of transformation.
            Patterns = new List <Pattern>(Size.x * Size.y * transformations.Count);
            //If the input is periodic, we can make our patterns all the way
            //    to the max edge of the input.
            //Otherwise, we have to back off the max edge a bit.
            Vector2i maxPatternMinCorner = Size - 1;

            if (!PeriodicX)
            {
                maxPatternMinCorner.x -= patternSize.x;
            }
            if (!PeriodicY)
            {
                maxPatternMinCorner.y -= patternSize.y;
            }
            foreach (Vector2i patternMinCornerPos in new Vector2i.Iterator(maxPatternMinCorner + 2))
            {
                foreach (var transform in transformations)
                {
                    Patterns.Add(new Pattern(this, patternMinCornerPos, patternSize, transform));
                }
            }

            //Remove identical patterns, using hashes to compare them quickly.
            List <int> patternHashes = Patterns.Select(p => p.GetHashCode()).ToList();

            for (int i = 0; i < Patterns.Count; ++i)
            {
                var basePattern = Patterns[i];
                for (int j = i + 1; j < Patterns.Count; ++j)
                {
                    var patternToCheck = Patterns[j];

                    //If the patterns match, remove the second one.
                    if (patternHashes[i] == patternHashes[j] && basePattern.Equals(patternToCheck))
                    {
                        //Increment the frequency of the original pattern.
                        Patterns[i] = new Pattern(Patterns[i].Values, Patterns[i].Frequency + 1);

                        Patterns.RemoveAt(j);
                        patternHashes.RemoveAt(j);
                        j -= 1;
                    }
                }
            }

            //Compute the color frequencies.
            ColorFrequencies = new Dictionary <Color, uint>();
            foreach (Pattern pattern in Patterns)
            {
                foreach (Vector2i patternPos in pattern.Values.AllIndices())
                {
                    Color patternColor = pattern.Values.Get(patternPos);
                    if (!ColorFrequencies.ContainsKey(patternColor))
                    {
                        ColorFrequencies.Add(patternColor, 0);
                    }
                    ColorFrequencies[patternColor] += pattern.Frequency;
                }
            }
        }