public SpiralSegment Next() { var nextSegment = new SpiralSegment(); // Update X and Y direction according to the cycle: // ... Right -> Down -> Left -> Up -> Right ... // // dX dY Direction //------------------- // 1 0 Right // 0 1 Down // -1 0 Left // 0 -1 Up nextSegment.Direction = new Vector2D( x: -1 * this.Direction.Y, y: this.Direction.X); // If changing from vertical to horizontal movement, increase the length of the segment by 1 nextSegment.Length = nextSegment.Direction.X == 0 ? this.Length : this.Length + 1; return nextSegment; }
/// <summary> /// Calculates the dimensions required for the spiral data matrix /// by simulating a run through the spiral. /// </summary> /// <param name="width">Output: width of matrix</param> /// <param name="height">Output: height of matrix</param> private void CalculateGridDimensions(out int width, out int height) { int minX = 0; int minY = 0; int maxX = 0; int maxY = 0; var location = new Vector2D(0, 0); var segment = new SpiralSegment(1, UnitVectors.Right); int index = 0; do { int remainingCells = _maxValue - index; Vector2D distanceToTravel; if (remainingCells >= segment.Length) { // travel the full segment and then get the next segment index += segment.Length; distanceToTravel = segment.Direction.Multiply(segment.Length); segment = segment.Next(); } else { // travel the remaining cells index += remainingCells; distanceToTravel = segment.Direction.Multiply(remainingCells); } location = location.Add(distanceToTravel); // Update the observed bounds minX = (int)Math.Min(minX, location.X); minY = (int)Math.Min(minY, location.Y); maxX = (int)Math.Max(maxX, location.X); maxY = (int)Math.Max(maxY, location.Y); } while (index < _maxValue); width = maxX - minX + 1; height = maxY - minY + 1; }
/// <summary> /// Generates a matrix representing a clockwise spiral of numbers /// with zero at the center /// </summary> /// <returns>Returns a matrix representing a spiral of numbers</returns> private int[,] GenerateSpiral() { // initialize the grid var output = InitializeGrid(); int width = output.GetLength(0); int height = output.GetLength(1); // Start at the center of the grid var location = new Vector2D( x: (int)((width - 1) / 2), y: (int)((height - 1) / 2)); // Set the initial segment (move 1 cell to the right) var segment = new SpiralSegment(1, UnitVectors.Right); int segmentIndex = 0; for (var i = 0; i <= _maxValue; i++) { output[location.X, location.Y] = i; // Move to the next cell segmentIndex++; location = location.Add(segment.Direction); // If this is the end of a segment, then change directions // and start a new segment if (segmentIndex >= segment.Length) { segmentIndex = 0; segment = segment.Next(); } } return output; }