A hue-to-rgb.lisp => hue-to-rgb.lisp +33 -0
@@ 0,0 1,33 @@
+(in-package :dev.aarontag.hue-to-rgb)
+
+;;; Makes a linear function out of two lines
+(defun two-points (x1 y1 x2 y2)
+ (lambda (x)
+ (let* ((m (/ (- y1 y2) (- x1 x2)))
+ (b (- y1 (* m x1))))
+ (+ (* m x) b))))
+
+;;; Take number between 0 and 1
+(defun hue-curve (x-real &key (width 1) (offset 0))
+ (let ((dn-sixth (two-points 1/6 1 2/6 0))
+ (up-sixth (two-points 4/6 0 5/6 1))
+ (x (mod (-(/ (float x-real) width) offset) 1)))
+ ;; just the decimal point...
+ (cond
+ ((< x 1/6) 1)
+ ((< x 2/6) (funcall dn-sixth x))
+ ((< x 4/6) 0)
+ ((< x 5/6) (funcall up-sixth x))
+ ((< x 6/6) 1)
+ (t 1))))
+
+(defun hue-to-rgb (x)
+ (if (= x 0) (return-from hue-to-rgb '(0 0 0)))
+ (mapcar (lambda (offset) (floor (* (hue-curve x :offset offset) 255)))
+ '(0 1/3 2/3)))
+
+;; (defun hue-plot ()
+;; (ppm-plot (lambda (x y) (hue-to-rgb x))
+;; (lambda (x) (apply #'format nil "~d ~d ~d " x))
+;; (range 1 :steps 256)
+;; (range 300)))
M make-plot.lisp => make-plot.lisp +56 -4
@@ 1,7 1,59 @@
-(in-package "COMMON-LISP-USER")
-
(require 'asdf)
-
(load "mandelbrot-plot.asd")
(asdf:load-system :mandelbrot-plot)
-(dev.aarontag.mandelbrot-plot:mandelbrot-plot)>
\ No newline at end of file
+
+(defpackage :dev.aarontag.make-plot
+ (:use :common-lisp
+ :dev.aarontag.simple-plot
+ :dev.aarontag.mandelbrot
+ :dev.aarontag.hue-to-rgb))
+
+(in-package :dev.aarontag.make-plot)
+
+(with-open-file (file "mandelbrot.ppm"
+ :direction :output
+ :if-exists :rename
+ :if-does-not-exist :create)
+
+ (ppm-plot (lambda (x y) (mandelbrot (complex x y)))
+ (lambda (x) (apply #'format nil "~d ~d ~d " (hue-to-rgb (/ x 255))))
+ (range 0.50 :start -2.00 :steps 5000)
+ (range 1.25 :start -1.25 :steps 5000)
+ :file file))
+
+;; Should look something like this:
+;; *
+;; * * * *
+;; * * * *
+;; * * * *
+;; * *
+;; * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * * * * * * * *
+;; * * * * * * * * * * *
+
+;; * * * *
+;; * * * *
+;; * * * *
+;; *
M mandelbrot-plot.asd => mandelbrot-plot.asd +2 -1
@@ 7,4 7,5 @@
:serial t
:components ((:file "packages")
(:file "plot")
- (:file "mandelbrot")))>
\ No newline at end of file
+ (:file "mandelbrot")
+ (:file "hue-to-rgb")))<
\ No newline at end of file
M mandelbrot.lisp => mandelbrot.lisp +21 -21
@@ 1,29 1,29 @@
-(in-package :dev.aarontag.mandelbrot-plot)
+(in-package :dev.aarontag.mandelbrot)
+
+(defvar *max-iter* 255)
(defun mag (c)
(let ((r (realpart c)) (i (imagpart c)))
- (sqrt (+ (* r r)
- (* i i)))))
+ (+ (* r r)
+ (* i i))))
-;;; Where it's all at
-(defun mandel (z c)
- (+ (* z z) c))
+;;; Takes z and n and makes a smooth interpolation between the different
+;;; iteration bands. tbh I don't quite understand it, but it's very pretty
+(defun interpolate (z n)
+ (let* ((x (realpart z))
+ (y (imagpart z))
+ (log-zn (/ (log (+ (* x x) (* y y))) 2))
+ (log2 (log 2))
+ (nu (/ (log (/ log-zn log2)) log2)))
+ (+ n (- 1 nu))))
;;; Ended up being a lot simpler than expected tbh
(defun mandelbrot (c)
(let ((z (complex 0 0)))
- (dotimes (i 1000) ; TODO: make tunable?
- (setf z (mandel z c))
- (if (>= (mag z) 2)
- (return-from mandelbrot nil))))
- t)
-
-(defun mandelbrot-xy (x y)
- (mandelbrot (complex x y)))
-
-
-;;; TODO: maybe find interesting edges
-(defun mandelbrot-plot ()
- (plot #'mandelbrot-xy
- (range 0.5 :start -2.0 :inc 0.05)
- (range 1.1 :start -1.1 :inc 0.05)))
+ (dotimes (i *max-iter*)
+ ;; A lotta magic in this line; are you watching closely?
+ (setf z (+ (* z z) c))
+ (if (>= (mag z) 512)
+ (return-from mandelbrot (interpolate z i)))))
+
+ 0)<
\ No newline at end of file
D mandelbrot.out => mandelbrot.out +0 -44
@@ 1,44 0,0 @@
-
-
-
-
-
- *
- * * * *
- * * * *
- * * * *
- * *
- * * * * * * * * * * *
- * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * *
- * * * * * * * * * * * * * * * * *
- * * * * * * * * * * *
-
- * * * *
- * * * *
- * * * *
- *
-
-
-
-
M packages.lisp => packages.lisp +8 -5
@@ 2,9 2,12 @@
(defpackage :dev.aarontag.simple-plot
(:use :common-lisp)
- (:export :range :plot))
+ (:export :range :ppm-plot))
-(defpackage :dev.aarontag.mandelbrot-plot
- (:use :dev.aarontag.simple-plot
- :common-lisp)
- (:export :mandelbrot-plot))
+(defpackage :dev.aarontag.mandelbrot
+ (:use :common-lisp)
+ (:export :mandelbrot))
+
+(defpackage :dev.aarontag.hue-to-rgb
+ (:use :common-lisp)
+ (:export :hue-to-rgb)) <
\ No newline at end of file
M plot.lisp => plot.lisp +19 -13
@@ 4,23 4,29 @@
;;; utility to make a range of numbers
;;; this could probably be done with a loop but meh
-(defun range (end &key (start 0) (inc 1))
- (if (< start end)
- (cons start (range end
- :start (+ start inc)
- :inc inc))))
-
-;;; the deadist of simplist
-(defun vis-print (b)
- (if b "*" " "))
+(defun range (end &key (start 0) (steps nil) (inc 1))
+ (let ((inc (if steps
+ (/ (- end start) steps)
+ inc)))
+ (if (< start end)
+ (cons start (range end
+ :start (+ start inc)
+ :inc inc)))))
;;; Simple iterative design
;;; Decided to leave ranges out, makes things cleaner
-(defun plot (selector-fn x-list y-list)
+(defun plot (fn num-to-print x-list y-list &key (file t))
(dolist (y y-list)
(dolist (x x-list)
;; On my terminal, characters are ~twice as tall, so this ends up looking
;; square
- (format t "~a "
- (vis-print (funcall selector-fn x y))))
- (format t "~%")))
+ (format file "~a"
+ (funcall num-to-print (funcall fn x y))))
+ (format file "~%")))
+
+(defun ppm-plot (fn num-to-print x-list y-list &key (file t))
+ (format file "P3 ~d ~d ~d ~%"
+ (length x-list)
+ (length y-list)
+ 255)
+ (plot fn num-to-print x-list y-list :file file))