/// <summary> /// Allocate large enough colormap.. /// </summary> public static void AssertColors(int num) { int i; if (debugColors == null || debugColors.Count < num) { debugColors = new List <Color>(num); RandomJames rnd = new RandomJames(); for (i = 0; i < num; i++) { int R = rnd.RandomInteger(0, 255); int G = rnd.RandomInteger(0, 255); int B = rnd.RandomInteger(0, 255); if (R >= 128 && G >= 128 && B >= 128) { if (rnd.UniformNumber() > 0.5) { R -= 128; } else { G -= 128; } } debugColors.Add(Color.FromArgb(R, G, B)); } } }
/// <summary> /// Update number of simulated marbles, 'Marbles' is requested to be equal to 'marbles'. /// </summary> void UpdateMarbles() { if (marbles < Marbles) { // Truncate the arrays. int remove = Marbles - marbles; centers.RemoveRange(marbles, remove); radii.RemoveRange(marbles, remove); velocities.RemoveRange(marbles, remove); colors.RemoveRange(marbles, remove); return; } // Extend the arrays. for (int i = Marbles; i < marbles; i++) { centers.Add(new Vector3(rnd.RandomFloat(-10.0f, 10.0f), rnd.RandomFloat(-10.0f, 10.0f), rnd.RandomFloat(-10.0f, 10.0f))); radii.Add(rnd.RandomFloat(0.4f, 1.0f)); velocities.Add(new Vector3(rnd.RandomFloat(-2.0f, 2.0f), rnd.RandomFloat(-2.0f, 2.0f), rnd.RandomFloat(-2.0f, 2.0f))); colors.Add(Color.FromArgb(rnd.RandomInteger(0, 255), rnd.RandomInteger(0, 255), rnd.RandomInteger(0, 255))); // {{ TODO: more initialization? // }} } }
/// <summary> /// Update number of simulated marbles, 'Marbles' is requested to be equal to 'marbles'. /// </summary> void UpdateMarbles() { if (marbles < Marbles) { // Truncate the arrays. int remove = Marbles - marbles; MyMarbles.RemoveRange(marbles, remove); return; } // Extend the arrays. for (int i = Marbles; i < marbles; i++) { var radius = rnd.RandomFloat(0.4f, 1.0f); var color = Color.FromArgb(rnd.RandomInteger(0, 100), rnd.RandomInteger(0, 255), rnd.RandomInteger(0, 255)); var position = new Vector3(rnd.RandomFloat(-10.0f, 10.0f), rnd.RandomFloat(-10.0f, 10.0f), rnd.RandomFloat(-10.0f, 10.0f)); var velocity = Speed * new Vector3(rnd.RandomFloat(-2.0f, 2.0f), rnd.RandomFloat(-2.0f, 2.0f), rnd.RandomFloat(-2.0f, 2.0f)); var marble = new SphereObject(radius, color, position, velocity) { bouncyness = initBouncy, mass = initMass }; marble.Create(); MyMarbles.Add(marble); } }
/// <summary> /// Draw the image into the initialized Canvas object. /// </summary> /// <param name="c">Canvas ready for your drawing.</param> /// <param name="param">Optional string parameter from the form.</param> public static void Draw(Canvas c, string param) { // {{ TODO: put your drawing code here int wq = c.Width / 4; int hq = c.Height / 4; int minq = Math.Min(wq, hq); double t; int i, j; double x, y, r; RandomJames rnd = new RandomJames(); c.Clear(Color.Black); // Example of even simpler passing of a numeric value through string param. long seed; if (long.TryParse(param, NumberStyles.Number, CultureInfo.InvariantCulture, out seed)) { rnd.Reset(seed); } // 1st quadrant - anti-aliased disks in a spiral. c.SetAntiAlias(true); const int MAX_DISK = 30; for (i = 0, t = 0.0; i < MAX_DISK; i++, t += 0.65) { r = 5.0 + i * (minq * 0.7 - 5.0) / MAX_DISK; c.SetColor(Color.FromArgb(i * 255 / MAX_DISK, 255, 255 - i * 255 / MAX_DISK)); c.FillDisc((float)(wq + r * Math.Sin(t)), (float)(hq + r * Math.Cos(t)), (float)(r * 0.3)); } // 2nd quadrant - anti-aliased random dots in a heart shape.. const int MAX_RND_DOTS = 1000; double xx, yy, tmp; for (i = 0; i < MAX_RND_DOTS; i++) { // This is called "Rejection Sampling" do { x = rnd.RandomDouble(-1.5, 1.5); y = rnd.RandomDouble(-1.0, 1.5); xx = x * x; yy = y * y; tmp = xx + yy - 1.0; } while (tmp * tmp * tmp - xx * yy * y > 0.0); c.SetColor(Color.FromArgb(rnd.RandomInteger(200, 255), rnd.RandomInteger(120, 220), rnd.RandomInteger(120, 220))); c.FillDisc(3.1f * wq + 0.8f * minq * (float)x, 1.2f * hq - 0.8f * minq * (float)y, rnd.RandomFloat(1.0f, minq * 0.03f)); } // 4th quadrant - CGG logo. c.SetColor(COLORS[0]); for (i = 0; i < DISC_DATA.Length / 3; i++) { x = DISC_DATA[i, 0]; y = DISC_DATA[i, 1]; r = DISC_DATA[i, 2]; if (i == FIRST_COLOR) { c.SetColor(COLORS[1]); } c.FillDisc(3.0f * wq + (float)((x - 85.0) * 0.018 * minq), 3.0f * hq + (float)((y - 65.0) * 0.018 * minq), (float)(r * 0.018 * minq)); } // 3rd quadrant - disk grid. const int DISKS = 12; for (j = 0; j < DISKS; j++) { for (i = 0; i < DISKS; i++) { c.SetColor(((i ^ j) & 1) == 0 ? Color.White : Color.Blue); c.FillDisc(wq + (i - DISKS / 2) * (wq * 1.8f / DISKS), 3 * hq + (j - DISKS / 2) * (hq * 1.7f / DISKS), (((i ^ j) & 15) + 1.0f) / DISKS * minq * 0.08f); } } // }} }
static void RecursiveMondrian(RandomJames rnd, Canvas c, Rect rect, int borderWidth, int depthOfRecursion, int maxDepth, int maxDots) { if (depthOfRecursion >= maxDepth) { goto FILL; } int divisionLine; Rect DivisionLine; Rect Splitted1; Rect Splitted2; if (depthOfRecursion % 2 == 0) { // Vertical split if (rect.x1 - rect.x0 <= borderWidth * 4) { goto FILL; } divisionLine = rnd.RandomInteger(rect.x0 + borderWidth * 2, rect.x1 - borderWidth * 2); DivisionLine = new Rect() { x0 = divisionLine - (borderWidth / 2), x1 = divisionLine + (borderWidth / 2), y0 = rect.y0, y1 = rect.y1 }; Splitted1 = new Rect() { x0 = rect.x0, x1 = DivisionLine.x0 - 1, y0 = rect.y0, y1 = rect.y1 }; Splitted2 = new Rect() { x0 = DivisionLine.x1 + 1, x1 = rect.x1, y0 = rect.y0, y1 = rect.y1 }; } else { // Horizontal split if (rect.y1 - rect.y0 <= borderWidth * 4) { goto FILL; } divisionLine = rnd.RandomInteger(rect.y0 + borderWidth * 2, rect.y1 - borderWidth * 2); DivisionLine = new Rect() { x0 = rect.x0, x1 = rect.x1, y0 = divisionLine - (borderWidth / 2), y1 = divisionLine + (borderWidth / 2) }; Splitted1 = new Rect() { x0 = rect.x0, x1 = rect.x1, y0 = rect.y0, y1 = DivisionLine.y0 - 1 }; Splitted2 = new Rect() { x0 = rect.x0, x1 = rect.x1, y0 = DivisionLine.y1 + 1, y1 = rect.y1 }; } // Filling Division line for (int i = 0; i < maxDots; i++) { int x = rnd.RandomInteger(DivisionLine.x0, DivisionLine.x1); int y = rnd.RandomInteger(DivisionLine.y0, DivisionLine.y1); c.SetColor(Color.Black); c.FillDisc((float)x, (float)y, (float)rnd.RandomInteger(1, borderWidth / 4)); } RecursiveMondrian(rnd, c, Splitted1, borderWidth, depthOfRecursion + 1, maxDepth, maxDots); RecursiveMondrian(rnd, c, Splitted2, borderWidth, depthOfRecursion + 1, maxDepth, maxDots); return; FILL: int area = (rect.x1 - rect.x0) * (rect.y1 - rect.y0); var maxCircleRadius = Math.Sqrt((double)area / (Math.PI * Math.Log(area) * 8)); //fill that rectangle with random color List <Color> colors = new List <Color>() { Color.White, Color.White, Color.White, Color.Red, Color.Blue, Color.Yellow }; Color randomColor = colors[rnd.RandomInteger(0, colors.Count - 1)]; for (int i = 0; i < maxDots; i++) { int x = rnd.RandomInteger(rect.x0, rect.x1); int y = rnd.RandomInteger(rect.y0, rect.y1); c.SetColor(randomColor); c.FillDisc((float)x, (float)y, (float)rnd.RandomDouble((maxCircleRadius / 2) * 0.25, maxCircleRadius / 2)); } }
/// <summary> /// Draw single animation frame. /// </summary> /// <param name="c">Canvas to draw to.</param> /// <param name="time">Current time in seconds.</param> /// <param name="start">Start time (t0)</param> /// <param name="end">End time (for animation length normalization).</param> /// <param name="param">Optional string parameter from the form.</param> public static void DrawFrame(Canvas c, double time, double start, double end, string param) { // {{ TODO: put your drawing code here int objects = 1200; long seed = 144; double speed = 1.0; // Parse parameters. Dictionary <string, string> p = Util.ParseKeyValueList(param); if (p.Count > 0) { // objects=<int> if (Util.TryParse(p, "objects", ref objects)) { if (objects < 10) { objects = 10; } } // seed=<long> Util.TryParse(p, "seed", ref seed); // speed=<double> Util.TryParse(p, "speed", ref speed); } int wq = c.Width / 4; int hq = c.Height / 4; int minq = Math.Min(wq, hq); double t; int i, j; double x, y, r; c.Clear(Color.Black); c.SetAntiAlias(true); // 1st quadrant - anti-aliased disks in a spiral. const int MAX_DISK = 30; for (i = 0, t = 0.0; i < MAX_DISK; i++, t += 0.65) { r = 5.0 + i * (minq * 0.7 - 5.0) / MAX_DISK; c.SetColor(Color.FromArgb((i * 255) / MAX_DISK, 255, 255 - (i * 255) / MAX_DISK)); c.FillDisc((float)(wq + r * Math.Sin(t)), (float)(hq + r * Math.Cos(t)), (float)(r * 0.3)); } // 2nd quadrant - anti-aliased random dots in a heart shape.. RandomJames rnd = new RandomJames(seed + (long)((time - start) * 5)); double xx, yy, tmp; for (i = 0; i < objects; i++) { // This is called "Rejection Sampling" do { x = rnd.RandomDouble(-1.5, 1.5); y = rnd.RandomDouble(-1.0, 1.5); xx = x * x; yy = y * y; tmp = xx + yy - 1.0; } while (tmp * tmp * tmp - xx * yy * y > 0.0); c.SetColor(Color.FromArgb(rnd.RandomInteger(200, 255), rnd.RandomInteger(120, 220), rnd.RandomInteger(120, 220))); c.FillDisc(3.1f * wq + 0.8f * minq * (float)x, 1.2f * hq - 0.8f * minq * (float)y, rnd.RandomFloat(1.0f, minq * 0.03f)); } // 4th quadrant - CGG logo. c.SetColor(COLORS[0]); for (i = 0; i < DISC_DATA.Length / 3; i++) { x = DISC_DATA[i, 0] - 65.0; y = DISC_DATA[i, 1] - 65.0; r = DISC_DATA[i, 2]; if (i == FIRST_COLOR) { c.SetColor(COLORS[1]); } t = 4.0 * speed * Math.PI * (time - start) / (end - start); double sina = Math.Sin(t); double cosa = Math.Cos(t); double nx = cosa * x + sina * y; double ny = -sina * x + cosa * y; c.FillDisc(3.0f * wq + (float)((nx - 20.0) * 0.018 * minq), 3.0f * hq + (float)(ny * 0.018 * minq), (float)(r * 0.018 * minq)); } // 3rd quadrant - jaggy disks. const int DISKS = 12; for (j = 0; j < DISKS; j++) { for (i = 0; i < DISKS; i++) { c.SetColor(((i ^ j) & 1) == 0 ? Color.White : Color.Blue); c.FillDisc(wq + (i - DISKS / 2) * (wq * 1.8f / DISKS), 3 * hq + (j - DISKS / 2) * (hq * 1.7f / DISKS), (((i ^ j) & 15) + 1.0f) / DISKS * minq * 0.08f); } } // }} }