getting back into clojure, and i wrote this little thing to check if two boxes are colliding by checking if vertices of one are inside the other:
(defn around
[val radius]
(let [half (/ radius 2)
low (- val half)
high (+ val half)]
[low high]))
(defn colliding?
[this that]
(let [[this-x1 this-x2] (around (:x this) (:w this))
[this-y1 this-y2] (around (:y this) (:h this))
[this-z1 this-z2] (around (:z this) (:l this))
[that-x1 that-x2] (around (:x that) (:w that))
[that-y1 that-y2] (around (:y that) (:h that))
[that-z1 that-z2] (around (:z that) (:l that))]
(or (and (or (<= that-x1 this-x1 that-x2)
(<= that-x1 this-x2 that-x2))
(or (<= that-y1 this-y1 that-y2)
(<= that-y1 this-y2 that-y2))
(or (<= that-z1 this-z1 that-z2)
(<= that-z1 this-z2 that-z2)))
(and (or (<= this-x1 that-x1 this-x2)
(<= this-x1 that-x2 this-x2))
(or (<= this-y1 that-y1 this-y2)
(<= this-y1 that-y2 this-y2))
(or (<= this-z1 that-z1 this-z2)
(<= this-z1 that-z2 this-z2))))))
this smells pretty bad due to repetition but i'm not sure what the best approach is for cleaning this up. is there a better way to do this?
You can simplify the code by using the fact that there is a collision in one direction unless the starting coordinate of one object is higher than the ending coordinate of the other. I.e. a sufficient test is
(not (or (> this-x1 that-x2)
(> that-x1 this-x2)))
which is equivalent to
(and (<= this-x1 that-x2)
(<= that-x1 this-x2))
Using this, your colliding?
may be simplified to
(defn colliding?
[this that]
(let [[this-x1 this-x2] (around (:x this) (:w this))
[this-y1 this-y2] (around (:y this) (:h this))
[this-z1 this-z2] (around (:z this) (:l this))
[that-x1 that-x2] (around (:x that) (:w that))
[that-y1 that-y2] (around (:y that) (:h that))
[that-z1 that-z2] (around (:z that) (:l that))]
(and (<= this-x1 that-x2)
(<= that-x1 this-x2)
(<= this-y1 that-y2)
(<= that-y1 this-y2)
(<= this-z1 that-z2)
(<= that-z1 this-z2))))
If you then factor out a function conflicting?
that checks for overlapping in one dimension,
(defn conflicting?
[this that coordinate size]
(let [[this-c1 this-c2] (around (coordinate this) (size this))
[that-c1 that-c2] (around (coordinate that) (size that))]
(and (<= this-c1 that-c2)
(<= that-c1 this-c2)))
colliding?
can be further simplified by utilizing mapping over dimensions and sizes:
(defn colliding?
[this that]
(every? true? (map #(conflicting? this that %1 %2)
[:x :y :z]
[:w :h :l])))
Edit:
Furthermore, conflicting?
may be simplified to
(defn conflicting?
[this that coordinate size]
(<= (math/abs (- (coordinate this) (coordinate that)))
(/ (+ (size this) (size that)) 2)))
making the function around
obsolete for the purpose of detecting collisions.