Skip to content

Commit

Permalink
Rewriting triangle for blog post
Browse files Browse the repository at this point in the history
  • Loading branch information
mreid committed Apr 13, 2009
1 parent e074bef commit 91d786d
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 13 deletions.
1 change: 1 addition & 0 deletions .clojure
@@ -0,0 +1 @@
src
7 changes: 7 additions & 0 deletions runtests.sh
@@ -0,0 +1,7 @@
#!/bin/bash
JARS=$HOME/Library/Clojure/lib
CP=.:./src:$JARS/clojure.jar:$JARS/clojure-contrib.jar
TEST="src/mreid/minilight/test/all.clj"
MAIN="(mreid.minilight.test.all/-main)"

java -cp $CP clojure.main -i $TEST -e "$MAIN"
9 changes: 9 additions & 0 deletions src/mreid/minilight/test/all.clj
@@ -0,0 +1,9 @@
(ns mreid.minilight.test.all
(:gen-class)
(:use mreid.minilight.test.vec)
(:use mreid.minilight.test.triangle)
(:use clojure.contrib.test-is))

(defn -main []
(run-tests 'mreid.minilight.test.vec)
(run-tests 'mreid.minilight.test.triangle))
58 changes: 58 additions & 0 deletions src/mreid/minilight/test/triangle.clj
@@ -0,0 +1,58 @@
;; --- src/name/reid/mark/minilight/test/triangle.clj ---
;; Tests for triangle.clj using the test-is library.
(ns mreid.minilight.test.triangle
(:use mreid.minilight.triangle)
(:use clojure.contrib.test-is))

(def xytriangle
(struct triangle
[ [0 0 0] [1 0 0] [0 1 0] ] ; Triangle in xy-plane
[0.5 0.5 0.5] ; Reflectivity
[1 1 1] ; Emitivity
))

(def y2ztriangle
(struct triangle
[ [0 0 0] [0 2 0] [0 0 1] ] ; Triangle in xy-plane
[0.5 0.5 0.5] ; Reflectivity
[1 1 1] ; Emitivity
))

(deftest test-vertex
(is (= [0 0 0] (vertex xytriangle 0)))
(is (= [1 0 0] (vertex xytriangle 1)))
(is (= [0 1 0] (vertex xytriangle 2)))

(is (= [0 0 0] (vertex y2ztriangle 0)))
(is (= [0 2 0] (vertex y2ztriangle 1)))
(is (= [0 0 1] (vertex y2ztriangle 2))))

(deftest test-edge
(is (= [1 0 0] (edge xytriangle 0 1)))
(is (= [0 1 0] (edge xytriangle 0 2)))
(is (= [-1 1 0] (edge xytriangle 1 2)))
(is (= [1 -1 0] (edge xytriangle 2 1)))

(is (= [0 2 0] (edge y2ztriangle 0 1)))
(is (= [0 0 1] (edge y2ztriangle 0 2)))
(is (= [0 -2 1] (edge y2ztriangle 1 2)))
(is (= [0 2 -1] (edge y2ztriangle 2 1))))

(deftest test-tangent
(is (= [1 0 0] (tangent xytriangle)))
(is (= [0 1 0] (tangent y2ztriangle))))

(deftest test-normal
(is (= [0 0 1] (normal xytriangle)))
(is (= [2 0 0] (normal y2ztriangle))))

(deftest test-unit-normal
(is (= [0 0 1] (unit-normal xytriangle)))
(is (= [1 0 0] (unit-normal y2ztriangle))))

(deftest test-area
(is (= 0.5 (area xytriangle)))
(is (= 1 (area y2ztriangle))))

(deftest test-intersect)
(is (= 1 (intersect xytriangle [0 0 1] [0 0 -1])))
24 changes: 20 additions & 4 deletions test/vec.clj → src/mreid/minilight/test/vec.clj
@@ -1,7 +1,11 @@
;; --- test/vec.clj ---
;; --- src/name/reid/mark/minilight/test/vec.clj ---
;; Tests for vec.clj using the test-is library.
(ns test.vec
(:use vec clojure.contrib.test-is))
(ns mreid.minilight.test.vec
(:use mreid.minilight.vec)
(:use clojure.contrib.test-is))

(def dyn100 (sub [1 2 3] [0 2 3]))
(def dyn010 (sub [1 2 3] [1 1 3]))

(deftest test-approx0
(is (approx0 -0.000000001))
Expand All @@ -20,21 +24,33 @@
(is (= [-2 3 4] (add origin [-2 3 4])))
(is (= [1 2 3] (add [1 -1 2] [0 3 1]))))

(deftest test-dynamic-add
(is (= [1 1 0] (add dyn100 dyn010))))

(deftest test-sub
(is (= [1 2 3] (sub [1 2 3] origin)))
(is (= [0 0 0] (sub [1 2 3] [1 2 3])))
(is (= [-2 0 2] (sub [1 2 3] [3 2 1]))))


(deftest test-dynamic-sub
(is (= [1 -1 0] (sub dyn100 dyn010))))

(deftest test-scale
(is (= [0 0 0] (scale 0 [1 2 3])))
(is (= [-1 -2 -3] (scale -1 [1 2 3])))
(is (= [2 4 6] (scale 2 [1 2 3]))))

(deftest test-dynamic-scale
(is (= [2 0 0] (scale 2 dyn100))))

(deftest test-cross
(is (= [-3 6 -3] (cross [1 2 3] [4 5 6])))
(is (= [0 0 1] (cross [1 0 0] [0 1 0])))
(is (= [0 0 0] (cross [1 0 0] [1 0 0]))))

(deftest test-dynamic-cross
(is (= [0 0 1] (cross dyn100 dyn010))))

(deftest test-norm
(is (= 0 (norm origin )))
(is (= (Math/sqrt 3) (norm [1 1 1])))
Expand Down
110 changes: 110 additions & 0 deletions src/mreid/minilight/triangle.clj
@@ -0,0 +1,110 @@
;; ----------------------------------------------------------------------------
;; MiniLight in Clojure --- Mark Reid <http://mark.reid.name/>
;;
;; Based on the Ruby code and architecture by Harrison Ainsworth / HXA7241.
;; <http://www.hxa7241.org/>
;; ----------------------------------------------------------------------------

;; --- src/name/reid/mark/minilight/triangle.clj ---
;; A structure and functions for defining and querying triangles.
(ns mreid.minilight.triangle
(:use mreid.minilight.vec))

(defstruct triangle
:vertices ; Collection of 3 vectors
:reflect ; Vector with all values in [0,1)
:emit ; Vector with positive values
)

(defn vertex
"Returns (the zero-indexed) vertex i in the triangle t"
[t i] (nth (:vertices t) i))

(defn edge
"Returns the edge in the triangle t from vertex i to vertex j"
[t i j] (sub (vertex t j) (vertex t i)))

(defn tangent
"Returns a unit vector tangent to the given triangle t"
[t] (normalise (edge t 0 1)))

(defn normal
"Returns a vector normal to the given triangle t (edge01 x edge12)"
[t] (cross (edge t 0 1) (edge t 1 2)))

(defn unit-normal
"Returns a unit vector normal to the given triangle t"
[t] (normalise (normal t)))

(defn area
"Returns the are of the given triangle t"
[t] (/ (norm (normal t)) 2))

;(defn read-triangle [string] (map read-vec (re-seq #"\(.*?\)" string)))
;
;(defn create
; "Creates a new triangle from a string of 5 3-tuples.
; The first three are vertex vectors, the fourth the reflectivity vector
; and the last the emitivity vector."
;
; [string]
; (let [ [v0 v1 v2 reflect emit] (read-triangle string)
; edge0 (sub v1 v0)
; edge1 (sub v2 v1)
; edge3 (sub v2 v0)
; tangent (normalise edge0)
; normal (normalise (cross tangent edge1))
; pa2 (cross edge0 edge1)
; area (/ (norm pa2) 2) ]
;
; (struct triangle
; [v0 v1 v2] edge0 edge3
; (clamp 0 (- 1 Float/MIN_VALUE) reflect)
; (clamp 0 Float/MAX_VALUE emit)
; tangent normal area)))

; FIXME: This could be more efficient by only looping through vertices once.
(def TOLERANCE (/ 1.0 1024.0))
(defn tweak
"Returns a function that adds or subtracts a small amount"
[add-or-sub]
(fn [x] (add-or-sub x (* (+ (Math/abs x) 1.0) TOLERANCE))))

(defn bounding-box
"Computes the bounding box for a triangle t, returning the result as
a list of two vectors [lower-corner upper-corner]."
[t]
(let [vs (:vertices t)]
[ (map (tweak -) (apply map min vs))
(map (tweak +) (apply map max vs)) ]))

(defn intersect
"Finds the intersection with the triangle t of the ray starting at r0 in
direction rd. The returned value is a positive number a such that r0 + a.rd
is contained within t, or nil if there is no such a."
[t r0 rd]
(let [ e01 (edge t 0 1)
e20 (edge t 2 0)
invdet (invdet e01 rd e20) ]
(if (number? invdet)
(let [ v0 (vertex t 0)
tv (sub r0 v0)
u (* (dot v0 tv) invdet) ]
(if (and (>= u 0) (<= u 1))
(let [ q (cross tv e01)
v (* (dot rd q) invdet) ]
(if (and (>= v 0) (<= (+ u v) 1))
(let [a (* (dot e20 q) invdet)]
(if (>= a 0) a)))))))))

(def rnd (java.util.Random.))
(defn sample-point
"Returns a random point as a vector from inside the given triangle t"
[t]
(let [ sqr1 (Math/sqrt (.nextFloat rnd))
r2 (.nextFloat rnd)
a (- 1 sqr1)
b (* (- 1 r2) sqr1) ]
(add (vertex t 0)
(add (scale a (edge t 0 1))
(scale b (edge t 2 0))))))
8 changes: 4 additions & 4 deletions vec.clj → src/mreid/minilight/vec.clj
Expand Up @@ -8,7 +8,7 @@
;; --- vec.clj ---
;; A simple vector package that defines functions for working with geometrical
;; vectors.
(ns vec)
(ns mreid.minilight.vec)

; Constants
(def origin [0 0 0]) ; Zero vector in 3D
Expand Down Expand Up @@ -39,9 +39,9 @@
(defn cross
"Returns the cross product vector for the 3D vectors v1 and v2."
[v1 v2]
[ (- (* (v1 1) (v2 2)) (* (v1 2) (v2 1)))
(- (* (v1 2) (v2 0)) (* (v1 0) (v2 2)))
(- (* (v1 0) (v2 1)) (* (v1 1) (v2 0))) ])
[ (- (* (nth v1 1) (nth v2 2)) (* (nth v1 2) (nth v2 1)))
(- (* (nth v1 2) (nth v2 0)) (* (nth v1 0) (nth v2 2)))
(- (* (nth v1 0) (nth v2 1)) (* (nth v1 1) (nth v2 0))) ])

; Scalar operators
(defn scale
Expand Down
5 changes: 0 additions & 5 deletions test/test.clj

This file was deleted.

0 comments on commit 91d786d

Please sign in to comment.