001 (ns walkmap.edge
002 "Essentially the specification for things we shall consider to be an edge.
003 An edge is a line segment having just a start and an end, with no intervening
004 nodes."
005 (:require [clojure.math.numeric-tower :as m]
006 [walkmap.polygon :refer [polygon?]]
007 [walkmap.vertex :refer [ensure3d vertex?]]))
008
009 (defn edge
010 "Return an edge between vertices `v1` and `v2`."
011 [v1 v2]
012 (if
013 (and (vertex? v1) (vertex? v2))
014 {:kind :edge :id (keyword (gensym "edge")) :start v1 :end v2}
015 (throw (IllegalArgumentException. "Must be vertices."))))
016
017 (defn edge?
018 "True if `o` satisfies the conditions for a edge. An edge shall be a map
019 having the keys `:start` and `:end`, such that the values of each of those
020 keys shall be a vertex."
021 [o]
022 (and
023 (map? o)
024 (vertex? (:start o))
025 (vertex? (:end o))))
026
027 (defn length
028 "Return the length of the edge `e`."
029 [e]
030 (let [start (ensure3d (:start e))
031 end (ensure3d (:end e))]
032 (m/sqrt
033 (reduce
034 +
035 (map
036 #(m/expt (- (% end) (% start)) 2)
037 [:x :y :z])))))
038
039 (defn unit-vector
040 "Return an vertex parallel to `e` starting from the coordinate origin. Two
041 edges which are parallel will have the same unit vector."
042 [e]
043 (let [e' {:start (ensure3d (:start e)) :end (ensure3d (:end e))}
044 l (length e')]
045 (reduce
046 merge
047 {}
048 (map
049 (fn [k]
050 {k (/ (- (k (:end e')) (k (:start e'))) l)})
051 [:x :y :z]))))
052
053 (defn parallel?
054 "True if all `edges` passed are parallel with one another."
055 ;; TODO: this bears being wary about, dealing with floating point arithmetic.
056 ;; Keep an eye out for spurious errors.
057 [& edges]
058 (let [uvs (map unit-vector edges)]
059 (every?
060 #(= % (first uvs))
061 (rest uvs))))
062
063 (defn collinear?
064 "True if edges `e1` and `e2` are collinear with one another."
065 [e1 e2]
066 (parallel?
067 e1
068 e2
069 {:start (:start e1) :end (:start e2)}))
070