Skip to content

Instantly share code, notes, and snippets.

@quoll
Created May 22, 2012 14:36
Show Gist options
  • Save quoll/2769463 to your computer and use it in GitHub Desktop.
Save quoll/2769463 to your computer and use it in GitHub Desktop.
Simple complex number code
(ns test.complex
"A simple complex number library")
(defprotocol ComplexOp
(abs [this] "The absolute value of the number")
(abs2 [this] "The absolute value squared of the number")
(plus [this ^Complex that] "Adds another number")
(times [this ^Complex that] "Multiplies by another number")
(minus [this ^Complex that] "Subtracts another number")
(divide [this ^Complex that] "Divides by another number")
(plus-dbl [this ^double that] "Adds a real number")
(times-dbl [this ^double that] "Multiplies by a real number")
(minus-dbl [this ^double that] "Subtracts a real number")
(divide-dbl [this ^double that] "Divides by a real number"))
(defrecord Complex [re im]
ComplexOp
(abs [this] (Math/sqrt (+ (* re re) (* im im))))
(abs2 [this] (+ (* re re) (* im im)))
(plus [this {tr :re, ti :im}] (Complex. (+ re tr) (+ im ti)))
(times [this {tr :re, ti :im}] (Complex. (- (* re tr) (* im ti)) (+ (* re ti) (* im tr))))
(minus [this {tr :re, ti :im}] (Complex. (- re tr) (- im ti)))
(divide [this {tr :re, ti :im}]
(let [denom (+ (* tr tr) (* ti ti))]
(Complex. (/ (+ (* re tr) (* im ti)) denom) (/ (- (* im tr) (* re ti)) denom))))
(plus-dbl [this that] (Complex. (+ re that) im))
(times-dbl [this that] (Complex. (* re that) (* im that)))
(minus-dbl [this that] (Complex. (- re that) im))
(divide-dbl [this that]
(Complex. (/ re that) (/ im that))))
(ns test.mand
"Mandelbrot generator. Test 2.
This version does not use any Java."
(:gen-class)
(:use [test.complex :only (abs2 times plus)])
(:import [test.complex Complex]
[java.awt Graphics Color Dimension]
[java.awt.event KeyListener KeyEvent]
[java.awt.image BufferedImage]
[javax.swing JPanel JFrame SwingUtilities]))
(def min-x -2.0)
(def max-x 1.0)
(def min-y -1.0)
(def max-y 1.0)
(def limit 1000)
(def window-name "Mandelbrot")
(def default-width 300)
(def default-height 200)
(defn ^long scaled-color [^long count] (long (* (Math/log (inc count)) 37)))
(defn mandelbrotColor [c]
(loop [z (Complex. 0 0) count 0]
(if (>= count limit)
Color/BLUE
(let [z (plus (times z z) c)]
(if (>= (abs2 z) 4)
(Color. (scaled-color count) 0 0)
(recur z (inc count)))))))
(defn plot [^Graphics g [x y c]]
(.setColor g c)
(.fillRect g x y 1 1)
g)
(defn render [^Graphics g ^long width ^long height]
(let [math-width (- max-x min-x)
math-height (- max-y min-y)
t (System/currentTimeMillis)]
(letfn [(coord-2-math [^long x ^long y]
(Complex. (+ (/ (* math-width x) width) min-x)
(- max-y (/ (* y math-height) height))))]
(reduce plot g
(map (fn [[a b]] [a b (mandelbrotColor (coord-2-math a b))]) (for [x (range width) y (range height)] [x y]))))
(println "Render: " (- (System/currentTimeMillis) t) "ms")))
(defn get-image- [^long width ^long height]
(let [image (BufferedImage. width height BufferedImage/TYPE_INT_RGB)]
(render (.createGraphics image) width height)
image))
(def get-image (memoize get-image-))
(defn new-drawer []
(proxy [JPanel] []
(paint [^Graphics graphics-context]
(let [width (proxy-super getWidth)
height (proxy-super getHeight)]
(.drawImage graphics-context (get-image width height) 0 0 nil)))))
(defn show-window []
(let [^JPanel drawing-obj (new-drawer)
frame (JFrame. window-name)
closer (proxy [KeyListener] []
(keyPressed [^KeyEvent e] (when (= (.getKeyChar e) \q) (.dispose frame)))
(keyReleased [e])
(keyTyped [e]))]
(.setPreferredSize drawing-obj (Dimension. default-width default-height))
(.add (.getContentPane frame) drawing-obj)
(doto frame
(.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
(.pack)
(.setBackground Color/WHITE)
(.addKeyListener closer)
(.setVisible true))))
(defn start-window []
(SwingUtilities/invokeLater #(show-window)))
(defn -main [& args] (start-window))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment