/* 'Murray Dragons' or what happens to the curlicue fractal (which is a discretisation of the equations of the Cornu spiral/Fresnel spiral/Euler's spiral/the clothoid) when you animate it. This version © Fergus Crawshay Murray, January 2000. Any comments or suggestions to dragons@fergusmurray.co.uk. */ import java.awt.*; import java.applet.Applet; public class Dragoric extends java.applet.Applet implements Runnable { // Main entry point when running standalone public static void main(String[] args) { Dragoric applet = new Dragoric(); applet.isStandalone = true; Frame frame = new Frame(); frame.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { Frame f = (Frame) e.getSource(); f.setVisible(false); f.dispose(); System.exit(0); } }); frame.setTitle("Applet Frame"); frame.add( applet, BorderLayout.CENTER ); applet.init(); applet.start(); frame.setSize( 768, 576 ); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); frame.setLocation( (d.width - frame.getSize().width) / 2, (d.height - frame.getSize().height) / 2); frame.setVisible( true ); } /* Notes on variables: count is incremented each step, reset each frame; number is incremented each 'frame'; idx is used by the sine and cosine lookup functions; i is used in setting up the sine/cosine & colour lookup tables; x and y are integer approximations of the true coordinates of the 'turtle'; ox and oy are x and y from the previous frame; drawer represents the kind of 'paintbrush' used - 0 means lines, n (!=0) means squares of size n; xcentre and ycentre are pretty obvious; symmetry, unsurprisingly, represents the kind of symmetry imposed; direction says whether the shape is going in 'reverse' or not; realx and realy are the true, floating-point values of the turtle coordinates; f represents the angle of the turtle; d is the rate of change of f; seed is the rate of change of d, the main crucial parameter in determining the shape; hue represents the hue, used when creating the colour lookup table; sineArray[] holds the sine lookup table (also used for cosine); colours[] holds all the colours; clearNow is true if it's time to clear the frame; leng is the length of 'dragon' calculated each frame; prop is the length actually drawn (which part is drawn shifts each frame); rate indicates the rate of change of the 'dragon'; zoom is, of course, the level of zoom; ecce is the 'eccentricity' - the distance from the centre each 'dragon' starts at; wipe is the number of frames between automatic wipes (-1 means automatic wiping is turned off); tillWipe is the number of frames until the next automatic wipe. */ boolean isStandalone=false; int count, number=0, idx, i, x,y,ox,oy, drawer, xcentre=250,ycentre=250, symmetry=1, direction=1; double f,realx,realy,d,seed=0.0001; float hue=0; double sineArray[]=new double[257]; Color colours[]=new Color[256]; public int leng=72,prop=64,rate=100,zoom=4,ecce=0, wipe, tillWipe; boolean clearNow=true, paused=false, watch=false; public Scrollbar lengBar,propBar,rateBar,zoomBar,ecceBar,wipeBar; public Label wipeLabel; public TextField inputBox; public TextArea paramArea; public CheckboxGroup drawType, symmGroup; public Checkbox reverseBox, pauseBox, watchBox; String theBox,symmName, moved, stepOrSteps; public ReportFrame reportFrame; public void init() { // Create lookup tables for colour and trig functions. for (i=0; i995) { wipeLabel.setText("Wipe: never."); wipe=-1; } else wipeLabel.setText("Wipe every: " + wipeBar.getValue() + " frames"); } // Update values associated with boxes. public void boxUpdate(){ theBox=drawType.getCurrent().getLabel(); if(theBox=="Lines") drawer=0; if(theBox=="Dots") drawer=1; if(theBox=="2x2 squares") drawer=2; if(theBox=="3x3 squares") drawer=3; symmName=symmGroup.getCurrent().getLabel(); if(symmName=="1 R") symmetry=1; if(symmName=="2 R") symmetry=2; if(symmName=="1 R, 1 M") symmetry=3; if(symmName=="1 R, 2 M") symmetry=4; if(reverseBox.getState()==true) direction=-1; if(reverseBox.getState()==false) direction=1; paused=pauseBox.getState(); watch=watchBox.getState(); } // Starts a thread for the animation. Thread dragonThread; public void start() { if (dragonThread == null) { dragonThread = new Thread(this, "dragon"); dragonThread.start(); } } // Defines the basic behaviour of the applet. public void run() { while (dragonThread != null) { if (!paused){ repaint(); number+=1;} try { dragonThread.sleep(10); } catch (InterruptedException e){ } } } // The real substance of the program is contained here, in the paint method. public void paint (Graphics drago) { if(!paused){ if (tillWipe==0) { clearNow=true; tillWipe=wipe; } tillWipe-=1; if (clearNow){ drago.setColor(Color.black); drago.fillRect(0,0,1280,1024); clearNow=false; } seed=seed+0.00000004*rate*direction; count=0; ox=ecce; oy=ecce; x=ox; y=oy; realx=ecce; realy=ecce; f=0; d=0; while (countMath.PI*2) f-=Math.PI*2; if (d>Math.PI*2) d-=Math.PI*2; if (f<0) f+=Math.PI*2; if (d<0) d+=Math.PI*2; realx+=zoom*(cosine(f)); realy+=zoom*(sine(f)); if (Math.abs(f)<0.0001 && Math.abs(d)<0.0001 && watch) { paused=true; report(); break; } x=(int)realx; y=(int)realy; drago.setColor(colours[(count+number)%255]); if ((count+number)%leng