001  (ns walkmap.vertex
002    "Essentially the specification for things we shall consider to be vertices.")
003  
004  (defn vertex-key
005    "Making sure we get the same key everytime we key a vertex with the same
006    coordinates. `o` must have numeric values for `:x`, `:y`, and optionally
007    `:z`."
008    [o]
009    (cond
010      (and (:x o) (:y o) (:z o)) (keyword (str "vert{" (:x o) "|" (:y o) "|" (:z o) "}"))
011      (and (:x o) (:y o)) (keyword (str "vert{" (:x o) "|" (:y o) "}"))
012      :else (throw (Exception. "Not a vertex."))))
013  
014  (defn vertex?
015    "True if `o` satisfies the conditions for a vertex. That is, essentially,
016    that it must rerpresent a two- or three- dimensional vector. A vertex is
017    shall be a map having at least the keys `:x` and `:y`, where the value of
018    those keys is a number. If the key `:z` is also present, its value must also
019    be a number.
020  
021    The name  `vector?` was not used as that would clash with a function of that
022    name in `clojure.core` whose semantics are entirely different."
023    [o]
024    (and
025      (map? o)
026      (:id o)
027      (number? (:x o))
028      (number? (:y o))
029      (or (nil? (:z o)) (number? (:z o)))
030      (or (nil? (:kind o)) (= (:kind o) :vertex))))
031  
032  (defn make-vertex
033    "Make a vertex with this `x`, `y` and (if provided) `z` values. Returns a map
034    with those values, plus a unique `:id` value, and `:kind` set to `:vertex`.
035    It's not necessary to use this function to create a vertex, but the `:id`
036    must be present and must be unique."
037    ([x y]
038     (let [v {:x x :y y :kind :vertex}]
039       (assoc v :id (vertex-key v))))
040    ([x y z]
041     (assoc (make-vertex x y) :z z)))
042  
043  (def ensure3d
044    "Given a vertex `o`, if `o` has a `:z` value, just return `o`; otherwise
045    return a vertex like `o` but having thie `dflt` value as the value of its
046    `:z` key, or zero as the value of its `:z` key if `dflt` is not specified.
047  
048    If `o` is not a vertex, throws an exception."
049    (memoize
050      (fn
051        ([o]
052         (ensure3d o 0.0))
053        ([o dflt]
054         (cond
055           (not (vertex? o)) (throw (Exception. "Not a vertex!"))
056           (:z o) o
057           :else (assoc o :z dflt))))))
058  
059  (def ensure2d
060    "If `o` is a vertex, set its `:z` value to zero; else throw an exception."
061    (memoize
062      (fn [o]
063        (if
064          (vertex? o)
065          (assoc o :z 0.0)
066          (throw (Exception. "Not a vertex!"))))))