/// <summary> /// Gets whether this pattern can fit into the given output at the given position. /// </summary> /// <param name="outputMinCorner"> /// The position in the output of this pattern's min corner. /// </param> /// <param name="output"> /// A way to get the current value of any output tile. /// A "null" result means that that tile isn't set yet, or that it's out of bounds. /// </param> public bool DoesFit(Vector2i outputMinCorner, Func <Vector2i, Color?> output) { //For every tile in this pattern, // see if the corresponding output tile // contains something different than the corresponding input tile. foreach (Vector2i patternPos in Values.AllIndices()) { Color patternCol = this[patternPos]; Vector2i outputPos = patternPos + outputMinCorner; Color? outputCol = output(outputPos); if (outputCol.HasValue && outputCol.Value != patternCol) { return(false); } } return(true); }
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.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)))); //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 + 1)) { 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; } } }