You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
8.3 KiB

  1. package verteiltesysteme.mandelbrot;
  2. //Mandelbot Example A. Gepperth
  3. import java.awt.Color;
  4. import java.awt.Graphics;
  5. import java.awt.event.ActionEvent;
  6. import java.awt.event.ActionListener;
  7. import java.awt.event.MouseEvent;
  8. import java.awt.event.MouseListener;
  9. import java.awt.event.MouseMotionListener;
  10. import java.awt.image.BufferedImage;
  11. import javax.swing.ImageIcon;
  12. import javax.swing.JButton;
  13. import javax.swing.JFrame;
  14. import javax.swing.JLabel;
  15. import javax.swing.JPanel;
  16. import javax.swing.JSlider;
  17. import javax.swing.event.ChangeEvent;
  18. import javax.swing.event.ChangeListener;
  19. class Complex {
  20. double r;
  21. double i;
  22. Complex() {
  23. r = 0.0;
  24. i = 0.0;
  25. }
  26. Complex(double r, double i) {
  27. this.r = r;
  28. this.i = i;
  29. }
  30. void mulBy(Complex other) {
  31. double rTmp = this.r * other.r - this.i * other.i;
  32. this.i = this.r * other.i + this.i * other.r;
  33. this.r = rTmp;
  34. }
  35. void add(Complex other) {
  36. this.r += other.r;
  37. this.i += other.i;
  38. }
  39. void sub(Complex other) {
  40. this.r -= other.r;
  41. this.i -= other.i;
  42. }
  43. double absValue() {
  44. return Math.sqrt(this.r * this.r + this.i * this.i);
  45. }
  46. }
  47. class MandelbrotCalculations {
  48. // hier wird das Ergebnis von iterateAll() gespeichert
  49. protected int[] result = null;
  50. // der augenblicklich gewaehlte Ausschnitt
  51. //double ULx = -2, ULy = -2, LRx = 2, LRy = 2;
  52. double ULx = -0.16099999999999995, ULy = -0.9365333333333333, LRx = -0.03533333333333327, LRy = -0.8108666666666666;
  53. int iterateOnePoint(Complex c, int maxIterations, double maxModulus) {
  54. Complex z = new Complex(0., 0.);
  55. for (int i = 0; i < maxIterations; i++) {
  56. z.mulBy(z);
  57. z.add(c);
  58. double m = z.absValue();
  59. if (m > maxModulus) {
  60. return i;
  61. }
  62. }
  63. return maxIterations;
  64. }
  65. void iterateAllPoints(int maxIterations, double nrPointsX, double nrPointsY) {
  66. this.result = new int[(int) (nrPointsX * nrPointsY)];
  67. int counter = 0;
  68. double stepX = (this.LRx - this.ULx) / nrPointsX;
  69. double stepY = (this.LRy - this.ULy) / nrPointsY;
  70. double i = this.ULy;
  71. for (int cy = 0; cy < nrPointsY; cy++) {
  72. double r = this.ULx;
  73. for (int cx = 0; cx < nrPointsX; cx++) {
  74. Complex c = new Complex(r, i);
  75. this.result[counter] = maxIterations - this.iterateOnePoint(c, maxIterations, 2.0);
  76. counter += 1;
  77. r += stepX;
  78. }
  79. i += stepY;
  80. }
  81. }
  82. public int[] getResult() {
  83. return this.result;
  84. }
  85. public double getULx() {
  86. return this.ULx;
  87. }
  88. public double getLRx() {
  89. return this.LRx;
  90. }
  91. public double getULy() {
  92. return this.ULy;
  93. }
  94. public double getLRy() {
  95. return this.LRy;
  96. }
  97. public void setView(double ULx, double ULy, double LRx, double LRy) {
  98. this.ULx = ULx;
  99. this.ULy = ULy;
  100. this.LRx = LRx;
  101. this.LRy = LRy;
  102. }
  103. }
  104. class MyJLabel extends JLabel {
  105. /**
  106. *
  107. */
  108. private static final long serialVersionUID = -5184881932223853807L;
  109. int boxULx, boxULy, boxW, boxH;
  110. MyJLabel() {
  111. super();
  112. }
  113. MyJLabel(String s) {
  114. super(s);
  115. }
  116. void setBox(int boxULx, int boxULy, int boxW, int boxH) {
  117. this.boxULx = boxULx;
  118. this.boxULy = boxULy;
  119. this.boxW = boxW;
  120. this.boxH = boxH;
  121. }
  122. @Override
  123. protected void paintComponent(Graphics g) {
  124. super.paintComponent(g);
  125. g.setColor(Color.black);
  126. g.drawRect(this.boxULx, this.boxULy, this.boxW, this.boxH);
  127. }
  128. }
  129. public class MGui implements ActionListener, ChangeListener, MouseListener, MouseMotionListener {
  130. // GUI elements
  131. JFrame frame;
  132. JPanel panel;
  133. JButton endButton;
  134. JButton backButton;
  135. JButton calcButton;
  136. JSlider maxIterations;
  137. MyJLabel view;
  138. int nrIterations;
  139. // box management
  140. int boxULx, boxULy, boxW, boxH;
  141. boolean dragging = false;
  142. // this one does all the calculating work
  143. MandelbrotCalculations calcObj;
  144. // how many points in the image?
  145. // change if you want a higher resolution
  146. public static final int RESX = 600;
  147. public static final int RESY = 600;
  148. MGui() {
  149. // set up GUI
  150. this.frame = new JFrame("Mandelbrotmenge");
  151. this.panel = new JPanel();
  152. this.endButton = new JButton("Ende");
  153. this.panel.add(this.endButton);
  154. this.backButton = new JButton("Zurueck");
  155. this.panel.add(this.backButton);
  156. this.calcButton = new JButton("Rechnen");
  157. this.panel.add(this.calcButton);
  158. this.frame.add(this.panel);
  159. this.frame.setSize(500, 500);
  160. this.frame.setVisible(true);
  161. this.view = new MyJLabel("Platzhalter");
  162. this.maxIterations = new JSlider(0, 50, 30);
  163. this.panel.add(this.maxIterations);
  164. this.panel.add(this.view);
  165. this.endButton.addActionListener(this);
  166. this.backButton.addActionListener(this);
  167. this.calcButton.addActionListener(this);
  168. this.maxIterations.addChangeListener(this);
  169. this.maxIterations.setMajorTickSpacing(10);
  170. this.maxIterations.setPaintTicks(true);
  171. this.maxIterations.setPaintLabels(true);
  172. this.view.addMouseListener(this);
  173. this.view.addMouseMotionListener(this);
  174. this.boxULx = 0;
  175. this.boxULy = 0;
  176. this.boxW = MGui.RESX;
  177. this.boxH = MGui.RESY;
  178. // Non-Gui stuff
  179. this.calcObj = new MandelbrotCalculations();
  180. this.nrIterations = 1000;
  181. }
  182. // visualization related stuff, do not touch!
  183. int[] generateLookupTable(int nrHues) {
  184. int[] tmp = new int[nrHues + 1];
  185. int cycle = 2048;
  186. for (int i = 0; i < nrHues; i++) {
  187. float hue = 1 * ((float) (i % cycle)) / cycle/* ((float)nrHues) */ ;
  188. tmp[i] = Color.HSBtoRGB(hue, 0.8f, 1.0f);
  189. }
  190. tmp[0] = Color.HSBtoRGB(0f, 1.0f, 0.0f);
  191. return tmp;
  192. }
  193. // visualization
  194. static void applyLookupTable(int[] data, int[] dest, int[] lookupTable) {
  195. for (int i = 0; i < data.length; i++) {
  196. dest[i] = lookupTable[data[i]];
  197. }
  198. }
  199. // here we check what the buttons do
  200. public void actionPerformed(ActionEvent ae) {
  201. if (ae.getSource() == this.endButton) {
  202. System.out.println("Ende");
  203. System.exit(0);
  204. } else
  205. if (ae.getSource() == this.backButton) {
  206. System.out.println("Zurueck");
  207. } else
  208. if (ae.getSource() == this.calcButton) {
  209. System.out.println("Rechnen");
  210. long timestampStart = System.currentTimeMillis();
  211. double ULx = this.calcObj.getULx();
  212. double ULy = this.calcObj.getULy();
  213. double LRx = this.calcObj.getLRx();
  214. double LRy = this.calcObj.getLRy();
  215. double w = LRx - ULx;
  216. double h = LRy - ULy;
  217. ULx = ULx + w * this.boxULx / (double) MGui.RESX;
  218. ULy = ULy + h * this.boxULy / (double) MGui.RESY;
  219. w *= this.boxW / (double) (RESX);
  220. h *= this.boxH / (double) (RESX);
  221. LRx = ULx + w;
  222. LRy = ULy + h;
  223. System.out.println(ULx + "/" + ULy + "/" + LRx + "/" + LRy);
  224. this.boxULx = 0;
  225. this.boxULy = 0;
  226. this.boxW = MGui.RESX;
  227. this.boxH = MGui.RESY;
  228. this.calcObj.setView(ULx, ULy, LRx, LRy);
  229. this.calcObj.iterateAllPoints(this.maxIterations.getValue() * 1000, MGui.RESX, MGui.RESY);
  230. int[] lookupTable = generateLookupTable(this.maxIterations.getValue() * 1000);
  231. int[] colors = new int[MGui.RESX * MGui.RESY];
  232. MGui.applyLookupTable(calcObj.getResult(), colors, lookupTable);
  233. BufferedImage colorImage = new BufferedImage(MGui.RESX, MGui.RESY, BufferedImage.TYPE_INT_ARGB);
  234. colorImage.setRGB(0, 0, MGui.RESX, MGui.RESY, colors, 0, MGui.RESX);
  235. this.view.setIcon(new ImageIcon(colorImage));
  236. long timestampEnd = System.currentTimeMillis();
  237. String timeElapsed = "Zeit: " + ((timestampEnd - timestampStart) / 1000.0) + " sec";
  238. System.out.println(timeElapsed);
  239. this.view.setText(timeElapsed);
  240. }
  241. }
  242. public void mousePressed(MouseEvent e) {
  243. this.boxULx = e.getX();
  244. this.boxULy = e.getY();
  245. this.boxW = 1;
  246. this.boxH = 1;
  247. this.view.setBox(this.boxULx, this.boxULy, this.boxW, this.boxH);
  248. }
  249. public void mouseDragged(MouseEvent e) {
  250. this.boxW = e.getX() - this.boxULx + 1;
  251. this.boxH = e.getY() - this.boxULy + 1;
  252. int m = Math.min(boxW, boxH);
  253. this.boxW = m;
  254. this.boxH = m;
  255. this.view.setBox(this.boxULx, this.boxULy, this.boxW, this.boxH);
  256. this.view.repaint();
  257. }
  258. public void mouseReleased(MouseEvent e) {
  259. if (e.getButton() == MouseEvent.BUTTON1) {
  260. this.view.repaint();
  261. }
  262. }
  263. public void mouseMoved(MouseEvent e) {
  264. }
  265. public void mouseExited(MouseEvent e) {
  266. }
  267. public void mouseEntered(MouseEvent e) {
  268. }
  269. public void mouseClicked(MouseEvent e) {
  270. }
  271. // process a new slider value
  272. public void stateChanged(ChangeEvent ce) {
  273. if (ce.getSource() == this.maxIterations) {
  274. //System.out.println("Neuer Wert");
  275. this.nrIterations = this.maxIterations.getValue() * 1000;
  276. }
  277. }
  278. // main, just instantiate an MGui object, gives control to the Gui
  279. public static void main(String[] args) {
  280. @SuppressWarnings("unused")
  281. MGui gui = new MGui();
  282. }
  283. }