home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 27 / IOPROG_27.ISO / SOFT / SPIRO.ZIP / AUser / Jos / javas / old / Spirograph / SpiroAnim.java < prev    next >
Encoding:
Java Source  |  1998-02-05  |  12.0 KB  |  389 lines

  1. /*
  2.  * @(#)SpiroAnim.java   1.0 97/11/04 Jos van den Oever
  3.  *
  4.  * based on: <A HREF=http://www.wordsmith.org/anu/java/spirograph.html>Spiro.java</A> by Anu Garg
  5.  *
  6.  * Copyright (c) 1997 Jos van den Oever
  7.  *
  8.  */
  9.  
  10. import java.awt.AWTEvent;
  11. import java.awt.Canvas;
  12. import java.awt.Color;
  13. import java.awt.Container;
  14. import java.awt.Graphics;
  15. import java.awt.Image;
  16. import java.awt.Window;
  17. import java.awt.event.ComponentEvent;
  18. import java.awt.event.MouseEvent;
  19. import java.awt.event.WindowEvent;
  20. import java.awt.event.WindowListener;
  21.  
  22. /**
  23.  * SpiroAnim - a class that produces an animated spirograph.
  24.  *
  25.  * SpiroAnim is an ideal component for entertaining users waiting for
  26.  * downloading applications. You can add it to any Container and an animation of a
  27.  * spirograph starts. It's thread has minimum priority. You can configure the
  28.  * component to stop and start or to reset when clicked.
  29.  * <P>
  30.  * If you like this class, feel free to use it. I'd like to hear how you like
  31.  * it, so don't hesitate to inform me if you use it.
  32.  * <P>
  33.  * @author <A HREF="mailto:Jos.vandenOever@nmr.bc.wau.nl">Jos van den Oever</A>
  34.  * @version 1.00
  35.  */
  36. public class SpiroAnim extends Canvas implements Runnable, WindowListener {
  37.  
  38.     private int I = 100;                                 // Number of Iterations
  39.  
  40.     private float Rvar = 0.03f, rvar = 0.03f, ovar = 0.03f, // variation in radii
  41.                   R, r, O,                               // radii per frame
  42.                   Rnew, rnew, Onew,                      // new radii
  43.                   Rold, rold, Oold;                      // old radii
  44.  
  45.     private int cvar=200,                                // variation in color
  46.                 svar = 10,                               // variation in #frames
  47.                 redBits, blueBits, greenBits,            // current color
  48.                 rednew, greennew, bluenew,               // new colors
  49.                 redold, blueold, greenold,               // old colors
  50.                 step,                                    // current frame
  51.                 steps;                                   // # of frames
  52.  
  53.     private Thread t;                                    // the animation thread
  54.  
  55.     private boolean go,       // if paint has drawn new frame, go == true
  56.                     mouseUpStopsAnimation = true,
  57.                               // this boolean determines wheter mouseUp stops
  58.                               // the animation or reset it.
  59.                     stopped = false;
  60.  
  61.     private Image osi;        // yes, the double buffering image again
  62.  
  63.     /**
  64.     * Constructs a SpiroAnim with 100 lines per frame.
  65.     */
  66.     public SpiroAnim() {
  67.         this(100);
  68.     }
  69.  
  70.     /**
  71.     * Constructs a SpiroAnim with 100 lines per frame.
  72.     * @param mouseUpStopsAnimation if true the animation stops when clicked else resets when clicked
  73.     */
  74.     public SpiroAnim(boolean mouseUpStopsAnimation) {
  75.         this(100, mouseUpStopsAnimation);
  76.     }
  77.  
  78.     /**
  79.     * Constructs a SpiroAnim with the specified number of lines per frame.
  80.     * @param I the number of lines per frame
  81.     */
  82.     public SpiroAnim(int I) {
  83.         this(I, true);
  84.     }
  85.  
  86.     /**
  87.     * Constructs a SpiroAnim with the specified number of lines per frame.
  88.     * @param I the number of lines per frame
  89.     * @param mouseUpStopsAnimation if true the animation stops when clicked else resets when clicked
  90.     */
  91.     public SpiroAnim(int I, boolean mouseUpStopsAnimation) {
  92.         super();
  93.         this.I = (I > 0) ? I : this.I;
  94.         this.mouseUpStopsAnimation = mouseUpStopsAnimation;
  95.         reset();
  96.         enableEvents(AWTEvent.COMPONENT_EVENT_MASK);
  97.         enableEvents(AWTEvent.MOUSE_EVENT_MASK);
  98.     }
  99.  
  100.     /**
  101.     * Starts the animation.
  102.     */
  103.     public void start() {
  104.         if (t == null && !stopped) {
  105.             t = new Thread(this);
  106.             t.setPriority(Thread.MIN_PRIORITY);
  107.             t.start();
  108.         }
  109.     }
  110.  
  111.     /**
  112.     * Stops the animation.
  113.     */
  114.     public void stop() {
  115.         if (t != null) {
  116.             t.stop();
  117.             t = null;
  118.         }
  119.     }
  120.  
  121.     /**
  122.     * Called when the animation is started. Shouldn't be called by user.
  123.     */
  124.     public void run() {
  125.         while (true) {
  126.             try {
  127.                 t.sleep(40);  // 25 frames per second at maximum speed
  128.             } catch (InterruptedException e) {
  129.                 System.out.println(e);
  130.             }
  131.             if (go && isShowing()) {
  132.                 nextFrame();
  133.                 repaint();
  134.             }
  135.         }
  136.     }
  137.  
  138.     private void nextFrame() {
  139.         if (step == 0) {
  140.  
  141.             Rold = Rnew;
  142.             rold = rnew;
  143.             Oold = Onew;
  144.  
  145.             redold = rednew;
  146.             blueold = bluenew;
  147.             greenold = greennew;
  148.  
  149.             Rnew = (float)Math.max(0.1,
  150.                                    Math.min(1,
  151.                                             Rold+((Math.random()-0.5)*Rvar)));
  152.             rnew = (float)Math.max(0.1,
  153.                                    Math.min(1,
  154.                                             rold+((Math.random()-0.5)*rvar)));
  155.             Onew = (float)Math.max(0,
  156.                                    Math.min(1,
  157.                                             Oold+((Math.random()-0.5)*rvar)));
  158.  
  159.             rednew = Math.max(0,
  160.                               Math.min(255,
  161.                                        redold+(int)((Math.random()-0.5)*cvar)));
  162.             bluenew = Math.max(0,
  163.                               Math.min(255,
  164.                                       blueold+(int)((Math.random()-0.5)*cvar)));
  165.             greennew = Math.max(0,
  166.                               Math.min(255,
  167.                                      greenold+(int)((Math.random()-0.5)*cvar)));
  168.             steps = Math.max(50,
  169.                              Math.min(100,
  170.                                       steps+(int)((Math.random()-0.5)*svar)));
  171.         }
  172.  
  173.         R = Rold + (Rnew-Rold)*step/steps;
  174.         r = rold + (rnew-rold)*step/steps;
  175.         O = Oold + (Onew-Oold)*step/steps;
  176.  
  177.         redBits = redold + (rednew-redold)*step/steps;
  178.         blueBits = blueold + (bluenew-blueold)*step/steps;
  179.         greenBits = greenold + (greennew-greenold)*step/steps;
  180.         go = false;
  181.         step++;
  182.         if (step == steps) {
  183.             step = 0;
  184.         }
  185.     }
  186.  
  187.     /**
  188.     * Update method, calls paint().
  189.     * @param g the graphics object on which is to be drawn
  190.     */
  191.     public void update(Graphics g) {
  192.         paint(g);
  193.     }
  194.  
  195.     /**
  196.     * The paint method draws the spirograph using double buffering.
  197.     * @param g the graphics object on which is to be drawn
  198.     */
  199.     public void paint(Graphics g) {
  200.         if(osi == null) {
  201.             osi = createImage(getSize().width, getSize().height);
  202.         }
  203.         Graphics osg = osi.getGraphics();
  204.         osg.setColor(getBackground());
  205.         osg.fillRect(0,0,getSize().width, getSize().height);
  206.         osg.setColor(g.getColor());
  207.         osg.setClip(0, 0, getSize().width, getSize().height);
  208.  
  209.         int x = 0, xpos = getSize().width/2;
  210.         int y = 0, ypos = getSize().height/2;
  211.         int prevx = 0;
  212.         int prevy = 0;
  213.         int t;
  214.  
  215.         float scalex = getSize().width / (2*(R + O + 2 * r));
  216.         float scaley = getSize().height/ (2*(R + O + 2 * r));
  217.  
  218.         osg.setColor(new Color(redBits, greenBits, blueBits));
  219.  
  220.         for(t=0; t<=I; t++){
  221.             prevx = x;
  222.             prevy = y;
  223.             x = (int)(scalex*((R+r)*Math.cos((double)t)
  224.                 - (r+O)*Math.cos(((R+r)/r)*t)));
  225.             y = (int)(scaley*((R+r)*Math.sin((double)t)
  226.                 - (r+O)*Math.sin(((R+r)/r)*t)));
  227.  
  228.             if (t > 0){
  229.                 osg.drawLine(prevx+xpos, prevy+ypos,
  230.                            x+xpos, y+ypos);
  231.             }
  232.         }
  233.         go = true;
  234.         g.drawImage(osi, 0, 0, null);
  235.         osg.dispose();
  236.     }
  237.  
  238.     /**
  239.     * Resets the animation.
  240.     */
  241.  
  242.     public void reset() {
  243.         Rnew = (float)Math.random();
  244.         rnew = (float)Math.random();
  245.         Onew = (float)Math.random();
  246.         rednew = (int)(Math.random()*255);
  247.         greennew = (int)(Math.random()*255);
  248.         bluenew = (int)(Math.random()*255);
  249.         nextFrame();
  250.         repaint();
  251.         step = 0;
  252.     }
  253.  
  254.     /**
  255.     * Invalidate the component. Shouldn't be called by user.
  256.     */
  257.     public void invalidate() {
  258.         super.invalidate();
  259.         osi = null;
  260.         stop();
  261.     }
  262.  
  263.     /**
  264.     * Validate the component. Is called by the system before the component is painted,
  265.     * if it has been invalidated. Shouldn't be called by user.
  266.     */
  267.     public void validate() {
  268.         super.validate();
  269.         start();
  270.     }
  271.  
  272.     /**
  273.     * Notifies the component it has been added to a Container. Shouldn't be called by user.
  274.     */
  275.     public void addNotify() {
  276.         super.addNotify();
  277.         Container p = getParent();
  278.         while (p != null && !(p instanceof Window)) {
  279.             p = p.getParent();
  280.         }
  281.         if (p instanceof Window) {
  282.             ((Window)p).addWindowListener(this);
  283.         }
  284.         start();
  285.     }
  286.  
  287.     /**
  288.     * Notifies the component is has been removed from a component. Shouldn't be called by
  289.     * user.
  290.     */
  291.     public void removeNotify() {
  292.         super.removeNotify();
  293.         Container p = getParent();
  294.         while (p != null && !(p instanceof Window)) {
  295.             p = p.getParent();
  296.         }
  297.         if (p instanceof Window) {
  298.             ((Window)p).removeWindowListener(this);
  299.         }
  300.         stop();
  301.     }
  302.  
  303.     /**
  304.     * Processes ComponentEvents concerning this component. Deals with showing and hiding
  305.     * this component. The SpiroAnim doesn't animate when hidden to save cpu time.
  306.     * @param e The ComponentEvent to be handled.
  307.     */
  308.     protected void processComponentEvent(ComponentEvent e) {
  309.         if (e.getID() == ComponentEvent.COMPONENT_HIDDEN) {
  310.             stop();
  311.         } else if (e.getID() == ComponentEvent.COMPONENT_SHOWN) {
  312.             start();
  313.         }
  314.     }
  315.  
  316.     /**
  317.     * Processes MouseEvents concerning this component. Deals with mouse clicking on this
  318.     * component. The animation starts/stops or resets on mouse click according to
  319.     * configuration.
  320.     * @param e The MouseEvent to be handled.
  321.     */
  322.     protected void processMouseEvent(MouseEvent e) {
  323.         if (e.getID() == MouseEvent.MOUSE_CLICKED) {
  324.             if (mouseUpStopsAnimation) {
  325.                 if (stopped) {
  326.                     stopped = false;
  327.                     start();
  328.                 } else {
  329.                     stopped = true;
  330.                     stop();
  331.                 }
  332.             } else {
  333.                 reset();
  334.             }
  335.         }
  336.     }
  337.  
  338.     /**
  339.     * Unused WindowListener interface function.
  340.     * @param e The WindowEvent to be handled.
  341.     */
  342.     public void windowOpened(WindowEvent e) {
  343.     }
  344.  
  345.     /**
  346.     * Unused WindowListener interface function.
  347.     * @param e The WindowEvent to be handled.
  348.     */
  349.     public void windowClosing(WindowEvent e) {
  350.     }
  351.  
  352.     /**
  353.     * Unused WindowListener interface function.
  354.     * @param e The WindowEvent to be handled.
  355.     */
  356.     public void windowClosed(WindowEvent e) {
  357.     }
  358.  
  359.     /**
  360.     * Function handles iconification of parent window to stop animation.
  361.     * This save cpu time.
  362.     * @param e The WindowEvent to be handled.
  363.     */
  364.     public void windowIconified(WindowEvent e) {
  365.         stop();
  366.     }
  367.  
  368.     /**
  369.     * Function handles deiconification of parent window to start animation.
  370.     * @param e The WindowEvent to be handled.
  371.     */
  372.     public void windowDeiconified(WindowEvent e) {
  373.         start();
  374.     }
  375.  
  376.     /**
  377.     * Unused WindowListener interface function.
  378.     * @param e The WindowEvent to be handled.
  379.     */
  380.     public void windowActivated(WindowEvent e) {
  381.     }
  382.  
  383.     /**
  384.     * Unused WindowListener interface function.
  385.     * @param e The WindowEvent to be handled.
  386.     */
  387.     public void windowDeactivated(WindowEvent e) {
  388.     }
  389. }