/// <summary> /// Draws a rectangle using point A and point D. /// /// Rectangle must be drawn on the coordinate that the points share, i.e., you /// cannot (or should not) draw a rectangle between a point at (0,0,7) and (1,2,3), /// as they have no common plane to drawn cleanly across at 90° angles. /// /// </summary> /// <param name="A">The first point to draw from (inside-originating corner).</param> /// <param name="D">The terminating point (outside-opposing corner).</param> public void DrawRectangle(Cube.AXIS axis, CubeController.Point A, CubeController.Point D) { // Draw the lines to the non-named points: // // SIDE 1 // A _______________ B // | | // SIDE 4 | | SIDE 2 // |_______________| // C D // SIDE 3 switch (axis) { case AXIS.AXIS_X: // X IS FIXED FOR BOTH A AND D DrawLine(A, new Point(A.X, A.Y, D.Z)); // Draw SIDE 1 DrawLine(D, new Point(A.X, A.Y, D.Z)); // Draw SIDE 2 DrawLine(D, new Point(A.X, D.Y, A.Z)); // Draw SIDE 3 DrawLine(A, new Point(A.X, D.Y, A.Z)); // Draw SIDE 4 break; case AXIS.AXIS_Y: // Y IS FIXED FOR BOTH A AND D DrawLine(A, new Point(A.X, A.Y, D.Z)); // Draw SIDE 1 DrawLine(D, new Point(A.X, A.Y, D.Z)); // Draw SIDE 2 DrawLine(D, new Point(D.X, A.Y, A.Z)); // Draw SIDE 3 DrawLine(A, new Point(D.X, A.Y, A.Z)); // Draw SIDE 4 break; case AXIS.AXIS_Z: // Z IS FIXED FOR BOTH A AND D DrawLine(A, new Point(D.X, A.Y, A.Z)); // Draw SIDE 1 DrawLine(D, new Point(D.X, A.Y, A.Z)); // Draw SIDE 2 DrawLine(D, new Point(A.X, D.Y, A.Z)); // Draw SIDE 3 DrawLine(A, new Point(A.X, D.Y, A.Z)); // Draw SIDE 4 break; default: break; } }
/// <summary> /// Draws a circle at [center] with radius [radius]. /// /// Follows the Midpoint Circle Algorithm: /// http://csunplugged.org/wp-content/uploads/2014/12/Lines.pdf, pg 9. /// </summary> /// <param name="center"></param> /// <param name="radius"></param> public void DrawCircle(Cube.AXIS axis, CubeController.Point center, CubeController.Point rad) { int radius = int.MinValue; int E; // E = -radius int A; // A = +radius int B = 0; // Until B becomes greater than A, repeat the following rules in order: // Fill the pixel at coordinate (A + center.A, B+Center.B) // Increase E by (2*B + 1) // Increase B by 1 // If E >= 0 // E -= (2 * A - 1) // --A // This covers one octave, you must repeat 7 times with varying reflections // in order to cover the circle. // In three dimensions: switch (axis) { // On the Y-Z plane, fix to X coordinate // and draw for Y-Z. case AXIS.AXIS_X: radius = (int)(Point.Distance(center.Y, rad.Y, center.Z, rad.Z)); E = -radius; A = radius; while (B < A) { SetVoxel(center.X, A + center.Y, B + center.Z); SetVoxel(center.X, A + center.Y, -B + center.Z); SetVoxel(center.X, -A + center.Y, B + center.Z); SetVoxel(center.X, -A + center.Y, -B + center.Z); SetVoxel(center.X, B + center.Y, A + center.Z); SetVoxel(center.X, B + center.Y, -A + center.Z); SetVoxel(center.X, -B + center.Y, A + center.Z); SetVoxel(center.X, -B + center.Y, -A + center.Z); E += ((2 * B) + 1); ++B; if (E >= 0) { E -= ((2 * A) - 1); --A; } } break; // On the X-Z plane, fix to Y coordinate // and draw for X-Z. case AXIS.AXIS_Y: radius = (int)(Point.Distance(center.X, rad.X, center.Z, rad.Z)); E = -radius; A = radius; while (B < A) { SetVoxel( A + center.X, center.Y, B + center.Z); SetVoxel( A + center.X, center.Y, -B + center.Z); SetVoxel(-A + center.X, center.Y, B + center.Z); SetVoxel(-A + center.X, center.Y, -B + center.Z); SetVoxel( B + center.X, center.Y, A + center.Z); SetVoxel( B + center.X, center.Y, -A + center.Z); SetVoxel(-B + center.X, center.Y, A + center.Z); SetVoxel(-B + center.X, center.Y, -A + center.Z); E += ((2 * B) + 1); ++B; if (E >= 0) { E -= ((2 * A) - 1); --A; } } break; // On the X-Y plane, fix to Z coordinate // and draw for X-Y. case AXIS.AXIS_Z: radius = (int)(Point.Distance(center.X, rad.X, center.Y, rad.Y)); E = -radius; A = radius; while (B < A) { SetVoxel( A + center.X, B + center.Y, center.Z); SetVoxel( A + center.X, -B + center.Y, center.Z); SetVoxel(-A + center.X, B + center.Y, center.Z); SetVoxel(-A + center.X, -B + center.Y, center.Z); SetVoxel( B + center.X, A + center.Y, center.Z); SetVoxel( B + center.X, -A + center.Y, center.Z); SetVoxel(-B + center.X, A + center.Y, center.Z); SetVoxel(-B + center.X, -A + center.Y, center.Z); E += ((2 * B) + 1); ++B; if (E >= 0) { E -= ((2 * A) - 1); --A; } } break; default: break; } }
/// <summary> /// Not quite sure of the effect. /// </summary> /// <param name="size"></param> /// <param name="axis"></param> /// <param name="direction"></param> /// <param name="iterations"></param> /// <param name="delay"></param> public void WormSqueeze(int size, Cube.AXIS axis, Cube.DIRECTION direction, int iterations, int delay) { int cubeSize = DIMENSION - size - 1; // If the direction is forward, start from ORIGIN. // Otherwise, start from TERMINUS. int origin = direction == DIRECTION.FORWARD ? 0 : (DIMENSION - 1); int x = _rgen.Next() % cubeSize; int y = _rgen.Next() % cubeSize; for (int i = 0; i < iterations; ++i) { // Random change in x and y. int dx = (_rgen.Next() % 3) - 1; int dy = (_rgen.Next() % 3) - 1; if ((x + dx) > 0 && (x + dx) < cubeSize) { x += dx; } if ((y+dy) > 0 && (y+dy) < cubeSize) { y += dy; } ShiftNoRoll(axis, direction); for (int j = 0; j < size; ++j) { for (int k = 0; k < size; ++k) { switch (axis) { case AXIS.AXIS_X: SetVoxel(origin, x + j, y + k); break; case AXIS.AXIS_Y: SetVoxel(x + j, origin, y + k); break; case AXIS.AXIS_Z: SetVoxel(x + j, y + k, origin); break; default: break; } } } DelayMS(delay); } }
/// <summary> /// A helper function for AxisUpDownRandSusp. /// </summary> /// <param name="axis"></param> /// <param name="positions"></param> /// <param name="invert"></param> private void DrawPositionsAxis(Cube.AXIS axis, int[] positions, bool invert) { int p = 0; ClearEntireCube(); for (int x = 0; x < DIMENSION; ++x) { for (int y = 0; y < DIMENSION; ++y) { if (invert) { p = (DIMENSION - 1 - positions[(x * DIMENSION) + y]); } else { p = positions[(x*DIMENSION) + y]; } switch (axis) { case AXIS.AXIS_X: SetVoxel(p, x, y); break; case AXIS.AXIS_Y: SetVoxel(x, p, y); break; case AXIS.AXIS_Z: SetVoxel(x, y, p); break; default: break; } } } }
/// <summary> /// Shamelessy "inspired" (edit: copied) from CHR's original code. /// </summary> /// <param name="axis">Axis to randomly suspend along.</param> /// <param name="delay">Delay between animation frames.</param> /// <param name="sleep">Time to hold the frozen suspensions.</param> /// <param name="invert">Inversion?</param> public void AxisUpDownRandSups(Cube.AXIS axis, int delay, int sleep, bool invert) { int length = DIMENSION * DIMENSION; int[] positions = new int[length]; int[] destinations = new int[length]; for (int i = 0; i < length; ++i) { positions[i] = 0; destinations[i] = _rgen.Next() % (DIMENSION); } for (int i = 0; i < DIMENSION; ++i) { for (int px = 0; px < DIMENSION; ++px) { if (positions[px] < destinations[px]) { positions[px]++; } if (positions[px] > destinations[px]) { positions[px]--; } } DrawPositionsAxis(axis, positions, invert); DelayMS(delay); } for (int i = 0; i < length; ++i) { destinations[i] = (DIMENSION - 1); } DelayMS(sleep); for (int i = 0; i < DIMENSION; ++i) { for (int px = 0; px < length; ++px) { if (positions[px] < destinations[px]) { positions[px]++; } if (positions[px] > destinations[px]) { positions[px]--; } } DrawPositionsAxis(axis, positions, invert); DelayMS(delay); } }