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