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 (IllegalArgumentException. "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 (defn canonicalise-vertex
044 "If `o` is a map with numeric values for `:x`, `:y` and optionally `:z`,
045 upgrade it to something we will recognise as a vertex."
046 [o]
047 (if
048 (and
049 (map? o)
050 (number? (:x o))
051 (number? (:y o))
052 (or (nil? (:z o)) (number? (:z o))))
053 (assoc o :kind :vertex :id (vertex-key o))
054 (throw (IllegalArgumentException. "Not a vertex."))))
055
056 (def ensure3d
057 "Given a vertex `o`, if `o` has a `:z` value, just return `o`; otherwise
058 return a vertex like `o` but having thie `dflt` value as the value of its
059 `:z` key, or zero as the value of its `:z` key if `dflt` is not specified.
060
061 If `o` is not a vertex, throws an exception."
062 (memoize
063 (fn
064 ([o]
065 (ensure3d o 0.0))
066 ([o dflt]
067 (cond
068 (not (vertex? o)) (throw (IllegalArgumentException. "Not a vertex!"))
069 (:z o) o
070 :else (assoc o :z dflt))))))
071
072 (def ensure2d
073 "If `o` is a vertex, set its `:z` value to zero; else throw an exception."
074 (memoize
075 (fn [o]
076 (if
077 (vertex? o)
078 (assoc o :z 0.0)
079 (throw (IllegalArgumentException. "Not a vertex!"))))))