Buddhabrot (java)
De GirinoWiki
Por ser mais complexa que as outras, esta applet foi dividida em diversas classes, num modelo MVC usando os Padrões de Projeto de operadores. O pacote java utilizadopara as classes é o mesmo das outras implementações de fractais: org.girino.frac.
Aqui seguem as classes e um exemplo de HTML para usá-las:
Tabela de conteúdo |
[editar] org.girino.frac.BuddhaBrotApplet.java
package org.girino.frac; import java.applet.Applet; import java.awt.Button; import java.awt.Checkbox; import java.awt.Color; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.Panel; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.text.NumberFormat; import java.util.Calendar; import java.util.Properties; import javax.imageio.ImageIO; import org.girino.frac.operators.InverseBuddhaOperator; /** * Applet to display BuddhaBrot sets. This applet * is only the view part of the system. Can be used with different * engines to display different fractals. * * The most important method is drawCurrentState(BuddhaOperator model); * This is what is called by the controler. * * @author girino * */ public class BuddhaBrotApplet extends Applet { /** * This can be used to adjust the apearance of the buddha. values of 0.3-0.5 * tends to be more buddha like. Above that very little detail is visible. * Bellow this, too much detail is shown and it looks more like a big ball. */ private static final double COLOR_EXPONENT_BLUE = 0.5; private static final double COLOR_EXPONENT_GREEN = 0.5; private static final double COLOR_EXPONENT_RED = 0.5; /** * I was just testing changes in color... */ public static final boolean USE_MATH_POW = true; // Parameters private int viewSize; private double scale; private BuddhaBrotControler controler; // Running support private Properties defaultParameters = new Properties(); private BufferedImage image; private Panel imagePanel; // checkboxes for redrawing private Checkbox stopRed = new Checkbox("Stop Red"); private Checkbox stopGreen = new Checkbox("Stop Green"); private Checkbox stopBlue = new Checkbox("Stop Blue"); /** * Asks controler to start redraw thread. or whatever * @see Applet#start() */ public void start() { controler.startRedraw(); } /** * Asks controler to stop redraw thread. or whatever * @see Applet#stop() */ public void stop() { controler.stopRedraw(); } /** * Inits parameters and creates controler. * * I tryed to use MVC here so it would ease maintenance. * The Applet is the View, the controler is the Controller (duh) * And the operators are the model. * * */ public BuddhaBrotApplet() { defaultParameters.put("tamanho", "800"); defaultParameters.put("x0", "-0.28"); defaultParameters.put("y0", "0"); defaultParameters.put("escala", "2.5"); defaultParameters.put("tempoRedesenho", "3000"); defaultParameters.put("tempoAutoSave", "300000"); defaultParameters.put("operator", "org.girino.frac.operators.InverseBuddhaOperator"); //defaultParameters.put("operator", "org.girino.frac.operators.MonochromeBuddhaOperator"); //defaultParameters.put("operator", "org.girino.frac.operators.RealInverseBuddhaOperator"); //defaultParameters.put("dumpFileName","data/" + MonochromeBuddhaOperator.class.getName() + ".dmp"); defaultParameters.put("dumpFileName","data/" + InverseBuddhaOperator.class.getName() + ".dmp"); //defaultParameters.put("dumpFileName","data/" + MonochromeBuddhaOperator.class.getName() + ".dmp"); //defaultParameters.put("dumpFileName","data/" + RealInverseBuddhaOperator.class.getName() + ".dmp"); controler = new BuddhaBrotControler(this); //controler = new GridBuddhaBrotControler(this); } /** * Overides parent to allow for default values. * @see Applet#getParameter(java.lang.String) */ public String getParameter(String name) { String ret = null; try { ret = super.getParameter(name); } catch(NullPointerException e) { ; // silently ignore } if (ret == null) { return getDefaultParameter(name); } return ret; } private String getDefaultParameter(String name) { return defaultParameters.getProperty(name); } /** * inits applet, inits controler. * * Create components and even listeners. * * @see Applet#init() */ public void init() { Properties properties = getPropertiesFromApplet(); initParameters(properties); initComponents(); prepareEventListeners(); controler.init(); } /** * stupid, but i thought it would work! Poor me... * @return */ private Properties getPropertiesFromApplet() { Properties properties = new Properties(defaultParameters); String [][] params = this.getParameterInfo(); for (int i = 0; params != null && i < params.length; i++) { System.out.println(params[i][0] + "," + params[i][1] + "," + params[i][2]); properties.put(params[i][0], params[i][1]); } return properties; } /** * Inits awt components, creates panels and buttons, etc. * */ private void initComponents() { this.setLayout(null); image = new BufferedImage(viewSize, viewSize, BufferedImage.TYPE_INT_RGB); imagePanel = new Panel() { public void paint(Graphics g) { g.drawImage(image, 0, 0, null); }; }; this.add(imagePanel); imagePanel.setLocation(0,0); imagePanel.setSize(viewSize, viewSize); Panel buttonPanel = new Panel(); Button saveDataButton = new Button("Save data"); saveDataButton.addActionListener(new ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { try { controler.dumpToFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }; }); Button saveImageButton = new Button("Save image"); saveImageButton.addActionListener(new ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { try { saveImage(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }; }); final Button stopStartButton = new Button("Stop"); stopStartButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (controler.isRunningStopped()) { stopStartButton.setEnabled(false); controler.startAll(); stopStartButton.setLabel("Stop"); stopStartButton.setEnabled(true); } else { stopStartButton.setEnabled(false); controler.stopAll(); stopStartButton.setLabel("Start"); stopStartButton.setEnabled(true); } } }); buttonPanel.setLayout(new GridLayout(1,6)); buttonPanel.add(saveDataButton); buttonPanel.add(saveImageButton); buttonPanel.add(stopStartButton); buttonPanel.add(stopRed); buttonPanel.add(stopGreen); buttonPanel.add(stopBlue); this.add(buttonPanel); buttonPanel.setLocation(0,viewSize); buttonPanel.setSize(viewSize, 20); resize(viewSize,viewSize+20); } /** * Save current displayed image as png. Uses date to form file name. * @throws IOException */ protected void saveImage() throws IOException { String filename = getNewImageName(); System.err.println("Saving: " + filename); ImageIO.write(image, "png", new File(filename)); } /** * Creates a new image name based on current date and time. * @return */ private String getNewImageName() { NumberFormat f2 = NumberFormat.getInstance(); f2.setMaximumIntegerDigits(2); f2.setMinimumIntegerDigits(2); f2.setMaximumFractionDigits(0); NumberFormat f4 = NumberFormat.getInstance(); f4.setMaximumIntegerDigits(4); f4.setMinimumIntegerDigits(4); f4.setMaximumFractionDigits(0); f4.setGroupingUsed(false); Calendar now = Calendar.getInstance(); String ret = "data/"; ret += f4.format(now.get(Calendar.YEAR)); ret += f2.format(now.get(Calendar.MONTH)+1); ret += f2.format(now.get(Calendar.DAY_OF_MONTH)); ret += f2.format(now.get(Calendar.HOUR_OF_DAY)); ret += f2.format(now.get(Calendar.MINUTE)); ret += f2.format(now.get(Calendar.SECOND)); ret += ".png"; return ret; } /** * Most parameters were migrated to controler and model. * Only "tamanho" (screen size) and "escala" (scale) where kept here. * * @param p */ private void initParameters(Properties p) { viewSize = Integer.valueOf(p.getProperty("tamanho")).intValue(); scale=(double)viewSize/Double.valueOf(p.getProperty("escala")).doubleValue(); } /** * Creates event listeners for... huh... * this shouldn't be here... its not used anymore * */ private void prepareEventListeners() { addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent ev) { try { controler.dumpToFile(); } catch (IOException e) { throw new RuntimeException(e); } } }); } /** * fun part for the view... * * draws an image with current state of the set. * * @param view */ public void drawCurrentState(BuddhaOperator view) { long[][] img_red = view.getRedImage(); long[][] img_green = view.getGreenImage(); long[][] img_blue = view.getBlueImage(); for(int j = 0; j < viewSize; j++) { for (int i = 0; i < viewSize; i++) { float red = 0f; float green = 0f; float blue = 0f; if (USE_MATH_POW) { red = (stopRed.getState())?0f:Math.min((float)Math.pow(img_red[j][i]/(float)view.getMaxRed(), COLOR_EXPONENT_RED), 1); green = (stopGreen.getState())?0f:Math.min((float)Math.pow(img_green[j][i]/(float)view.getMaxGreen(), COLOR_EXPONENT_GREEN), 1); blue = (stopBlue.getState())?0f:Math.min((float)Math.pow(img_blue[j][i]/(float)view.getMaxBlue(), COLOR_EXPONENT_BLUE), 1); } else { red = (stopRed.getState())?0f:Math.min(img_red[j][i]/(float)view.getMaxRed(), 1); green = (stopGreen.getState())?0f:Math.min(img_green[j][i]/(float)view.getMaxGreen(), 1); blue = (stopBlue.getState())?0f:Math.min(img_blue[j][i]/(float)view.getMaxBlue(), 1); } Color c = new Color(red, green, blue); image.setRGB(i,j,c.getRGB()); if (controler.isRedrawStopped()) { return; } } } Graphics g = imagePanel.getGraphics(); g.drawImage(image, 0, 0, null); } public double rescaleX(double xf) { return (xf-viewSize/2)/scale + controler.getX(); } public double rescaleY(double yf) { return (yf-viewSize/2)/scale + controler.getY(); } public double revertScaleX(double xf) { return (xf-controler.getX())*scale + viewSize/2; } public double revertScaleY(double yf) { return (yf-controler.getY())*scale + viewSize/2; } public static void main(String[] args) { BuddhaBrotApplet applet = new BuddhaBrotApplet(); applet.init(); applet.start(); applet.stop(); runPrompt(applet); } private static void runPrompt(BuddhaBrotApplet applet) { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); while (true) { System.out.println("Valid commands: quit"); System.out.print("> "); String line = null; try { line = in.readLine(); } catch (IOException e) { ; // silently ignore errors. } if (line != null && line.equalsIgnoreCase("quit")) { break; } else { System.out.println("Error: Invalid command."); } } applet.controler.stopAll(); try { applet.controler.dumpToFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public double getScale() { return scale; } public void setScale(double scale) { this.scale = scale; } public int getViewSize() { return viewSize; } public void setViewSize(int size) { this.viewSize = size; } }
[editar] org.girino.frac.BuddhaBrotControler.java
package org.girino.frac; import java.io.IOException; import org.girino.frac.operators.NormalBuddhaOperator; /** * This class is the controler part of the buddhabrot system. * It creates threads for updating screens, * autosaving and also for doing the calculations. * * The logic is kept here (except for the formulas, which is * considered as model and is thus in the Operator). * * @author girino * */ public class BuddhaBrotControler { private boolean runningStopped = false; private boolean redrawStopped = false; private boolean savingStopped = false; private Thread runnerThread = null; private Thread repaintThread = null; private Thread savingThread = null; // must rename to model. private BuddhaOperator operator; private BuddhaBrotApplet view; // initial coordinates private double x; private double y; // times private int savingTime = 300000; private int redrawTime = 4000; /** * Creates and keeps the view for future use. * * @param view */ public BuddhaBrotControler(BuddhaBrotApplet view) { this.view = view; } /** * Starts All the threads. * */ public void startAll() { startRunning(); startRedraw(); startAutoSave(); } /** * Starts autosave threads. * */ public void startAutoSave() { savingStopped = false; createSavingThread(); System.err.println("startAutoSave"); } /** * Starts redraw threads. * */ public void startRedraw() { redrawStopped = false; createRedrawThread(); System.err.println("startRedraw"); } /** * starts calculation threads. * */ public void startRunning() { runningStopped = false; createRunnerThread(); System.err.println("startRunning"); } /** * stop all threads. * */ public void stopAll() { // asks them to finish beforehand runningStopped = redrawStopped = savingStopped = false; stopRunning(); stopRedraw(); stopAutoSave(); } /** * stop redraw threds. * */ public void stopRedraw() { redrawStopped = true; if (repaintThread != null) { try { repaintThread.join(); } catch (InterruptedException e) { } } repaintThread = null; System.err.println("stopRedraw"); } /** * stop calculation threads. * */ public void stopRunning() { runningStopped = true; if (runnerThread != null) { try { runnerThread.join(); } catch (InterruptedException e) { } } runnerThread = null; System.err.println("stopRunning"); } /** * stop autosave threads. * */ public void stopAutoSave() { savingStopped= true; if (savingThread != null) { try { savingThread.join(); } catch (InterruptedException e) { } } savingThread = null; System.err.println("stopAutoSave"); } /** * Create sthe thread that is going to control the calculation. * The thread is an anonymous inner class for convenience. * */ private void createRunnerThread() { if(runnerThread == null) { runningStopped = false; runnerThread = new Thread(new Runnable() { public void run() { while (!runningStopped) { nextpoints(); } } }); runnerThread.start(); } } /** * Create sthe thread that is going to control the screen redrawing. * The thread is an anonymous inner class for convenience. * parameter "tempoRedesenho" is used to calculate the interval between * redraws. * */ private void createRedrawThread() { if(repaintThread == null) { redrawStopped = false; repaintThread = new Thread(new Runnable() { public void run() { view.drawCurrentState(operator); while (!redrawStopped) { try { Thread.sleep(redrawTime); view.drawCurrentState(operator); } catch (InterruptedException e) { e.printStackTrace(); } } } }); repaintThread.start(); } } /** * Create sthe thread that is going to control the auto saving. * The thread is an anonymous inner class for convenience. * parameter "tempoAutoSave" is used to calculate the interval between * savings. */ private void createSavingThread() { if(savingThread == null) { savingStopped = false; savingThread = new Thread(new Runnable() { public void run() { while (!savingStopped) { try { Thread.sleep(savingTime); operator.dumpToFile("data/" + operator.getClass().getName() + ".dmp"); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }); savingThread.start(); } } /** * initializes the controler and starts the threads. * */ public void init() { initParameters(); startAll(); } private void recoverDumpedOperator(String fileName) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { BuddhaOperator dummy = new NormalBuddhaOperator(); operator = dummy.loadFromFile(fileName); } private void createOperator(String operatorName) throws InstantiationException, IllegalAccessException, ClassNotFoundException { operator = (BuddhaOperator)Class.forName(operatorName).newInstance(); operator.init(view); } /** * Reads parameters fro mthe view (must change that). * */ public void initParameters() { x = Double.valueOf(view.getParameter("x0")).doubleValue(); y = Double.valueOf(view.getParameter("y0")).doubleValue(); redrawTime = Integer.valueOf(view.getParameter("tempoRedesenho")).intValue(); savingTime = Integer.valueOf(view.getParameter("tempoAutoSave")).intValue(); if (view.getParameter("dumpFileName") != null) { try { recoverDumpedOperator(view.getParameter("dumpFileName")); } catch (Exception e) { ; //silently ignores System.err.println("Could not open file: " + view.getParameter("dumpFileName")); } } if (operator == null) { try { createOperator(view.getParameter("operator")); } catch (Exception e) { throw new RuntimeException(e); } } } /** * Calculates (and keeps calculating forever until stoped) * the buddahbrot set. * * This algorithm uses random points. A grid can be also used in * other implementations * @see GridBuddhaBrotControler#nextpoints() * */ protected void nextpoints() { int[][] img_cache = new int[operator.getMaxIterations()][2]; double multiplier = 4 * (double)view.getViewSize()/(double)view.getScale(); while (!runningStopped) { double a = (Math.random() - 0.5) * multiplier + x; double b = (Math.random() - 0.5) * multiplier + y; // optimization from http://en.wikipedia.org/wiki/User:Evercat/Buddhabrot.c if ((a > -1.2 && a <= -1.1 && b > -0.1 && b < 0.1) || (a > -1.1 && a <= -0.9 && b > -0.2 && b < 0.2) || (a > -0.9 && a <= -0.8 && b > -0.1 && b < 0.1) || (a > -0.69 && a <= -0.61 && b > -0.2 && b < 0.2) || (a > -0.61 && a <= -0.5 && b > -0.37 && b < 0.37) || (a > -0.5 && a <= -0.39 && b > -0.48 && b < 0.48) || (a > -0.39 && a <= 0.14 && b > -0.55 && b < 0.55) || (a > 0.14 && a < 0.29 && b > -0.42 && b < -0.07) || (a > 0.14 && a < 0.29 && b > 0.07 && b < 0.42)) { continue; } double aa = a; double bb = b; int iter = 0; double mag2 = 0;; do { double aanew = operator.calcReal(aa, bb, a , b); double bbnew = operator.calcImaginary(aa, bb, a, b); aa = aanew; bb = bbnew; mag2 = aa*aa + bb*bb; double pointx = view.revertScaleX(aa); double pointy = view.revertScaleY(bb); img_cache[iter][0] = (int)Math.floor(pointx); img_cache[iter][1] = (int)Math.floor(pointy); iter++; } while ( (iter < operator.getMaxIterations()) && (mag2 < 4) ); operator.apply(iter, mag2, img_cache); } } /** * saves the current state (actually saves the operator); * * @throws IOException */ public void dumpToFile() throws IOException { operator.dumpToFile("data/" + operator.getClass().getName() + ".dmp"); } /** * gets the coordinates for the center of the screen. * @return x */ public double getX() { return x; } /** * gets the coordinates for the center of the screen. * @return y */ public double getY() { return y; } /** * checks if redraw is stoped. * @return */ public boolean isRedrawStopped() { return redrawStopped; } /** * checks if calculation is stoped. * @return */ public boolean isRunningStopped() { return runningStopped; } /** * checks if autosave is stoped. * @return */ public boolean isSavingStopped() { return savingStopped; } /** * means for subclasses to access the model. * * @return */ protected BuddhaOperator getOperator() { return operator; } /** * means for subclasses to access the view. * * @return */ protected BuddhaBrotApplet getView() { return view; } }
[editar] org.girino.frac.BuddhaOperator.java
package org.girino.frac; import java.applet.Applet; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; /** * interface that provides all needed services for a buddha operator. * A buddha operator is the model (in this context, the formula and * the data holder for the image values) of the buddhabrot system. * @author girino * */ public interface BuddhaOperator extends Serializable { /** * gets parameters from the applet. * * @param parent */ public void init(Applet parent); /** * gets the array of red points. * @return */ public long[][] getRedImage(); /** * gets the array of green points. * @return */ public long[][] getGreenImage(); /** * gets the array of blue points. * @return */ public long[][] getBlueImage(); /** * sets a new array of red points. * @param image */ public void setRedImage(long[][] image); /** * sets a new array of green points. * @param image */ public void setGreenImage(long[][] image); /** * sets a new array of blue points. * @param image */ public void setBlueImage(long[][] image); /** * retuns the maximum value found for a red point. * @return */ public long getMaxRed(); /** * retuns the maximum value found for a green point. * @return */ public long getMaxGreen(); /** * retuns the maximum value found for a blue point. * @return */ public long getMaxBlue(); /** * sets the right points in the images given an iteration from the controler. * @param numIterations * @param mag2 * @param cacheImage */ public void apply(int numIterations, double mag2, int[][] cacheImage); /** * calculates the real part of the formula. * @param x * @param y * @param x0 * @param y0 * @return */ public double calcReal(double x, double y, double x0, double y0); /** * Calculates the imaginary part of the formula. * @param x * @param y * @param x0 * @param y0 * @return */ public double calcImaginary(double x, double y, double x0, double y0); /** * returns the maximum number of iterations needed for thsi formula. * @return */ public int getMaxIterations(); /** * dumps this data to file. * * @param string * @throws IOException */ public void dumpToFile(String string) throws IOException; /** * load a new model from file. * @param filename * @return * @throws IOException * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalAccessException */ public BuddhaOperator loadFromFile(String filename) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException; /** * initializes data from a stream (used by subclasses of a given model). * @param in * @throws IOException * @throws ClassNotFoundException */ public void initFromFile(ObjectInputStream in) throws IOException, ClassNotFoundException; }
[editar] org.girino.frac.operators.InverseBuddhaOperator.java
package org.girino.frac.operators; /** * So, this is not inverse at all, this is actually the right one! * I thought it was inverse at first because i was dumb, * stupid or something.. don't really know! * @author girino * */ public class InverseBuddhaOperator extends NormalBuddhaOperator { private int depth_blue = 50; private int depth_green = 200; private int depth_red = 1000; /** * So this is where I check if the iteration s deserving of being plotted and * record the points i want plotted. I dont plot, this is the view's part. * * In this, I get fast escapes in blue, medium escapes in green and * slow escapes (up do getMaxIterations()) in red. * I don't plot non escapes (> getMaxIterations()). * */ public void apply(int numIterations, double mag2, int[][] cacheImage) { if (mag2 < 4) { return; } else if ( (numIterations < getDepth_blue()) ) { for (int j = 0; j < numIterations; j++) { if (cacheImage[j][0] < size && cacheImage[j][1] < size && cacheImage[j][0] >= 0 && cacheImage[j][1] >= 0) { blueImage[cacheImage[j][0]][cacheImage[j][1]]++; if (blueImage[cacheImage[j][0]][cacheImage[j][1]] > maxBlue) { maxBlue = blueImage[cacheImage[j][0]][cacheImage[j][1]]; } } } } else if ( (numIterations < getDepth_green()) ) { for (int j = 0; j < numIterations; j++) { if (cacheImage[j][0] < size && cacheImage[j][1] < size && cacheImage[j][0] >= 0 && cacheImage[j][1] >= 0) { greenImage[cacheImage[j][0]][cacheImage[j][1]]++; if (greenImage[cacheImage[j][0]][cacheImage[j][1]] > maxGreen) { maxGreen = greenImage[cacheImage[j][0]][cacheImage[j][1]]; } } } } else if ( (numIterations < getDepth_red()) ) { for (int j = 0; j < numIterations; j++) { if (cacheImage[j][0] < size && cacheImage[j][1] < size && cacheImage[j][0] >= 0 && cacheImage[j][1] >= 0) { redImage[cacheImage[j][0]][cacheImage[j][1]]++; if (redImage[cacheImage[j][0]][cacheImage[j][1]] > maxRed) { maxRed = redImage[cacheImage[j][0]][cacheImage[j][1]]; } } } } } /** * maximum number of iterations i'm interested on. * This is for the model to know when to stop. */ public int getMaxIterations() { return getDepth_red(); } /** * these are for helping the view compensating colors. */ public void setDepth_blue(int depth_blue) { this.depth_blue = depth_blue; } /** * these are for helping the view compensating colors. */ public int getDepth_blue() { return depth_blue; } /** * these are for helping the view compensating colors. */ public void setDepth_green(int depth_green) { this.depth_green = depth_green; } /** * these are for helping the view compensating colors. */ public int getDepth_green() { return depth_green; } /** * these are for helping the view compensating colors. */ public void setDepth_red(int depth_red) { this.depth_red = depth_red; } /** * these are for helping the view compensating colors. */ public int getDepth_red() { return depth_red; } }
[editar] org.girino.frac.operators.NormalBuddhaOperator.java
package org.girino.frac.operators; import java.applet.Applet; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import org.girino.frac.BuddhaOperator; /** * I thought this was normal, but it's actually inverse. * I'm too lazy to rename now! * * This is also base class for all other controlers. * * @author girino * */ public class NormalBuddhaOperator implements BuddhaOperator { private static final int MAGIC_NUMBER = 20060614; private int depth_blue = 500; private int depth_green = 2000; private int depth_red = 5000; /** guess I figured out subclasses might need these... dunno... */ protected long[][] redImage; /** guess I figured out subclasses might need these... dunno... */ protected long[][] greenImage; /** guess I figured out subclasses might need these... dunno... */ protected long[][] blueImage; /** guess I figured out subclasses might need these... dunno... */ protected long maxRed; /** guess I figured out subclasses might need these... dunno... */ protected long maxGreen; /** guess I figured out subclasses might need these... dunno... */ protected long maxBlue; /** guess I figured out subclasses might need these... dunno... */ protected int size; /** * creates new image arrays and initializes params. */ public void init(Applet parent) { size = Integer.parseInt(parent.getParameter("tamanho")); setRedImage(new long[size][size]); setGreenImage(new long[size][size]); setBlueImage(new long[size][size]); } /** * calculations. * gets pretty much the not escaped points. Blue for those not escaping * in few iterations, red for thos not escaping at all (at least in * getMaxIterations() iterations). Green for the medium ones. */ public void apply(int numIterations, double mag2, int[][] cacheImage) { if ( (numIterations >= getDepth_blue()) ) { for (int j = 0; j < getDepth_blue(); j++) { if (cacheImage[j][0] < size && cacheImage[j][1] < size && cacheImage[j][0] >= 0 && cacheImage[j][1] >= 0) { blueImage[cacheImage[j][0]][cacheImage[j][1]]++; if (blueImage[cacheImage[j][0]][cacheImage[j][1]] > maxBlue) { maxBlue = blueImage[cacheImage[j][0]][cacheImage[j][1]]; } } } } if ( (numIterations >= getDepth_red()) ) { for (int j = 0; j < getDepth_red(); j++) { if (cacheImage[j][0] < size && cacheImage[j][1] < size && cacheImage[j][0] >= 0 && cacheImage[j][1] >= 0) { redImage[cacheImage[j][0]][cacheImage[j][1]]++; if (redImage[cacheImage[j][0]][cacheImage[j][1]] > maxRed) { maxRed = redImage[cacheImage[j][0]][cacheImage[j][1]]; } } } } if ( (numIterations >= getDepth_green()) ) { for (int j = 0; j < getDepth_green(); j++) { if (cacheImage[j][0] < size && cacheImage[j][1] < size && cacheImage[j][0] >= 0 && cacheImage[j][1] >= 0) { greenImage[cacheImage[j][0]][cacheImage[j][1]]++; if (greenImage[cacheImage[j][0]][cacheImage[j][1]] > maxGreen) { maxGreen = greenImage[cacheImage[j][0]][cacheImage[j][1]]; } } } } } /** * calculates mandelbrot set for a point. */ public double calcReal(double x, double y, double x0, double y0) { return x*x - y*y + x0; } /** * calculates mandelbrot set for a point. */ public double calcImaginary(double x, double y, double x0, double y0) { return 2*x*y + y0; } /** * @see BuddhaOperator#getBlueImage() */ public long[][] getBlueImage() { return blueImage; } /** * @see BuddhaOperator#setBlueImage(long[][]) */ public void setBlueImage(long[][] blueImage) { this.blueImage = blueImage; } /** * @see BuddhaOperator#getGreenImage() */ public long[][] getGreenImage() { return greenImage; } /** * @see BuddhaOperator#setGreenImage(long[][]) */ public void setGreenImage(long[][] greenImage) { this.greenImage = greenImage; } /** * @see BuddhaOperator#getRedImage() */ public long[][] getRedImage() { return redImage; } /** * @see BuddhaOperator#setRedImage(long[][]) */ public void setRedImage(long[][] redImage) { this.redImage = redImage; } /** * @see BuddhaOperator#getMaxIterations(); */ public int getMaxIterations() { return getDepth_red(); } /** * @see BuddhaOperator#getMaxBlue() */ public long getMaxBlue() { return maxBlue; } /** * @see BuddhaOperator#getMaxGreen() */ public long getMaxGreen() { return maxGreen; } /** * @see BuddhaOperator#getMaxRed() */ public long getMaxRed() { return maxRed; } /** * @see BuddhaOperator#dumpToFile(String) */ public void dumpToFile(String filename) throws IOException { System.out.println("Writing..."); FileOutputStream fout = new FileOutputStream(filename); ObjectOutputStream out = new ObjectOutputStream(fout); // first we write some file identifier. In our case I chose todays date out.writeObject(new Integer(MAGIC_NUMBER)); // then write the class name for current object. Or better, // write the class object so we just need to read it afterwards. out.writeObject(this.getClass()); // now delegate internalDumpToFile(out); // flush and close out.close(); fout.flush(); fout.close(); System.out.println("Writen!"); } /** * yeah, this is for subclasses. Maybe Ishould add to the * interface? this stores subclass specific data. */ protected void internalDumpToFile(ObjectOutputStream out) throws IOException { // for most classes this might work... which means, writes down max values // and image arrays in the order R then G then B. out.writeObject(redImage); out.writeObject(greenImage); out.writeObject(blueImage); // max values come afterwards so we avoid sync errors ;) // actually we don't avoid "errors", just exceptions. out.writeObject(new Long(maxRed)