/* Iterative Scaling Experiment by: Chris M. Thomasson _________________________________________________________*/ /* Our global 2d plane _________________________________________________________*/ float g_radius = 4.0; // master zoom ct_axes_2d g_axes = new ct_axes_2d(0, 0, g_radius); ct_plane_2d g_plane = null; //static int g_anime_frame_n = 24 * 5; static int g_anime_frame_n = 8 * 10; static float g_anime_frame_step = (PI * 2) / g_anime_frame_n; int g_anime_frame_i = 0; float g_anime_a0 = 0; static PFont g_font = null; // Runtime setup, pre-main... void setup() { // setup our global plane //size(3840, 2160); //size(1920, 1080); size(720, 405); g_plane = new ct_plane_2d(g_axes, width, height); // Initial state noFill(); noLoop(); background(0); colorMode(RGB, 255); strokeWeight(3); stroke(255, 255, 255, 128); g_font = createFont("Arial",16,true); // STEP 2 Create Font // Call main! ct_main(); } /* Main _________________________________________________________*/ void ct_main() { ct_mbrot_plane(.1); stroke(255); ct_circle(0, 0, 1); //ct_render_grid(); saveFrame("ct_vector_field.jpg"); loop(); } float g_anime_scale = .1; void draw() { if (g_anime_frame_i < g_anime_frame_n) { float angle = g_anime_frame_step * g_anime_frame_i; g_anime_scale = abs(sin(angle / 2)) * .25 + .05; clear(); ct_mbrot_plane(g_anime_scale); print("g_anime_scale:" + g_anime_scale + ", "); ct_save_frame("ct_mbrot"); ++g_anime_frame_i; } else { println("Complete!"); noLoop(); } } float ct_cmul_x(float x0, float y0, float x1, float y1) { return x0 * x1 - y0 * y1; } float ct_cmul_y(float x0, float y0, float x1, float y1) { return x0 * y1 + y0 * x1; } void ct_save_frame(String prefix) { String file = "\\movie\\" + prefix + "_" + g_anime_frame_i + ".jpg"; //saveFrame(file); println("frame:" + file); } // Iterative Re-Scaling void ct_mbrot_point( int xi, int yi, float zx, float zy, float cx, float cy, float scale ) { int n = 73; int b = 0; float rn = 2; // escape float o = 99999999999.0; for (int i = 1; i < n + 1; ++i) { // z = z^2+c float tzx = ct_cmul_x(zx, zy, zx, zy); zy = ct_cmul_y(zx, zy, zx, zy); zx = tzx; zx += cx; zy += cy; // r = abs(z); float r = sqrt(zx*zx + zy*zy); // orbit trap for coloring... if (r < o) o = r; // check for escape... if (r > rn) { // retry 5 times if (b < 5) { // scale z back, z *= scale zx *= scale; zy *= scale; ++b; // increase the next escape radius rn += 2 + scale; continue; } // Color outside //stroke((i * 123) % 256, (i * 4586) % 256, i); int red = (int)(o * (i * i)); stroke(red % 256, (red * 10 * scale) % 256, (i * 453) % 256); point(xi, yi); return; } } // Color inside //stroke(0, 255, 0); int red = (int)(o * 256); stroke(red % 256, 0, 0); point(xi, yi); } // Iterate the global plane void ct_mbrot_plane(float scale) { for (int yi = 0; yi < height; ++yi) { for (int xi = 0; xi < width; ++xi) { float zx = g_plane.project_x(xi);// * .15 * (1/scale); float zy = g_plane.project_y(yi);// * .15 * (1/scale); ct_mbrot_point(xi, yi, zx, zy, zx, zy, scale); } } } void ct_render_grid() { // white lines and circle stroke(255, 255, 255); ct_circle(0, 0, 1); ct_rect_center(0, 0, 1, 1); ct_line(-1, 1, -2, 2); ct_line(1, 1, 2, 2); ct_line(1, -1, 2, -2); ct_line(-1, -1, -2, -2); // purple circles and lines stroke(255, 255, 0); ct_circle(0, 0, 2); ct_rect_center(0, 0, 2, 2); stroke(255, 0, 255); ct_circle(-1.5, 0, .5); ct_circle(1.5, 0, .5); ct_circle(0, -1.5, .5); ct_circle(0, 1.5, .5); // axes green as x and red as y. float oradius = (sqrt(8) - 2) / 2; stroke(0, 255, 0); ct_line(-oradius * 2 - 2, 0, oradius * 2 + 2, 0); stroke(255, 0, 0); ct_line(0, -oradius * 2 - 2, 0, oradius * 2 + 2); // Cyan circles stroke(0, 255, 255); ct_circle(0, 0, sqrt(8)); ct_circle(-2 - oradius, 0, oradius); ct_circle(2 + oradius, 0, oradius); ct_circle(0, -2 - oradius, oradius); ct_circle(0, 2 + oradius, oradius); } /* 2d Projected Drawing Tools _________________________________________________________*/ void ct_circle(float x, float y, float r) { float x_proj = g_plane.project_x(x); float y_proj = g_plane.project_y(y); float r_proj = g_plane.project_h(r) * 2; ellipse(x_proj, y_proj, r_proj, r_proj); } void ct_rect_center(float x, float y, float w, float h) { ct_rect(x - w, y + h, w, h); } void ct_text(float x, float y, String b) { float x_proj = g_plane.project_x(x); float y_proj = g_plane.project_y(y); textFont(g_font, 20); // STEP 3 Specify font to be used fill(255); // STEP 4 Specify font color text(b, x_proj, y_proj); // STEP 5 Display Text noFill(); } void ct_rect(float x, float y, float w, float h) { float x_proj = g_plane.project_x(x); float y_proj = g_plane.project_y(y); float w_proj = g_plane.project_w(w) * 2; float h_proj = g_plane.project_h(h) * 2; rect(x_proj, y_proj, w_proj, h_proj); } void ct_line(float x0, float y0, float x1, float y1) { float x0_proj = g_plane.project_x(x0); float y0_proj = g_plane.project_y(y0); float x1_proj = g_plane.project_x(x1); float y1_proj = g_plane.project_y(y1); line(x0_proj, y0_proj, x1_proj, y1_proj); } void ct_point(float x, float y) { float x_proj = g_plane.project_x(x); float y_proj = g_plane.project_y(y); point(x_proj, y_proj); } /* 2d Axes _________________________________________________________*/ class ct_axes_2d { float m_xmin; float m_xmax; float m_ymin; float m_ymax; ct_axes_2d(float xmin, float xmax, float ymin, float ymax) { m_xmin = xmin; m_xmax = xmax; m_ymin = ymin; m_ymax = ymax; } ct_axes_2d(ct_axes_2d axes) { m_xmin = axes.m_xmin; m_xmax = axes.m_xmax; m_ymin = axes.m_ymin; m_ymax = axes.m_ymax; } ct_axes_2d(float x, float y, float r) { m_xmin = x - r; m_xmax = x + r; m_ymin = y - r; m_ymax = y + r; } ct_axes_2d copy_to(ct_axes_2d dest) { dest.m_xmin = m_xmin; dest.m_xmax = m_xmax; dest.m_ymin = m_ymin; dest.m_ymax = m_ymax; return dest; } float width() { return m_xmax - m_xmin; } float height() { return m_ymax - m_ymin; } }; /* 2d Plane _________________________________________________________*/ class ct_plane_2d { ct_axes_2d m_axes; int m_width; int m_height; float m_aratio; float m_xstep; float m_ystep; ct_plane_2d(ct_axes_2d axes, int width_, int height_) { m_axes = new ct_axes_2d(axes); // copy m_width = width_; m_height = height_; float daspect = abs((float)height_ / width_); float waspect = abs(m_axes.height() / m_axes.width()); if (daspect > waspect) { float excess = m_axes.height() * (daspect / waspect - 1); m_axes.m_ymax += excess / 2; m_axes.m_ymin -= excess / 2; } else if (daspect < waspect) { float excess = m_axes.width() * (waspect / daspect - 1); m_axes.m_xmax += excess / 2; m_axes.m_xmin -= excess / 2; } m_xstep = m_axes.width() / ((m_width > 1) ? (m_width - 1) : m_width); m_ystep = m_axes.height() / ((m_height > 1) ? (m_height - 1) : m_height); } float project_x(float x) { return floor((x - m_axes.m_xmin) / m_xstep); } float project_y(float y) { return floor((m_axes.m_ymax - y) / m_ystep); } float project_w(float w) { return round(w / m_xstep); } float project_h(float h) { return round(h / m_ystep); } float project_x(int x) { return m_axes.m_xmin + x * m_xstep; } float project_y(int y) { return m_axes.m_ymax - y * m_ystep; } };