250 likes | 343 Views
Today’s topics. Java Recursion in Graphics Writing a Class Simple Animation Upcoming Simulation Reading Great Ideas , Chapters 5. Using Recursion in Graphics. Recursion can be a powerful tool Closely related to Fractals Self-similarity Keep zooming in: still looks the same
E N D
Today’s topics Java Recursion in Graphics Writing a Class Simple Animation Upcoming Simulation Reading Great Ideas, Chapters 5
Using Recursion in Graphics • Recursion can be a powerful tool • Closely related to Fractals • Self-similarity • Keep zooming in: still looks the same • Can produce very interesting figures with very little input • Serpinsky Gasket is just a lot of triangles • Define recursively
Serpinsky Gasket • Start with triangle • Then put (1/2 size) triangles within triangle
Serpinsky Gasket • Continue process with ¼ sized triangles, etc • Insight: use Serpinsky Gaskets instead of triangles
Serpinsky public class Serpinsky extends java.applet.Applet implements ActionListener { Graphics g; Canvas c; IntField iSlow; Button b1, b2, b3, b4, b5, b6, b7, b8, b9; Color col; int x, y, slow; public void init() { c = new Canvas(); c.setSize(400, 400); add(c); g = c.getGraphics(); b1 = new Button("Start"); b2 = new Button("Triangle"); b3 = new Button("Gasket"); b4 = new Button("Red");
Serpinsky.2 b5 = new Button("Green"); b6 = new Button("Blue"); b7 = new Button("Black"); b8 = new Button("White"); b9 = new Button("Slow"); iSlow = new IntField(10); col = Color.blue; slow = 0; b1.addActionListener(this); b2.addActionListener(this); b3.addActionListener(this); b4.addActionListener(this); b5.addActionListener(this); b6.addActionListener(this); b7.addActionListener(this); b8.addActionListener(this); b9.addActionListener(this); add(iSlow); add(b1); add(b2); add(b3); add(b4); add(b5); add(b6); add(b7); add(b8); add(b9); }
Serpinsky.3 int mid(int a, int b) { return (a + b)/2; } void triangle(int x1, int y1, int x2, int y2, int x3, int y3) { int k; k = 0; while ( k < slow) k = k + 1; // code to slow down g.drawLine(x1, y1, x2, y2); g.drawLine(x2, y2, x3, y3); g.drawLine(x3, y3, x1, y1); }
Serpinsky.4 void serpinsky(int x1, int y1, int x2, int y2, int x3, int y3) { int size, limit=10; size = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1); if (size < limit) return; // base case: do nothing! i.e.: halting case triangle(x1, y1, x2, y2, x3, y3); // recursive calls serpinsky(x1, y1, mid(x1,x2), mid(y1,y2), mid(x1,x3), mid(y1,y3)); serpinsky(x2, y2, mid(x2,x1), mid(y2,y1), mid(x2,x3), mid(y2,y3)); serpinsky(x3, y3, mid(x3,x1), mid(y3,y1), mid(x3,x2), mid(y3,y2)); }
Serpinsky.5 public void actionPerformed(ActionEvent event) { Object cause = event.getSource(); if (cause == b1) { g.setColor(Color.white); // Color the whole canvas white g.fillRect(0, 0, 400, 400); g.setColor(Color.black); g.drawString("Serpinsky Gasket", 20, 20); } if (cause == b2) { g.setColor(col); triangle(50, 310, 200, 70, 350, 310); } if (cause == b3) { g.setColor(col); serpinsky(50, 310, 200, 70, 350, 310); }
Serpinsky.6 if (cause == b4) { col = Color.red; } if (cause == b5) { col = Color.green; } if (cause == b6) { col = Color.blue; } if (cause == b7) { col = Color.black; } if (cause == b8) { col = Color.white; } if (cause == b9) { slow = iSlow.getInt(); } } }
Serpinsky Details • Note feature to slow down drawing • Get betters sense of how recursive calls work • Also see how incredibly fast computer is… • Note new graphics method void drawString(String s, int x, int y) • Review recursive features • What is done in the base case? • What would figure be like if we drew nothing except • In the base case?
Writing a Class • Have been writing one class all along • Our applet is always a class • Have used other classes such as TextFields • Rewrite Serpinsky applet • Write class named Serp which actually draws the gasket • Class requires data (instance variables) • Class requires methods (functions) • Needs constructor (to initialize) (like init in applet) • Now that we have such a class, can create many instances • Use the new operator to accomplish this: new Serp(x1, y1, x2, y2, x3, y3, g); • Where we pass in the 3 vertices of the triangle • and the Graphics object
SerpClass public class SerpClass extends java.applet.Applet implements ActionListener { Graphics g; Canvas c; Button b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11; Color col; int range = 70; public void init() { c = new Canvas(); c.setSize(400, 400); add(c); g = c.getGraphics(); b1 = new Button("Start"); b2 = new Button("NW"); b3 = new Button("NE"); b4 = new Button("SW"); b5 = new Button("SE"); b6 = new Button("CTR"); b7 = new Button("Red"); b8 = new Button("Green"); b9 = new Button("Blue"); b10 = new Button("Black");
SerpClass.2 col = Color.black; b1.addActionListener(this); b2.addActionListener(this); b3.addActionListener(this); b4.addActionListener(this); b5.addActionListener(this); b6.addActionListener(this); b7.addActionListener(this); b8.addActionListener(this); b9.addActionListener(this); b10.addActionListener(this); b11.addActionListener(this); add(b1); add(b2); add(b3); add(b4); add(b5); add(b6); add(b7); add(b8); add(b9); add(b10); add(b11); } public void actionPerformed(ActionEvent event) { Object cause = event.getSource(); if (cause == b1) { g.setColor(Color.white); // Color the whole canvas white g.fillRect(0, 0, 400, 400); g.setColor(Color.black); g.drawString("Serpinsky Gasket", 20, 20); }
SerpClass.3 if (cause == b2) { // NW int dx = -range, dy = -range; g.setColor(col); new Serp(50+dx, 310+dy, 200+dx, 70+dy, 350+dx, 310+dy, g); } if (cause == b3) { // NE int dx = range, dy = -range; g.setColor(col); new Serp(50+dx, 310+dy, 200+dx, 70+dy, 350+dx, 310+dy, g); } if (cause == b4) { // SW int dx = -range, dy = range; g.setColor(col); new Serp(50+dx, 310+dy, 200+dx, 70+dy, 350+dx, 310+dy, g); }
SerpClass.4 if (cause == b5) { // SE int dx = range, dy = range; g.setColor(col); new Serp(50+dx, 310+dy, 200+dx, 70+dy, 350+dx, 310+dy, g); } if (cause == b6) { // CTR g.setColor(col); new Serp(50, 310, 200, 70, 350, 310, g); } if (cause == b7) col = Color.red; if (cause == b8) col = Color.green; if (cause == b9) col = Color.blue; if (cause == b10) col = Color.black; if (cause == b11) col = Color.white; }
SerpClass.5 public class Serp { Graphics g; public Serp(int x1, int y1, int x2, int y2, int x3, int y3, Graphics gg) { g = gg; serpinsky(x1, y1, x2, y2, x3, y3); } public int mid(int a, int b) { return (a + b)/2; } public void triangle(int x1, int y1, int x2, int y2, int x3, int y3) { g.drawLine(x1, y1, x2, y2); g.drawLine(x2, y2, x3, y3); g.drawLine(x3, y3, x1, y1); }
SerpClass.6 public void serpinsky(int x1, int y1, int x2, int y2, int x3, int y3) { int size, limit=200; size = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1); if (size < limit) // base case return; // do nothing triangle(x1, y1, x2, y2, x3, y3); // recursive calls serpinsky(x1, y1, mid(x1,x2), mid(y1,y2), mid(x1,x3), mid(y1,y3)); serpinsky(x2, y2, mid(x2,x1), mid(y2,y1), mid(x2,x3), mid(y2,y3)); serpinsky(x3, y3, mid(x3,x1), mid(y3,y1), mid(x3,x2), mid(y3,y2)); } } }
Simple Minded Animation • Simple Recipe • Draw figure • Delay • Erases figure • Shift slightly • Repeat (step 1. , etc.) • Draw and Erase • Draw figure: is straight-forward • Erase: overdraw with background color (white) • Will demonstrate with Serpinsky Gasket
Moving Serpinsky public class SerpMove extends java.applet.Applet implements ActionListener { Graphics g; Canvas c; IntField iSlow; Button b1, b2, b3, b4, b5, b6, b7, b8, b9; Color col; int slow = 1000000; public void init() { c = new Canvas(); c.setSize(400, 400); add(c); g = c.getGraphics(); b1 = new Button("Start"); b2 = new Button("Move"); b3 = new Button("Gasket"); b4 = new Button("Red"); b5 = new Button("Green"); b6 = new Button("Blue"); b7 = new Button("Black"); b8 = new Button("White");
Moving Serpinsky.2 b9 = new Button("Slow"); iSlow = new IntField(10); col = Color.blue; b1.addActionListener(this); b2.addActionListener(this); b3.addActionListener(this); b4.addActionListener(this); b5.addActionListener(this); b6.addActionListener(this); b7.addActionListener(this); b8.addActionListener(this); b9.addActionListener(this); add(iSlow); add(b1); add(b2); add(b3); add(b4); add(b5); add(b6); add(b7); add(b8); add(b9); } public void delay() { double sum = 0.0, x = 3.14159265; int k = 0; while (k < slow) { sum = sum + 1.0/x; k = k + 1; } }
Moving Serpinsky.3 public void actionPerformed(ActionEvent event) { Object cause = event.getSource(); if (cause == b1) { g.setColor(Color.white); // Color the whole canvas white g.fillRect(0, 0, 400, 400); g.setColor(Color.black); g.drawString("Serpinsky Gasket", 20, 20); } • Interesting Part Follows • Actual Motion done here
Moving Serpinsky.4 if (cause == b2) { // move int k = 0, range = 100; int dx = -range, dy = -range; while (k < range) { dx = dx + 2; dy = dy + 2; g.setColor(col); new Serp(50+dx, 310+dy, 200+dx, 70+dy, 350+dx, 310+dy, g); delay(); g.setColor(Color.white); new Serp(50+dx, 310+dy, 200+dx, 70+dy, 350+dx, 310+dy, g); g.setColor(col); k = k + 1; } }
Moving Serpinsky.5 if (cause == b3) { g.setColor(col); new Serp(50, 310, 200, 70, 350, 310, g); } if (cause == b4) col = Color.red; if (cause == b5) col = Color.green; if (cause == b6) col = Color.blue; if (cause == b7) col = Color.black; if (cause == b8) col = Color.white; if (cause == b9) slow = iSlow.getInt(); } }
Simple Minded Animation • Did not show the Serp class which is unchanged • Quality of animation is poor: flicker, not smooth • Beats with monitor and outside lighting • Speed dependence on processor and load • Erases anything “below” • Fixing this is outside the scope of this class • Should do much in this class that we do outside • Could (should) add a number of methods • Let it handle the move, just pass new locations void setLocation(int newX, int newY) void glideTo(int newX, int newY) • The former would jump to new location, the latter would provide continuous motion