Last active
December 14, 2015 22:12
-
-
Save domgetter/450182edf3e88da7512f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns mandelclj.core | |
(:gen-class) | |
(:import | |
(sun.java2d SunGraphics2D) | |
(javax.swing JFrame JLabel) | |
(java.awt.image BufferedImage) | |
(java.awt Dimension Color) | |
(java.awt.event ActionEvent | |
ActionListener | |
MouseAdapter | |
MouseMotionListener | |
MouseEvent | |
KeyEvent | |
ActionListener))) | |
(set! *unchecked-math* :warn-on-boxed) | |
(deftype complex [^double real ^double imag]) | |
(defn plus | |
"(a + bi) + (c + di) == (a + b) + (c + d)i" | |
[^complex z1 ^complex z2] | |
(complex. (+ (.real z1) (.real z2)) (+ (.imag z1) (.imag z2)))) | |
(defn magnitude-squared | |
"|z|^2 == a^2 + b^2" | |
^double [^complex z] | |
(+ (* (.real z) (.real z)) (* (.imag z) (.imag z)))) | |
(defn times | |
"(a + bi)*(c + di) == (ac - bd) + (ad + bc)i" | |
[^complex z1 ^complex z2] | |
(complex. | |
(- (* (.real z1) (.real z2)) (* (.imag z1) (.imag z2))) | |
(+ (* (.real z1) (.imag z2)) (* (.imag z1) (.real z2))))) | |
(defn mandelbrot | |
"Calculates the number of iterations taken to escape, up to a bailout | |
(mandelbrot (complex. 0 0) 100) => 100 since [0,0] is in the set" | |
([^complex c ^long dwell] | |
(mandelbrot (complex. 0.0 0.0) c 0 dwell)) | |
(^long [z c ^long its ^long dwell] | |
(if (or (> (magnitude-squared z) 4.0) (= its dwell)) | |
its | |
(recur (plus (times z z) c) c (inc its) dwell)))) | |
(defn top-left [viewport] | |
(let [x (double ((viewport :center) 0)) | |
y (double ((viewport :center) 1)) | |
dx (double (viewport :dx)) | |
dy (double (viewport :dy))] | |
[(- x dx) (+ y dy)])) | |
(defn array-index->coord [^long index ^long rows ^long columns viewport] | |
(let [column (mod index columns) | |
row (quot index columns) | |
[x y] (top-left viewport) | |
x (double x) | |
y (double y) | |
viewport-dx (double (viewport :dx)) | |
viewport-dy (double (viewport :dy)) | |
dx (* (/ 1.0 (dec columns)) 2.0 viewport-dx) | |
dy (* (/ 1.0 (dec rows)) 2.0 viewport-dy)] | |
[(+ x (* dx (double column))) (- y (* dy (double row)))])) | |
(defn array-index->x-coord [index columns viewport-x viewport-dx] | |
(let [index (long index) | |
columns (long columns) | |
viewport-x (double viewport-x) | |
viewport-dx (double viewport-dx)] | |
(let [dx (* (/ 1.0 (dec columns)) 2.0 viewport-dx (double (mod index columns)))] | |
(+ (- viewport-x viewport-dx) dx)))) | |
(defn array-index->y-coord [index rows columns viewport-y viewport-dy] | |
(let [index (long index) | |
rows (long rows) | |
columns (long columns) | |
viewport-y (double viewport-y) | |
viewport-dy (double viewport-dy)] | |
(let [dy (* (/ 1.0 (dec rows)) 2.0 viewport-dy (quot index columns))] | |
(- (+ viewport-y viewport-dy) dy)))) | |
(def columns 500) | |
(def rows 370) | |
(defn make-int-array [rows columns] | |
{:rows rows | |
:columns columns | |
:array (make-array Integer/TYPE (* ^long rows ^long columns))}) | |
(def viewport | |
{:center [-0.5 0.0] | |
:dx 2.0 | |
:dy 2.0}) | |
(def viewports (atom (list viewport))) | |
(def output (make-int-array rows columns)) | |
(defn palette [^long i] | |
(let [i (mod i 8)] | |
([0xFF0000 0x00FF00 0x0000FF 0xFFFF00 0xFF00FF 0x00FFFF 0x0F0F0F 0xD2E729] i))) | |
(defn calc-mandelbrot-for-array [array dwell] | |
(let [raw-array (array :array) | |
array-size (long (count raw-array)) | |
viewport (first @viewports) | |
rows (long (array :rows)) | |
columns (long (array :columns)) | |
center-x (double ((viewport :center) 0)) | |
center-y (double ((viewport :center) 1)) | |
dx (double (viewport :dx)) | |
dy (double (viewport :dy))] | |
(loop [array-index 0] | |
(if (= array-index array-size) | |
nil | |
(do | |
(let [x-coord (array-index->x-coord array-index columns center-x dx) | |
y-coord (array-index->y-coord array-index rows columns center-y dy) | |
i (mandelbrot (complex. x-coord y-coord) dwell) | |
color (int (palette i))] | |
(aset ^"[I" raw-array array-index color)) | |
(recur (inc array-index))))))) | |
(defn new-center [point old-center] | |
(let [amount 0.28 | |
p0 (double (point 0)) | |
p1 (double (point 1)) | |
oc0 (double (old-center 0)) | |
oc1 (double (old-center 1)) | |
x (+ (* amount p0) (* (- 1 amount) oc0)) | |
y (+ (* amount p1) (* (- 1 amount) oc1))] | |
[x y])) | |
(defn zoom-in [point viewports output image columns rows canvas] | |
(let [center (new-center point ((first @viewports) :center)) | |
viewport-dx (double ((first @viewports) :dx)) | |
viewport-dy (double ((first @viewports) :dy))] | |
(swap! viewports conj {:center center :dx (/ viewport-dx 1.4) :dy (/ viewport-dy 1.4)})) | |
(time (calc-mandelbrot-for-array output 170)) | |
(.setRGB ^BufferedImage image 0 0 columns rows ^"[I" (output :array) 0 columns) | |
(.repaint ^JLabel canvas)) | |
(defn zoom-out [viewports output image columns rows canvas] | |
(if (= 1 (count @viewports)) | |
nil | |
(do | |
(swap! viewports pop) | |
(calc-mandelbrot-for-array output 170) | |
(.setRGB ^BufferedImage image 0 0 columns rows ^"[I" (output :array) 0 columns) | |
(.repaint ^JLabel canvas)))) | |
(defn -main | |
[& args] | |
(calc-mandelbrot-for-array output 170) | |
(def image (BufferedImage. columns rows BufferedImage/TYPE_INT_RGB)) | |
(def canvas (proxy [JLabel] [] | |
(paint [g] | |
(let [^JLabel this this] | |
(proxy-super paint ^SunGraphics2D g)) | |
(.drawImage ^SunGraphics2D g ^BufferedImage image 0 0 ^JLabel this)))) | |
(def graphics (.createGraphics ^BufferedImage image)) | |
(def frame (JFrame. "MandelCLJ")) | |
(.setDefaultCloseOperation ^JFrame frame JFrame/EXIT_ON_CLOSE) | |
(let [columns (long columns) | |
rows (long rows)] | |
(.setSize ^JFrame frame (Dimension. (+ (+ 8 8) columns) (+ (+ 8 30) rows)))) | |
(.setSize ^JLabel canvas columns rows) | |
(.add ^JFrame frame ^JLabel canvas) | |
(.show ^JFrame frame) | |
(.setRGB ^BufferedImage image 0 0 columns rows ^"[I" (output :array) 0 columns) | |
(.repaint ^JLabel canvas) | |
(.addMouseListener ^JLabel canvas (proxy [MouseAdapter] [] | |
(mouseReleased [e] | |
(if (= 1 (.getButton ^MouseEvent e)) | |
(let [columns (long columns)] (zoom-in (array-index->coord (+ (.getX ^MouseEvent e) (* (.getY ^MouseEvent e) columns)) rows columns (first @viewports)) | |
viewports output image columns rows canvas)) | |
(zoom-out viewports output image columns rows canvas)))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defproject mandelclj "0.1.3-SNAPSHOT" | |
:description "FIXME: write description" | |
:url "http://example.com/FIXME" | |
:license {:name "Eclipse Public License" | |
:url "http://www.eclipse.org/legal/epl-v10.html"} | |
:dependencies [[org.clojure/clojure "1.8.0-RC3"]] | |
:main ^:skip-aot myapp.core | |
:target-path "target/%s" | |
:profiles {:uberjar {:aot :all}}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment