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.path :refer [path? polygon->path]]
007              [walkmap.polygon :refer [polygon?]]
008              [walkmap.vertex :refer [ensure3d vertex?]]))
009  
010  (defn edge?
011    "True if `o` satisfies the conditions for a path. A path shall be a map
012    having the keys `:start` and `:end`, such that the values of each of those
013    keys shall be a vertex."
014    [o]
015    (and
016      (map? o)
017      (vertex? (:start o))
018      (vertex? (:end o))))
019  
020  (defn path->edges
021    "if `o` is a path, a polygon, or a sequence of vertices, return a sequence of
022    edges representing that path, polygon or sequence."
023    [o]
024    (cond
025      (seq? o)
026      (when
027        (and
028          (vertex? (first o))
029          (vertex? (first (rest o))))
030        (cons
031          {:start (first o)
032           :end (first (rest o))}
033          (path->edges (rest o))))
034      (path? o)
035      (path->edges (:nodes o))
036      (polygon? o)
037      (path->edges (polygon->path o))))
038  
039  (defn length
040    "Return the length of the edge `e`."
041    [e]
042    (let [start (ensure3d (:start e))
043          end (ensure3d (:end e))]
044      (m/sqrt
045        (reduce
046          +
047          (map
048            #(m/expt (- (% end) (% start)) 2)
049            [:x :y :z])))))
050  
051  (defn unit-vector
052    "Return an vertex parallel to `e` starting from the coordinate origin. Two
053    edges which are parallel will have the same unit vector."
054    [e]
055    (let [e' {:start (ensure3d (:start e)) :end (ensure3d (:end e))}
056          l (length e')]
057      (reduce
058        merge
059        {}
060        (map
061          (fn [k]
062            {k (/ (- (k (:end e')) (k (:start e'))) l)})
063          [:x :y :z]))))
064  
065  (defn parallel?
066    "True if all `edges` passed are parallel with one another."
067    ;; TODO: this bears being wary about, dealing with floating point arithmetic.
068    ;; Keep an eye out for spurious errors.
069    [& edges]
070    (let [uvs (map unit-vector edges)]
071      (every?
072        #(= % (first uvs))
073        (rest uvs))))
074  
075  (defn collinear?
076    "True if edges `e1` and `e2` are collinear with one another."
077    [e1 e2]
078    (parallel?
079      e1
080      e2
081      {:start (:start e1) :end (:start e2)}))
082