/// <summary> /// Gets/sets a pixel in this input. /// Automatically handles things like wrapping the position if this instance is periodic. /// </summary> public Color this[Vector2i pos] { get { Vector2i size = Size; if (PeriodicX) { while (pos.x < 0) { pos.x += size.x; } pos.x %= size.x; } if (PeriodicY) { while (pos.y < 0) { pos.y += size.y; } pos.y %= size.y; } return(data.Get(pos)); } set { Vector2i size = Size; if (PeriodicX) { while (pos.x < 0) { pos.x += size.x; } pos.x %= size.x; } if (PeriodicY) { while (pos.y < 0) { pos.y += size.y; } pos.y %= size.y; } if (!IsInside(pos)) { return; } data.Set(pos, value); } }
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; } } }
public Color this[Vector2i pos] { get { return(Values.Get(pos)); } set { Values.Set(pos, value); } }