diff --git a/docs/cloverage/index.html b/docs/cloverage/index.html index fcfdf92..e26e161 100644 --- a/docs/cloverage/index.html +++ b/docs/cloverage/index.html @@ -27,20 +27,14 @@ walkmap.edge
136
60
-69.39 % + style="width:100.0%; + float:left;"> 164 +100.00 %
35
1
14
-72.00 % -82750 + style="width:100.0%; + float:left;"> 40 +100.00 % +70740 walkmap.geometry
walkmap.path
4
91
-4.21 % + style="width:3.5294117647058822%; + float:left;"> 6
164
+3.53 %
4
15
-21.05 % -38519 + style="width:15.789473684210526%; + float:left;"> 6
32
+15.79 % +76738 walkmap.polygon
walkmap.stl
203
168
-54.72 % + style="width:52.02156334231806%; + float:left;"> 193
178
+52.02 %
30
28
9
37
-51.32 % + style="width:51.31578947368421%; + float:left;"> 39 +48.68 % 1481376 walkmap.superstructure
119
47
-71.69 % -
20
4
5
-82.76 % -76829 + style="width:97.40259740259741%; + float:left;"> 150 +2.60 % +
4
23
+14.81 % +74827 walkmap.svg
108766 - walkmap.utils
24
14
-63.16 % + walkmap.tag
137
+100.00 %
6
2
2
-80.00 % + style="width:100.0%; + float:left;"> 36
+100.00 % +65736 + + + walkmap.utils
3
35
+7.89 % +
3
7
+30.00 % 26210 walkmap.vertex
213
39
-84.52 % + style="width:84.92063492063492%; + float:left;"> 214
38
+84.92 %
27
8
28
7
7
83.33 % -79842 +82942 Totals: -47.23 % +44.01 % -52.63 % +50.55 % diff --git a/docs/cloverage/walkmap/edge.clj.html b/docs/cloverage/walkmap/edge.clj.html index 280afe2..0d75b13 100644 --- a/docs/cloverage/walkmap/edge.clj.html +++ b/docs/cloverage/walkmap/edge.clj.html @@ -20,235 +20,199 @@ 005    (:require [clojure.math.numeric-tower :as m]
- 006              [walkmap.path :refer [path? polygon->path]] + 006              [walkmap.polygon :refer [polygon?]]
- 007              [walkmap.polygon :refer [polygon?]] -
- - 008              [walkmap.vertex :refer [ensure3d vertex?]])) + 007              [walkmap.vertex :refer [ensure3d vertex?]]))
- 009   + 008  
- 010  (defn edge? + 009  (defn edge
- 011    "True if `o` satisfies the conditions for a path. A path shall be a map + 010    "Return an edge between vertices `v1` and `v2`."
- 012    having the keys `:start` and `:end`, such that the values of each of those + 011    [v1 v2]
- - 013    keys shall be a vertex." + + 012    (if
- - 014    [o] + + 013      (and (vertex? v1) (vertex? v2))
- - 015    (and + + 014      {:kind :edge :id (keyword (gensym "edge")) :start v1 :end v2}
- 016      (map? o) -
- - 017      (vertex? (:start o)) -
- - 018      (vertex? (:end o)))) + 015      (throw (IllegalArgumentException. "Must be vertices."))))
- 019   + 016  
- 020  (defn path->edges + 017  (defn edge?
- 021    "if `o` is a path, a polygon, or a sequence of vertices, return a sequence of + 018    "True if `o` satisfies the conditions for a edge. An edge shall be a map
- 022    edges representing that path, polygon or sequence." + 019    having the keys `:start` and `:end`, such that the values of each of those
- 023    [o] + 020    keys shall be a vertex."
- - 024    (cond + + 021    [o]
- - 025      (seq? o) + + 022    (and
- - 026      (when + + 023      (map? o)
- - 027        (and + + 024      (vertex? (:start o))
- - 028          (vertex? (first o)) + + 025      (vertex? (:end o))))
- - 029          (vertex? (first (rest o)))) + + 026  
- - 030        (cons + + 027  (defn length
- - 031          {:start (first o) + + 028    "Return the length of the edge `e`."
- - 032           :end (first (rest o))} + + 029    [e]
- - 033          (path->edges (rest o)))) + + 030    (let [start (ensure3d (:start e))
- - 034      (path? o) + + 031          end (ensure3d (:end e))]
- - 035      (path->edges (:nodes o)) + + 032      (m/sqrt
- - 036      (polygon? o) + + 033        (reduce
- - 037      (path->edges (polygon->path o)))) + + 034          + +
+ + 035          (map +
+ + 036            #(m/expt (- (% end) (% start)) 2) +
+ + 037            [:x :y :z])))))
038  
- 039  (defn length + 039  (defn unit-vector
- 040    "Return the length of the edge `e`." + 040    "Return an vertex parallel to `e` starting from the coordinate origin. Two
- 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 + 041    edges which are parallel will have the same 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] + 042    [e]
- 055    (let [e' {:start (ensure3d (:start e)) :end (ensure3d (:end e))} + 043    (let [e' {:start (ensure3d (:start e)) :end (ensure3d (:end e))}
- 056          l (length e')] + 044          l (length e')]
- 057      (reduce + 045      (reduce
- 058        merge + 046        merge
- 059        {} + 047        {}
- 060        (map + 048        (map
- 061          (fn [k] + 049          (fn [k]
- 062            {k (/ (- (k (:end e')) (k (:start e'))) l)}) + 050            {k (/ (- (k (:end e')) (k (:start e'))) l)})
- 063          [:x :y :z])))) + 051          [:x :y :z]))))
- 064   + 052  
- 065  (defn parallel? + 053  (defn parallel?
- 066    "True if all `edges` passed are parallel with one another." + 054    "True if all `edges` passed are parallel with one another."
- 067    ;; TODO: this bears being wary about, dealing with floating point arithmetic. + 055    ;; TODO: this bears being wary about, dealing with floating point arithmetic.
- 068    ;; Keep an eye out for spurious errors. + 056    ;; Keep an eye out for spurious errors.
- 069    [& edges] + 057    [& edges]
- 070    (let [uvs (map unit-vector edges)] + 058    (let [uvs (map unit-vector edges)]
- 071      (every? + 059      (every?
- 072        #(= % (first uvs)) + 060        #(= % (first uvs))
- 073        (rest uvs)))) + 061        (rest uvs))))
- 074   + 062  
- 075  (defn collinear? + 063  (defn collinear?
- 076    "True if edges `e1` and `e2` are collinear with one another." + 064    "True if edges `e1` and `e2` are collinear with one another."
- 077    [e1 e2] + 065    [e1 e2]
- 078    (parallel? + 066    (parallel?
- 079      e1 + 067      e1
- 080      e2 + 068      e2
- 081      {:start (:start e1) :end (:start e2)})) + 069      {:start (:start e1) :end (:start e2)}))
- 082   + 070  
diff --git a/docs/cloverage/walkmap/path.clj.html b/docs/cloverage/walkmap/path.clj.html index 7e8c4d2..247af41 100644 --- a/docs/cloverage/walkmap/path.clj.html +++ b/docs/cloverage/walkmap/path.clj.html @@ -8,115 +8,229 @@ 001  (ns walkmap.path

- 002    "Essentially the specification for things we shall consider to be path." + 002    "Essentially the specification for things we shall consider to be path.
- 003    (:require [walkmap.polygon :refer [polygon?]] + 003    **Note that** for these purposes `path` means any continuous linear
- 004              [walkmap.vertex :refer [vertex?]])) + 004    feature, where such features specifically include watercourses." +
+ + 005    (:require [walkmap.edge :as e] +
+ + 006              [walkmap.polygon :refer [polygon?]] +
+ + 007              [walkmap.vertex :refer [vertex?]]))
- 005   + 008  
- 006  (defn path? + 009  (defn path?
- 007    "True if `o` satisfies the conditions for a path. A path shall be a map + 010    "True if `o` satisfies the conditions for a path. A path shall be a map
- 008    having the key `:nodes`, whose value shall be a sequence of vertices as + 011    having the key `:nodes`, whose value shall be a sequence of vertices as
- 009    defined in `walkmap.vertex`." + 012    defined in `walkmap.vertex`."
- 010    [o] + 013    [o]
- 011    (let + 014    (let
- 012      [v (:nodes o)] + 015      [v (:nodes o)]
- - 013      (and + + 016      (and
- 014        (seq? v) + 017        (seq? v)
- 015        (> (count v) 2) + 018        (> (count v) 2)
- 016        (every? vertex? v) + 019        (every? vertex? v) +
+ + 020        (:id o)
- 017        (or (nil? (:kind o)) (= (:kind o) :path))))) + 021        (or (nil? (:kind o)) (= (:kind o) :path)))))
- 018   + 022  
- 019  (defn make-path + 023  (defn path
- 020    [nodes] + 024    "Return a path constructed from these `vertices`." +
+ + 025    [& vertices]
- 021    (if + 026    (if
- 022      (every? vertex? nodes) + 027      (every? vertex? vertices)
- 023      {:nodes nodes :id (keyword (gensym "path")) :kind :path} + 028      {:nodes vertices :id (keyword (gensym "path")) :kind :path}
- 024      (throw (Exception. "Each item on path must be a vertex.")))) + 029      (throw (IllegalArgumentException. "Each item on path must be a vertex."))))
- 025   + 030  
- 026  (defn polygon->path + 031  (defn polygon->path
- 027    "If `o` is a polygon, return an equivalent path. What's different about + 032    "If `o` is a polygon, return an equivalent path. What's different about
- 028    a path is that in polygons there is an implicit edge between the first + 033    a path is that in polygons there is an implicit edge between the first
- 029    vertex and the last. In paths, there isn't, so we need to add that + 034    vertex and the last. In paths, there isn't, so we need to add that
- 030    edge explicitly. + 035    edge explicitly.
- 031   + 036  
- 032    If `o` is not a polygon, will throw an exception." + 037    If `o` is not a polygon, will throw an exception."
- 033    [o] + 038    [o]
- 034    (if + 039    (if
- 035      (polygon? o) + 040      (polygon? o)
- 036      (assoc (dissoc o :vertices) :kind :path :nodes (concat (:vertices o) (list (first (:vertices o))))) + 041      (assoc (dissoc o :vertices) :kind :path :nodes (concat (:vertices o) (list (first (:vertices o)))))
- 037      (throw (Exception. "Not a polygon!")))) + 042      (throw (IllegalArgumentException. "Not a polygon!"))))
- 038   + 043   +
+ + 044  (defn path->edges +
+ + 045    "if `o` is a path, a polygon, or a sequence of vertices, return a sequence of +
+ + 046    edges representing that path, polygon or sequence. +
+ + 047   +
+ + 048    Throws `IllegalArgumentException` if `o` is not a path, a polygon, or +
+ + 049    sequence of vertices." +
+ + 050    [o] +
+ + 051    (cond +
+ + 052      (seq? o) +
+ + 053      (when +
+ + 054        (and +
+ + 055          (vertex? (first o)) +
+ + 056          (vertex? (first (rest o)))) +
+ + 057        (cons +
+ + 058          (e/edge (first o) (rest o)) +
+ + 059          (path->edges (rest o)))) +
+ + 060      (path? o) +
+ + 061      (path->edges (:nodes o)) +
+ + 062      :else +
+ + 063      (throw (IllegalArgumentException. +
+ + 064               "Not a path or sequence of vertices!")))) +
+ + 065   +
+ + 066  (defn length +
+ + 067    "Return the length of this path, in metres. **Note that** +
+ + 068    1. This is not the same as the distance from the start to the end of the +
+ + 069    path, which, except for absolutely straight paths, will be shorter; +
+ + 070    2. It is not even quite the same as the length of the path *as rendered*, +
+ + 071    since paths will generally be rendered as spline curves." +
+ + 072    [path] +
+ + 073    (if +
+ + 074      (path? path) +
+ + 075      (reduce + (map e/length (path->edges path))) +
+ + 076      (throw (IllegalArgumentException. "Not a path!"))))
diff --git a/docs/cloverage/walkmap/stl.clj.html b/docs/cloverage/walkmap/stl.clj.html index e6cd3a5..61b4549 100644 --- a/docs/cloverage/walkmap/stl.clj.html +++ b/docs/cloverage/walkmap/stl.clj.html @@ -29,7 +29,7 @@ 008              [walkmap.polygon :refer [polygon?]]

- 009              [walkmap.vertex :refer [canonicalise-vertex]]) + 009              [walkmap.vertex :as v])
010    (:import org.clojars.smee.binary.core.BinaryIO @@ -212,7 +212,7 @@ 069      ;; if it has a value for :x it's a vertex, but it doesn't yet conform to `vertex?`
- 070      (:x o) (canonicalise-vertex o) + 070      (:x o) (v/canonicalise o)
071      ;; shouldn't happen @@ -244,10 +244,10 @@ 080    [filename]
- + 081    (let [in (io/input-stream filename)]
- + 082      (canonicalise (b/decode binary-stl in))))
diff --git a/docs/cloverage/walkmap/superstructure.clj.html b/docs/cloverage/walkmap/superstructure.clj.html index fe56429..3c16e1c 100644 --- a/docs/cloverage/walkmap/superstructure.clj.html +++ b/docs/cloverage/walkmap/superstructure.clj.html @@ -70,19 +70,19 @@ 022    [s o v]
- + 023    (if-not (v/vertex? o)
- + 024      (if (:id o)
- + 025        (if (v/vertex? v)
- + 026          (let [vi (or (:vertex-index s) {})
- + 027                current (or (vi (:id v)) {})]
@@ -91,7 +91,7 @@ 029            ;; stage we need to build a map.
- + 030            (assoc vi (:id v) (assoc current (:id o) (:id v))))
@@ -136,28 +136,28 @@ 044    [s o]
- + 045    (assoc
- + 046      s
047      :vertex-index
- + 048      (reduce
- + 049        u/deep-merge
- + 050        (map
- + 051          #(index-vertex s o %)
- + 052          (u/vertices o)))))
@@ -196,22 +196,22 @@ 064    ([o]
- + 065     (add-to-superstructure {} o))
066    ([s o]
- + 067    (cond
- + 068      (map? o) (let [o' (if (:id o) o (assoc o :id (keyword (gensym "obj"))))]
- + 069                 (index-vertices (assoc s (:id o') o') o'))
- + 070      (coll? o) (reduce u/deep-merge (map #(add-to-superstructure s %) o))
@@ -226,11 +226,5 @@ 074  
- - 075  (:vertex-index (add-to-superstructure (:facets (s/decode-binary-stl "resources/isle_of_man.stl")))) -
- - 076  (s/decode-binary-stl "resources/isle_of_man.stl") -
diff --git a/docs/cloverage/walkmap/tag.clj.html b/docs/cloverage/walkmap/tag.clj.html new file mode 100644 index 0000000..53bb926 --- /dev/null +++ b/docs/cloverage/walkmap/tag.clj.html @@ -0,0 +1,203 @@ + + + + walkmap/tag.clj + + + + 001  (ns walkmap.tag +
+ + 002    "Code for tagging, untagging, and finding tags on objects. Note the use of +
+ + 003    the namespaced keyword, `:walkmap.tag/tags`, denoted in this file `::tags`. +
+ + 004    This is in an attempt to avoid name clashes with other uses of this key." +
+ + 005    (:require [clojure.set :refer [difference union]])) +
+ + 006   +
+ + 007  (defn tagged? +
+ + 008    "True if this `object` is tagged with each of these `tags`. It is an error +
+ + 009    (and an exception will be thrown) if +
+ + 010   +
+ + 011    1. `object` is not a map; +
+ + 012    2. any of `tags` is not a keyword." +
+ + 013    [object & tags] +
+ + 014    (if +
+ + 015      (map? object) +
+ + 016      (if +
+ + 017        (every? keyword? tags) +
+ + 018        (let [ot (::tags object)] +
+ + 019          (and +
+ + 020            (set? ot) +
+ + 021            (every? ot tags))) +
+ + 022        (throw (IllegalArgumentException. +
+ + 023                 (str "Must be keyword(s): " (map type tags))))) +
+ + 024      (throw (IllegalArgumentException. +
+ + 025               (str "Must be a map: " (type object)))))) +
+ + 026   +
+ + 027  (defn tag +
+ + 028    "Return an object like this `object` but with these `tags` added to its tags, +
+ + 029    if they are not already present.It is an error (and an exception will be +
+ + 030    thrown) if +
+ + 031   +
+ + 032    1. `object` is not a map; +
+ + 033    2. any of `tags` is not a keyword." +
+ + 034    [object & tags] +
+ + 035    (if +
+ + 036      (map? object) +
+ + 037      (if +
+ + 038        (every? keyword? tags) +
+ + 039        (assoc object ::tags (union (set tags) (::tags object))) +
+ + 040        (throw (IllegalArgumentException. +
+ + 041                 (str "Must be keyword(s): " (map type tags))))) +
+ + 042      (throw (IllegalArgumentException. +
+ + 043               (str "Must be a map: " (type object)))))) +
+ + 044   +
+ + 045  (defmacro tags +
+ + 046    "Return the tags of this object, if any." +
+ + 047    [object] +
+ + 048    `(::tags ~object)) +
+ + 049   +
+ + 050  (defn untag +
+ + 051    "Return an object like this `object` but with these `tags` removed from its +
+ + 052    tags, if present. It is an error (and an exception will be thrown) if +
+ + 053   +
+ + 054    1. `object` is not a map; +
+ + 055    2. any of `tags` is not a keyword." +
+ + 056    [object & tags] +
+ + 057    (if +
+ + 058      (map? object) +
+ + 059      (if +
+ + 060        (every? keyword? tags) +
+ + 061        (assoc object ::tags (difference (::tags object) (set tags))) +
+ + 062        (throw (IllegalArgumentException. +
+ + 063                 (str "Must be keywords: " (map type tags))))) +
+ + 064      (throw (IllegalArgumentException. +
+ + 065               (str "Must be a map: " (type object)))))) +
+ + diff --git a/docs/cloverage/walkmap/utils.clj.html b/docs/cloverage/walkmap/utils.clj.html index f0d7116..44beefb 100644 --- a/docs/cloverage/walkmap/utils.clj.html +++ b/docs/cloverage/walkmap/utils.clj.html @@ -34,10 +34,10 @@ 010    [& vals]
- + 011    (if (every? map? vals)
- + 012      (apply merge-with deep-merge vals)
@@ -70,13 +70,13 @@ 022    [o]
- + 023    (cond
- + 024      (v/vertex? o) (list o)
- + 025      (q/polygon? o) (:vertices o)
diff --git a/docs/cloverage/walkmap/vertex.clj.html b/docs/cloverage/walkmap/vertex.clj.html index 3ba073f..c5c0170 100644 --- a/docs/cloverage/walkmap/vertex.clj.html +++ b/docs/cloverage/walkmap/vertex.clj.html @@ -8,238 +8,247 @@ 001  (ns walkmap.vertex
- 002    "Essentially the specification for things we shall consider to be vertices.") + 002    "Essentially the specification for things we shall consider to be vertices.
003  
+ + 004    Note that there's no `distance` function here; to find the distance between +
+ + 005    two vertices, create an edge from them and use `walkmap.edge/length`.") +
+ + 006   +
- 004  (defn vertex-key + 007  (defn vertex-key
- 005    "Making sure we get the same key everytime we key a vertex with the same + 008    "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 + 009    coordinates. `o` must have numeric values for `:x`, `:y`, and optionally
- 007    `:z`." + 010    `:z`."
- 008    [o] + 011    [o]
- 009    (cond + 012    (cond
- 010      (and (:x o) (:y o) (:z o)) (keyword (str "vert{" (:x o) "|" (:y o) "|" (:z o) "}")) + 013      (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) "}")) + 014      (and (:x o) (:y o)) (keyword (str "vert{" (:x o) "|" (:y o) "}"))
- 012      :else (throw (IllegalArgumentException. "Not a vertex.")))) + 015      :else (throw (IllegalArgumentException. "Not a vertex."))))
- 013   + 016  
- 014  (defn vertex? + 017  (defn vertex?
- 015    "True if `o` satisfies the conditions for a vertex. That is, essentially, + 018    "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 + 019    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 + 020    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 + 021    those keys is a number. If the key `:z` is also present, its value must also
- 019    be a number. + 022    be a number.
- 020   + 023  
- 021    The name  `vector?` was not used as that would clash with a function of that + 024    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." + 025    name in `clojure.core` whose semantics are entirely different."
- 023    [o] + 026    [o]
- 024    (and + 027    (and
- 025      (map? o) + 028      (map? o)
- 026      (:id o) + 029      (:id o)
- 027      (number? (:x o)) + 030      (number? (:x o))
- 028      (number? (:y o)) + 031      (number? (:y o))
- - 029      (or (nil? (:z o)) (number? (:z o))) + + 032      (or (nil? (:z o)) (number? (:z o)))
- 030      (or (nil? (:kind o)) (= (:kind o) :vertex)))) + 033      (or (nil? (:kind o)) (= (:kind o) :vertex))))
- 031   + 034  
- 032  (defn make-vertex + 035  (defn vertex
- 033    "Make a vertex with this `x`, `y` and (if provided) `z` values. Returns a map + 036    "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`. + 037    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` + 038    It's not necessary to use this function to create a vertex, but the `:id`
- 036    must be present and must be unique." + 039    must be present and must be unique."
- 037    ([x y] + 040    ([x y]
- 038     (let [v {:x x :y y :kind :vertex}] + 041     (let [v {:x x :y y :kind :vertex}]
- 039       (assoc v :id (vertex-key v)))) + 042       (assoc v :id (vertex-key v))))
- 040    ([x y z] + 043    ([x y z]
- 041     (assoc (make-vertex x y) :z z))) + 044     (assoc (vertex x y) :z z)))
- 042   + 045  
- 043  (defn canonicalise-vertex + 046  (defn canonicalise
- 044    "If `o` is a map with numeric values for `:x`, `:y` and optionally `:z`, + 047    "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." + 048    upgrade it to something we will recognise as a vertex."
- 046    [o] + 049    [o]
- 047    (if + 050    (if
- 048      (and + 051      (and
- 049        (map? o) + 052        (map? o)
- 050        (number? (:x o)) + 053        (number? (:x o))
- 051        (number? (:y o)) + 054        (number? (:y o))
- 052        (or (nil? (:z o)) (number? (:z o)))) + 055        (or (nil? (:z o)) (number? (:z o))))
- 053      (assoc o :kind :vertex :id (vertex-key o)) + 056      (assoc o :kind :vertex :id (vertex-key o))
- 054      (throw (IllegalArgumentException. "Not a vertex.")))) + 057      (throw (IllegalArgumentException. "Not a proto-vertex: must have numeric `:x` and `:y`."))))
- 055   + 058  
- 056  (def ensure3d + 059  (def ensure3d
- 057    "Given a vertex `o`, if `o` has a `:z` value, just return `o`; otherwise + 060    "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 + 061    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. + 062    `:z` key, or zero as the value of its `:z` key if `dflt` is not specified.
- 060   + 063  
- 061    If `o` is not a vertex, throws an exception." + 064    If `o` is not a vertex, throws an exception."
- 062    (memoize + 065    (memoize
- 063      (fn + 066      (fn
- 064        ([o] + 067        ([o]
- 065         (ensure3d o 0.0)) + 068         (ensure3d o 0.0))
- 066        ([o dflt] + 069        ([o dflt]
- 067         (cond + 070         (cond
- 068           (not (vertex? o)) (throw (IllegalArgumentException. "Not a vertex!")) + 071           (not (vertex? o)) (throw (IllegalArgumentException. "Not a vertex!"))
- 069           (:z o) o + 072           (:z o) o
- 070           :else (assoc o :z dflt)))))) + 073           :else (assoc o :z dflt))))))
- 071   + 074  
- 072  (def ensure2d + 075  (def ensure2d
- 073    "If `o` is a vertex, set its `:z` value to zero; else throw an exception." + 076    "If `o` is a vertex, set its `:z` value to zero; else throw an exception."
- 074    (memoize + 077    (memoize
- 075      (fn [o] + 078      (fn [o]
- 076        (if + 079        (if
- 077          (vertex? o) + 080          (vertex? o)
- 078          (assoc o :z 0.0) + 081          (assoc o :z 0.0)
- 079          (throw (IllegalArgumentException. "Not a vertex!")))))) + 082          (throw (IllegalArgumentException. "Not a vertex!"))))))
diff --git a/docs/codox/dali-performance.html b/docs/codox/dali-performance.html index f90fcc1..6d81232 100644 --- a/docs/codox/dali-performance.html +++ b/docs/codox/dali-performance.html @@ -1,6 +1,6 @@ -Dali performance

Dali performance

+Dali performance

Dali performance

Notes written while trying to characterise the performance problem in Dali.

Hypothesis one: it’s the way I format the polygons that’s the issue

Firstly, with both versions of stl->svg using the same version of facet->svg-poly, i.e. this one:

diff --git a/docs/codox/index.html b/docs/codox/index.html index 2fd020f..766d5d5 100644 --- a/docs/codox/index.html +++ b/docs/codox/index.html @@ -1,3 +1,3 @@ -Walkmap 0.1.0-SNAPSHOT

Walkmap 0.1.0-SNAPSHOT

Released under the EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0

A Clojure library designed to assist in computing walkmaps for games.

Installation

To install, add the following dependency to your project or build file:

[journeyman-cc/walkmap "0.1.0-SNAPSHOT"]

Topics

Namespaces

walkmap.core

This namespace mostly gets used as a scratchpad for ideas which haven’t yet solidified.

Public variables and functions:

    walkmap.edge

    Essentially the specification for things we shall consider to be an edge. An edge is a line segment having just a start and an end, with no intervening nodes.

    Public variables and functions:

    walkmap.geometry

    TODO: write docs

    Public variables and functions:

    walkmap.ocean

    Deal with (specifically, at this stage, cull) ocean areas

    Public variables and functions:

    walkmap.path

    Essentially the specification for things we shall consider to be path.

    Public variables and functions:

    walkmap.polygon

    Essentially the specification for things we shall consider to be polygons.

    Public variables and functions:

    walkmap.stl

    Utility functions dealing with stereolithography (STL) files. Not a stable API yet!

    walkmap.superstructure

    single indexing structure for walkmap objects

    Public variables and functions:

    walkmap.svg

    Utility functions for writing stereolithography (STL) files (and possibly, later, other geometry files of interest to us) as scalable vector graphics (SVG).

    walkmap.utils

    Miscellaneous utility functions.

    Public variables and functions:

    walkmap.vertex

    Essentially the specification for things we shall consider to be vertices.

    Public variables and functions:

    \ No newline at end of file +Walkmap 0.1.0-SNAPSHOT

    Walkmap 0.1.0-SNAPSHOT

    Released under the EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0

    A Clojure library designed to assist in computing walkmaps for games.

    Installation

    To install, add the following dependency to your project or build file:

    [journeyman-cc/walkmap "0.1.0-SNAPSHOT"]

    Topics

    Namespaces

    walkmap.core

    This namespace mostly gets used as a scratchpad for ideas which haven’t yet solidified.

    Public variables and functions:

      walkmap.core

      This namespace mostly gets used as a scratchpad for ideas which haven’t yet solidified.

      Public variables and functions:

        walkmap.edge

        Essentially the specification for things we shall consider to be an edge. An edge is a line segment having just a start and an end, with no intervening nodes.

        Public variables and functions:

        walkmap.geometry

        TODO: write docs

        Public variables and functions:

        walkmap.ocean

        Deal with (specifically, at this stage, cull) ocean areas

        Public variables and functions:

        walkmap.path

        Essentially the specification for things we shall consider to be path.

        Public variables and functions:

        walkmap.polygon

        Essentially the specification for things we shall consider to be polygons.

        Public variables and functions:

        walkmap.stl

        Utility functions dealing with stereolithography (STL) files. Not a stable API yet!

        walkmap.superstructure

        single indexing structure for walkmap objects

        Public variables and functions:

        walkmap.svg

        Utility functions for writing stereolithography (STL) files (and possibly, later, other geometry files of interest to us) as scalable vector graphics (SVG).

        walkmap.tag

        Code for tagging, untagging, and finding tags on objects. Note the use of the namespaced keyword, :walkmap.tag/tags, denoted in this file ::tags. This is in an attempt to avoid name clashes with other uses of this key.

        Public variables and functions:

        walkmap.utils

        Miscellaneous utility functions.

        Public variables and functions:

        walkmap.vertex

        Essentially the specification for things we shall consider to be vertices.

        \ No newline at end of file diff --git a/docs/codox/intro.html b/docs/codox/intro.html index 8e5f50e..b999120 100644 --- a/docs/codox/intro.html +++ b/docs/codox/intro.html @@ -1,6 +1,6 @@ -Introduction to walkmap

        Introduction to walkmap

        +Introduction to walkmap

        Introduction to walkmap

        This library is written in support of work on The Great Game, but is separate because it may be of some use in other settings.

        Usage

        What works:

        diff --git a/docs/codox/walkmap.core.html b/docs/codox/walkmap.core.html index 4dbd673..73868ed 100644 --- a/docs/codox/walkmap.core.html +++ b/docs/codox/walkmap.core.html @@ -1,3 +1,3 @@ -walkmap.core documentation

        walkmap.core

        This namespace mostly gets used as a scratchpad for ideas which haven’t yet solidified.

        \ No newline at end of file +walkmap.core documentation

        walkmap.core

        This namespace mostly gets used as a scratchpad for ideas which haven’t yet solidified.

        \ No newline at end of file diff --git a/docs/codox/walkmap.edge.html b/docs/codox/walkmap.edge.html index fa1c0b8..53996c4 100644 --- a/docs/codox/walkmap.edge.html +++ b/docs/codox/walkmap.edge.html @@ -1,3 +1,4 @@ -walkmap.edge documentation

        walkmap.edge

        Essentially the specification for things we shall consider to be an edge. An edge is a line segment having just a start and an end, with no intervening nodes.

        collinear?

        (collinear? e1 e2)

        True if edges e1 and e2 are collinear with one another.

        edge?

        (edge? o)

        True if o satisfies the conditions for a path. A path shall be a map having the keys :start and :end, such that the values of each of those keys shall be a vertex.

        length

        (length e)

        Return the length of the edge e.

        parallel?

        (parallel? & edges)

        True if all edges passed are parallel with one another.

        path->edges

        (path->edges o)

        if o is a path, a polygon, or a sequence of vertices, return a sequence of edges representing that path, polygon or sequence.

        unit-vector

        (unit-vector e)

        Return an vertex parallel to e starting from the coordinate origin. Two edges which are parallel will have the same unit vector.

        \ No newline at end of file +walkmap.edge documentation

        walkmap.edge

        Essentially the specification for things we shall consider to be an edge. An edge is a line segment having just a start and an end, with no intervening nodes.

        collinear?

        (collinear? e1 e2)

        True if edges e1 and e2 are collinear with one another.

        edge?

        (edge? o)

        True if o satisfies the conditions for a edge. An edge shall be a map having the keys :start and :end, such that the values of each of those keys shall be a vertex.

        length

        (length e)

        Return the length of the edge e.

        parallel?

        (parallel? & edges)

        True if all edges passed are parallel with one another.

        path->edges

        (path->edges o)

        if o is a path, a polygon, or a sequence of vertices, return a sequence of edges representing that path, polygon or sequence.

        +

        Throws IllegalArgumentException if o is not a path, a polygon, or sequence of vertices.

        unit-vector

        (unit-vector e)

        Return an vertex parallel to e starting from the coordinate origin. Two edges which are parallel will have the same unit vector.

        \ No newline at end of file diff --git a/docs/codox/walkmap.geometry.html b/docs/codox/walkmap.geometry.html index bd7067c..722174d 100644 --- a/docs/codox/walkmap.geometry.html +++ b/docs/codox/walkmap.geometry.html @@ -1,3 +1,3 @@ -walkmap.geometry documentation

        walkmap.geometry

        TODO: write docs

        on?

        (on? e v)

        True if the vertex v is on the edge e.

        \ No newline at end of file +walkmap.geometry documentation

        walkmap.geometry

        TODO: write docs

        on?

        (on? e v)

        True if the vertex v is on the edge e.

        \ No newline at end of file diff --git a/docs/codox/walkmap.ocean.html b/docs/codox/walkmap.ocean.html index 4b4d52a..d449226 100644 --- a/docs/codox/walkmap.ocean.html +++ b/docs/codox/walkmap.ocean.html @@ -1,4 +1,4 @@ -walkmap.ocean documentation

        walkmap.ocean

        Deal with (specifically, at this stage, cull) ocean areas

        *sea-level*

        dynamic

        The sea level on heightmaps we’re currently handling. If characters are to be able to swin in the sea, we must model the sea bottom, so we need heightmaps which cover at least the continental shelf. However, the sea bottom is not walkable territory and can be culled from walkmaps.

        +walkmap.ocean documentation

        walkmap.ocean

        Deal with (specifically, at this stage, cull) ocean areas

        *sea-level*

        dynamic

        The sea level on heightmaps we’re currently handling. If characters are to be able to swin in the sea, we must model the sea bottom, so we need heightmaps which cover at least the continental shelf. However, the sea bottom is not walkable territory and can be culled from walkmaps.

        Note must be a floating point number. (= 0 0.0) returns false!

        cull-ocean-facets

        (cull-ocean-facets stl)

        Ye cannae walk on water. Remove all facets from this stl structure which are at sea level.

        ocean?

        (ocean? facet)

        Of a facet, is the altitude of every vertice equal to *sea-level*?

        \ No newline at end of file diff --git a/docs/codox/walkmap.path.html b/docs/codox/walkmap.path.html index 0a63179..eadb965 100644 --- a/docs/codox/walkmap.path.html +++ b/docs/codox/walkmap.path.html @@ -1,4 +1,4 @@ -walkmap.path documentation

        walkmap.path

        Essentially the specification for things we shall consider to be path.

        make-path

        (make-path nodes)

        TODO: write docs

        path?

        (path? o)

        True if o satisfies the conditions for a path. A path shall be a map having the key :nodes, whose value shall be a sequence of vertices as defined in walkmap.vertex.

        polygon->path

        (polygon->path o)

        If o is a polygon, return an equivalent path. What’s different about a path is that in polygons there is an implicit edge between the first vertex and the last. In paths, there isn’t, so we need to add that edge explicitly.

        +walkmap.path documentation

        walkmap.path

        Essentially the specification for things we shall consider to be path.

        make-path

        (make-path nodes)

        TODO: write docs

        path?

        (path? o)

        True if o satisfies the conditions for a path. A path shall be a map having the key :nodes, whose value shall be a sequence of vertices as defined in walkmap.vertex.

        polygon->path

        (polygon->path o)

        If o is a polygon, return an equivalent path. What’s different about a path is that in polygons there is an implicit edge between the first vertex and the last. In paths, there isn’t, so we need to add that edge explicitly.

        If o is not a polygon, will throw an exception.

        \ No newline at end of file diff --git a/docs/codox/walkmap.polygon.html b/docs/codox/walkmap.polygon.html index c3c2657..997efc6 100644 --- a/docs/codox/walkmap.polygon.html +++ b/docs/codox/walkmap.polygon.html @@ -1,3 +1,3 @@ -walkmap.polygon documentation

        walkmap.polygon

        Essentially the specification for things we shall consider to be polygons.

        polygon?

        (polygon? o)

        True if o satisfies the conditions for a polygon. A polygon shall be a map which has a value for the key :vertices, where that value is a sequence of vertices.

        \ No newline at end of file +walkmap.polygon documentation

        walkmap.polygon

        Essentially the specification for things we shall consider to be polygons.

        polygon?

        (polygon? o)

        True if o satisfies the conditions for a polygon. A polygon shall be a map which has a value for the key :vertices, where that value is a sequence of vertices.

        \ No newline at end of file diff --git a/docs/codox/walkmap.stl.html b/docs/codox/walkmap.stl.html index 271e681..bac014e 100644 --- a/docs/codox/walkmap.stl.html +++ b/docs/codox/walkmap.stl.html @@ -1,5 +1,5 @@ -walkmap.stl documentation

        walkmap.stl

        Utility functions dealing with stereolithography (STL) files. Not a stable API yet!

        binary-stl

        A codec for binary STL files

        binary-stl-to-ascii

        (binary-stl-to-ascii in-filename)(binary-stl-to-ascii in-filename out-filename)

        Convert the binary STL file indicated by in-filename, and write it to out-filename, if specified; otherwise, to a file with the same basename as in-filename but the extension .ascii.stl.

        canonicalise

        (canonicalise o)

        Objects read in from STL won’t have all the keys/values we need them to have.

        decode-binary-stl

        (decode-binary-stl filename)

        Parse a binary STL file from this filename and return an STL structure representing its contents.

        +walkmap.stl documentation

        walkmap.stl

        Utility functions dealing with stereolithography (STL) files. Not a stable API yet!

        binary-stl

        A codec for binary STL files

        binary-stl-to-ascii

        (binary-stl-to-ascii in-filename)(binary-stl-to-ascii in-filename out-filename)

        Convert the binary STL file indicated by in-filename, and write it to out-filename, if specified; otherwise, to a file with the same basename as in-filename but the extension .ascii.stl.

        canonicalise

        (canonicalise o)

        Objects read in from STL won’t have all the keys/values we need them to have.

        decode-binary-stl

        (decode-binary-stl filename)

        Parse a binary STL file from this filename and return an STL structure representing its contents.

        NOTE that we’ve no way of verifying that the input file is binary STL data, if it is not this will run but will return garbage.

        facet

        A codec for a facet (triangle) within a binary STL file.

        stl->ascii

        (stl->ascii stl)(stl->ascii stl solidname)

        Return as a string an ASCII rendering of the stl structure.

        stl?

        (stl? o)(stl? o verify-count?)

        True if o is recogniseable as an STL structure. An STL structure must have a key :facets, whose value must be a sequence of polygons; and may have a key :header whose value should be a string, and/or a key :count, whose value should be a positive integer.

        If verify-count? is passed and is not false, verify that the value of the :count header is equal to the number of facets.

        vect

        A codec for vectors within a binary STL file.

        write-ascii-stl

        (write-ascii-stl filename stl)(write-ascii-stl filename stl solidname)

        Write an stl structure as read by decode-binary-stl to this filename as ASCII encoded STL.

        \ No newline at end of file diff --git a/docs/codox/walkmap.superstructure.html b/docs/codox/walkmap.superstructure.html index 0dbecd5..0876fb7 100644 --- a/docs/codox/walkmap.superstructure.html +++ b/docs/codox/walkmap.superstructure.html @@ -1,6 +1,6 @@ -walkmap.superstructure documentation

        walkmap.superstructure

        single indexing structure for walkmap objects

        add-to-superstructure

        (add-to-superstructure o)(add-to-superstructure s o)

        Return a superstructure like s with object o added. If o is a collection, return a superstructure like s with each element of o added. If only one argument is supplied it will be assumed to represent o and a new superstructure will be returned.

        +walkmap.superstructure documentation

        walkmap.superstructure

        single indexing structure for walkmap objects

        add-to-superstructure

        (add-to-superstructure o)(add-to-superstructure s o)

        Return a superstructure like s with object o added. If o is a collection, return a superstructure like s with each element of o added. If only one argument is supplied it will be assumed to represent o and a new superstructure will be returned.

        It is an error (and an exception may be thrown) if

        1. s is not a map;
        2. diff --git a/docs/codox/walkmap.svg.html b/docs/codox/walkmap.svg.html index 2f47187..6b8baa2 100644 --- a/docs/codox/walkmap.svg.html +++ b/docs/codox/walkmap.svg.html @@ -1,3 +1,3 @@ -walkmap.svg documentation

          walkmap.svg

          Utility functions for writing stereolithography (STL) files (and possibly, later, other geometry files of interest to us) as scalable vector graphics (SVG).

          *preferred-svg-render*

          dynamic

          Mainly for debugging dali; switch SVG renderer to use. Expected values: :dali, :hiccup.

          binary-stl-file->svg

          (binary-stl-file->svg in-filename)(binary-stl-file->svg in-filename out-filename)

          Given only an in-filename, parse the indicated file, expected to be binary STL, and return an equivalent SVG structure. Given both in-filename and out-filename, as side-effect write the SVG to the indicated output file.

          dali-stl->svg

          (dali-stl->svg stl minx maxx miny maxy)

          Format this stl as SVG for the dali renderer on a page with these bounds.

          hiccup-stl->svg

          (hiccup-stl->svg stl minx maxx miny maxy)

          Format this stl as SVG for the hiccup renderer on a page with these bounds.

          stl->svg

          (stl->svg stl)

          Convert this in-memory stl structure, as read by decode-binary-stl, into an in-memory hiccup representation of SVG structure, and return it.

          \ No newline at end of file +walkmap.svg documentation

          walkmap.svg

          Utility functions for writing stereolithography (STL) files (and possibly, later, other geometry files of interest to us) as scalable vector graphics (SVG).

          *preferred-svg-render*

          dynamic

          Mainly for debugging dali; switch SVG renderer to use. Expected values: :dali, :hiccup.

          binary-stl-file->svg

          (binary-stl-file->svg in-filename)(binary-stl-file->svg in-filename out-filename)

          Given only an in-filename, parse the indicated file, expected to be binary STL, and return an equivalent SVG structure. Given both in-filename and out-filename, as side-effect write the SVG to the indicated output file.

          dali-stl->svg

          (dali-stl->svg stl minx maxx miny maxy)

          Format this stl as SVG for the dali renderer on a page with these bounds.

          hiccup-stl->svg

          (hiccup-stl->svg stl minx maxx miny maxy)

          Format this stl as SVG for the hiccup renderer on a page with these bounds.

          stl->svg

          (stl->svg stl)

          Convert this in-memory stl structure, as read by decode-binary-stl, into an in-memory hiccup representation of SVG structure, and return it.

          \ No newline at end of file diff --git a/docs/codox/walkmap.tag.html b/docs/codox/walkmap.tag.html new file mode 100644 index 0000000..1c2045c --- /dev/null +++ b/docs/codox/walkmap.tag.html @@ -0,0 +1,15 @@ + +walkmap.tag documentation

          walkmap.tag

          Code for tagging, untagging, and finding tags on objects. Note the use of the namespaced keyword, :walkmap.tag/tags, denoted in this file ::tags. This is in an attempt to avoid name clashes with other uses of this key.

          tag

          (tag object & tags)

          Return an object like this object but with these tags added to its tags, if they are not already present.It is an error (and an exception will be thrown) if

          +
            +
          1. object is not a map;
          2. +
          3. any of tags is not a keyword.
          4. +

          tagged?

          (tagged? object & tags)

          True if this object is tagged with each of these tags. It is an error (and an exception will be thrown) if

          +
            +
          1. object is not a map;
          2. +
          3. any of tags is not a keyword.
          4. +

          tags

          macro

          (tags object)

          Return the tags of this object, if any.

          untag

          (untag object & tags)

          Return an object like this object but with these tags removed from its tags, if present. It is an error (and an exception will be thrown) if

          +
            +
          1. object is not a map;
          2. +
          3. any of tags is not a keyword.
          4. +
          \ No newline at end of file diff --git a/docs/codox/walkmap.utils.html b/docs/codox/walkmap.utils.html index d648133..eed6c5e 100644 --- a/docs/codox/walkmap.utils.html +++ b/docs/codox/walkmap.utils.html @@ -1,3 +1,3 @@ -walkmap.utils documentation

          walkmap.utils

          Miscellaneous utility functions.

          deep-merge

          (deep-merge & vals)

          Recursively merges maps. If vals are not maps, the last value wins.

          vertices

          (vertices o)

          If o is an object with vertices, return those vertices, else nil.

          \ No newline at end of file +walkmap.utils documentation

          walkmap.utils

          Miscellaneous utility functions.

          deep-merge

          (deep-merge & vals)

          Recursively merges maps. If vals are not maps, the last value wins.

          vertices

          (vertices o)

          If o is an object with vertices, return those vertices, else nil.

          \ No newline at end of file diff --git a/docs/codox/walkmap.vertex.html b/docs/codox/walkmap.vertex.html index a8e5c6e..77c0205 100644 --- a/docs/codox/walkmap.vertex.html +++ b/docs/codox/walkmap.vertex.html @@ -1,5 +1,5 @@ -walkmap.vertex documentation

          walkmap.vertex

          Essentially the specification for things we shall consider to be vertices.

          ensure2d

          If o is a vertex, set its :z value to zero; else throw an exception.

          ensure3d

          Given a vertex o, if o has a :z value, just return o; otherwise return a vertex like o but having thie dflt value as the value of its :z key, or zero as the value of its :z key if dflt is not specified.

          -

          If o is not a vertex, throws an exception.

          make-vertex

          (make-vertex x y)(make-vertex x y z)

          Make a vertex with this x, y and (if provided) z values. Returns a map with those values, plus a unique :id value, and :kind set to :vertex. It’s not necessary to use this function to create a vertex, but the :id must be present and must be unique.

          vertex-key

          (vertex-key o)

          Making sure we get the same key everytime we key a vertex with the same coordinates. o must have numeric values for :x, :y, and optionally :z.

          vertex?

          (vertex? o)

          True if o satisfies the conditions for a vertex. That is, essentially, that it must rerpresent a two- or three- dimensional vector. A vertex is shall be a map having at least the keys :x and :y, where the value of those keys is a number. If the key :z is also present, its value must also be a number.

          +walkmap.vertex documentation

          walkmap.vertex

          Essentially the specification for things we shall consider to be vertices.

          canonicalise-vertex

          (canonicalise-vertex o)

          If o is a map with numeric values for :x, :y and optionally :z, upgrade it to something we will recognise as a vertex.

          ensure2d

          If o is a vertex, set its :z value to zero; else throw an exception.

          ensure3d

          Given a vertex o, if o has a :z value, just return o; otherwise return a vertex like o but having thie dflt value as the value of its :z key, or zero as the value of its :z key if dflt is not specified.

          +

          If o is not a vertex, throws an exception.

          make-vertex

          (make-vertex x y)(make-vertex x y z)

          Make a vertex with this x, y and (if provided) z values. Returns a map with those values, plus a unique :id value, and :kind set to :vertex. It’s not necessary to use this function to create a vertex, but the :id must be present and must be unique.

          vertex-key

          (vertex-key o)

          Making sure we get the same key everytime we key a vertex with the same coordinates. o must have numeric values for :x, :y, and optionally :z.

          vertex?

          (vertex? o)

          True if o satisfies the conditions for a vertex. That is, essentially, that it must rerpresent a two- or three- dimensional vector. A vertex is shall be a map having at least the keys :x and :y, where the value of those keys is a number. If the key :z is also present, its value must also be a number.

          The name vector? was not used as that would clash with a function of that name in clojure.core whose semantics are entirely different.

          \ No newline at end of file diff --git a/src/walkmap/edge.clj b/src/walkmap/edge.clj index 356414b..17319ed 100644 --- a/src/walkmap/edge.clj +++ b/src/walkmap/edge.clj @@ -3,10 +3,17 @@ An edge is a line segment having just a start and an end, with no intervening nodes." (:require [clojure.math.numeric-tower :as m] - [walkmap.path :refer [path? polygon->path]] [walkmap.polygon :refer [polygon?]] [walkmap.vertex :refer [ensure3d vertex?]])) +(defn edge + "Return an edge between vertices `v1` and `v2`." + [v1 v2] + (if + (and (vertex? v1) (vertex? v2)) + {:kind :edge :id (keyword (gensym "edge")) :start v1 :end v2} + (throw (IllegalArgumentException. "Must be vertices.")))) + (defn edge? "True if `o` satisfies the conditions for a edge. An edge shall be a map having the keys `:start` and `:end`, such that the values of each of those @@ -17,31 +24,6 @@ (vertex? (:start o)) (vertex? (:end o)))) -(defn path->edges - "if `o` is a path, a polygon, or a sequence of vertices, return a sequence of - edges representing that path, polygon or sequence. - - Throws `IllegalArgumentException` if `o` is not a path, a polygon, or - sequence of vertices." - [o] - (cond - (seq? o) - (when - (and - (vertex? (first o)) - (vertex? (first (rest o)))) - (cons - {:start (first o) - :end (first (rest o))} - (path->edges (rest o)))) - (path? o) - (path->edges (:nodes o)) - (polygon? o) - (path->edges (polygon->path o)) - :else - (throw (IllegalArgumentException. - "Not a path, polygon, or sequence of vertices!")))) - (defn length "Return the length of the edge `e`." [e] diff --git a/src/walkmap/path.clj b/src/walkmap/path.clj index 1928d6e..ebd47c3 100644 --- a/src/walkmap/path.clj +++ b/src/walkmap/path.clj @@ -1,6 +1,9 @@ (ns walkmap.path - "Essentially the specification for things we shall consider to be path." - (:require [walkmap.polygon :refer [polygon?]] + "Essentially the specification for things we shall consider to be path. + **Note that** for these purposes `path` means any continuous linear + feature, where such features specifically include watercourses." + (:require [walkmap.edge :as e] + [walkmap.polygon :refer [polygon?]] [walkmap.vertex :refer [vertex?]])) (defn path? @@ -14,14 +17,16 @@ (seq? v) (> (count v) 2) (every? vertex? v) + (:id o) (or (nil? (:kind o)) (= (:kind o) :path))))) -(defn make-path - [nodes] +(defn path + "Return a path constructed from these `vertices`." + [& vertices] (if - (every? vertex? nodes) - {:nodes nodes :id (keyword (gensym "path")) :kind :path} - (throw (Exception. "Each item on path must be a vertex.")))) + (every? vertex? vertices) + {:nodes vertices :id (keyword (gensym "path")) :kind :path} + (throw (IllegalArgumentException. "Each item on path must be a vertex.")))) (defn polygon->path "If `o` is a polygon, return an equivalent path. What's different about @@ -34,5 +39,40 @@ (if (polygon? o) (assoc (dissoc o :vertices) :kind :path :nodes (concat (:vertices o) (list (first (:vertices o))))) - (throw (Exception. "Not a polygon!")))) + (throw (IllegalArgumentException. "Not a polygon!")))) +(defn path->edges + "if `o` is a path, a polygon, or a sequence of vertices, return a sequence of + edges representing that path, polygon or sequence. + + Throws `IllegalArgumentException` if `o` is not a path, a polygon, or + sequence of vertices." + [o] + (cond + (seq? o) + (when + (and + (vertex? (first o)) + (vertex? (first (rest o)))) + (cons + ;; TODO: think about: when constructing an edge from a path, should the + ;; constructed edge be tagged with the tags of the path? + (e/edge (first o) (rest o)) + (path->edges (rest o)))) + (path? o) + (path->edges (:nodes o)) + :else + (throw (IllegalArgumentException. + "Not a path or sequence of vertices!")))) + +(defn length + "Return the length of this path, in metres. **Note that** + 1. This is not the same as the distance from the start to the end of the + path, which, except for absolutely straight paths, will be shorter; + 2. It is not even quite the same as the length of the path *as rendered*, + since paths will generally be rendered as spline curves." + [path] + (if + (path? path) + (reduce + (map e/length (path->edges path))) + (throw (IllegalArgumentException. "Not a path!")))) diff --git a/src/walkmap/stl.clj b/src/walkmap/stl.clj index accbb09..123bb49 100644 --- a/src/walkmap/stl.clj +++ b/src/walkmap/stl.clj @@ -6,7 +6,7 @@ [org.clojars.smee.binary.core :as b] [taoensso.timbre :as l :refer [info error spy]] [walkmap.polygon :refer [polygon?]] - [walkmap.vertex :refer [canonicalise-vertex]]) + [walkmap.vertex :as v]) (:import org.clojars.smee.binary.core.BinaryIO java.io.DataInput)) @@ -67,7 +67,7 @@ :kind :polygon :vertices (canonicalise (:vertices o))) ;; if it has a value for :x it's a vertex, but it doesn't yet conform to `vertex?` - (:x o) (canonicalise-vertex o) + (:x o) (v/canonicalise o) ;; shouldn't happen :else o)) diff --git a/src/walkmap/tag.clj b/src/walkmap/tag.clj index aacab67..5502fff 100644 --- a/src/walkmap/tag.clj +++ b/src/walkmap/tag.clj @@ -5,7 +5,11 @@ (:require [clojure.set :refer [difference union]])) (defn tagged? - "True if this `object` is tagged with each of these `tags`." + "True if this `object` is tagged with each of these `tags`. It is an error + (and an exception will be thrown) if + + 1. `object` is not a map; + 2. any of `tags` is not a keyword." [object & tags] (if (map? object) @@ -14,8 +18,7 @@ (let [ot (::tags object)] (and (set? ot) - (every? ot tags) - true)) + (every? ot tags))) (throw (IllegalArgumentException. (str "Must be keyword(s): " (map type tags))))) (throw (IllegalArgumentException. @@ -23,7 +26,11 @@ (defn tag "Return an object like this `object` but with these `tags` added to its tags, - if they are not already present." + if they are not already present.It is an error (and an exception will be + thrown) if + + 1. `object` is not a map; + 2. any of `tags` is not a keyword." [object & tags] (if (map? object) @@ -35,9 +42,17 @@ (throw (IllegalArgumentException. (str "Must be a map: " (type object)))))) +(defmacro tags + "Return the tags of this object, if any." + [object] + `(::tags ~object)) + (defn untag "Return an object like this `object` but with these `tags` removed from its - tags, if present." + tags, if present. It is an error (and an exception will be thrown) if + + 1. `object` is not a map; + 2. any of `tags` is not a keyword." [object & tags] (if (map? object) diff --git a/src/walkmap/vertex.clj b/src/walkmap/vertex.clj index 6a01de2..ea8d8bc 100644 --- a/src/walkmap/vertex.clj +++ b/src/walkmap/vertex.clj @@ -1,5 +1,8 @@ (ns walkmap.vertex - "Essentially the specification for things we shall consider to be vertices.") + "Essentially the specification for things we shall consider to be vertices. + + Note that there's no `distance` function here; to find the distance between + two vertices, create an edge from them and use `walkmap.edge/length`.") (defn vertex-key "Making sure we get the same key everytime we key a vertex with the same @@ -29,7 +32,7 @@ (or (nil? (:z o)) (number? (:z o))) (or (nil? (:kind o)) (= (:kind o) :vertex)))) -(defn make-vertex +(defn vertex "Make a vertex with this `x`, `y` and (if provided) `z` values. Returns a map with those values, plus a unique `:id` value, and `:kind` set to `:vertex`. It's not necessary to use this function to create a vertex, but the `:id` @@ -38,9 +41,9 @@ (let [v {:x x :y y :kind :vertex}] (assoc v :id (vertex-key v)))) ([x y z] - (assoc (make-vertex x y) :z z))) + (assoc (vertex x y) :z z))) -(defn canonicalise-vertex +(defn canonicalise "If `o` is a map with numeric values for `:x`, `:y` and optionally `:z`, upgrade it to something we will recognise as a vertex." [o] @@ -51,7 +54,7 @@ (number? (:y o)) (or (nil? (:z o)) (number? (:z o)))) (assoc o :kind :vertex :id (vertex-key o)) - (throw (IllegalArgumentException. "Not a vertex.")))) + (throw (IllegalArgumentException. "Not a proto-vertex: must have numeric `:x` and `:y`.")))) (def ensure3d "Given a vertex `o`, if `o` has a `:z` value, just return `o`; otherwise diff --git a/test/walkmap/edge_test.clj b/test/walkmap/edge_test.clj index fe5865b..e8dc303 100644 --- a/test/walkmap/edge_test.clj +++ b/test/walkmap/edge_test.clj @@ -1,12 +1,12 @@ (ns walkmap.edge-test (:require [clojure.test :refer :all] [walkmap.edge :refer :all] - [walkmap.vertex :refer [make-vertex]])) + [walkmap.vertex :refer [vertex]])) (deftest edge-test (testing "identification of edges." - (is (edge? {:start (make-vertex 0.0 0.0 0.0) - :end (make-vertex 3 4 0.0)}) "It is.") + (is (edge? {:start (vertex 0.0 0.0 0.0) + :end (vertex 3 4 0.0)}) "It is.") (is (not (edge? {:start {:y 0.0 :z 0.0 :id 'foo} :end {:x 3 :y 4 :z 0.0 :id 'bar}})) "Start lacks :x key") (is (not (edge? {:start {:x nil :y 0.0 :z 0.0 :id 'foo} @@ -17,7 +17,16 @@ :finish {:x 3 :y 4 :z 0.0 :id 'bar}})) "Lacks end key") (is (not (edge? {:start {:x "zero" :y 0.0 :z 0.0 :id 'foo} :end {:x 3 :y 4 :z 0.0 :id 'bar}})) "Value of x in start is not a number") - )) + (is (false? (edge? "I am not an edge")) "Edge mustbe a map."))) + +(deftest construction-test + (testing "Construction of edges." + (is (edge? (edge (vertex 1.0 2.0 3.0) (vertex 4.0 8.0 12.0))) + "If both arguments are vertices, we should get an edge") + (is (thrown? IllegalArgumentException (edge "Not a vertex" (vertex 1 2))) + "If first argument is not a vertex, we should get an exception.") + (is (thrown? IllegalArgumentException (edge (vertex 1 2) "Not a vertex")) + "If second argument is not a vertex, we should get an exception."))) (deftest length-test (testing "length of an edge" diff --git a/test/walkmap/tag_test.clj b/test/walkmap/tag_test.clj index 9f0a269..00d578a 100644 --- a/test/walkmap/tag_test.clj +++ b/test/walkmap/tag_test.clj @@ -5,7 +5,7 @@ (deftest tag-tests (testing "Tagging" (is (set? (:walkmap.tag/tags (tag {} :foo :bar :ban :froboz))) - "The value of `:walkmap.tag/tags should be a set.") + "The value of `:walkmap.tag/tags` should be a set.") (is (= (count (:walkmap.tag/tags (tag {} :foo :bar :ban :froboz))) 4) "All the tags passed should be added.") (is (:walkmap.tag/tags (tag {} :foo :bar :ban :froboz) :ban) @@ -17,12 +17,18 @@ "`tagged?` should return an explicit `true`, not any other value.") (is (tagged? (tag {} :foo :bar :ban :froboz) :bar :froboz) "We should be able to test for the presence of more than one tag") + (is (false? (tagged? {} :foo)) + "A missing `:walkmap.tag/tags` should not cause an error.") (is (= (tagged? (tag {} :foo :bar :ban :froboz) :bar :cornflakes) false) "If any of the queried tags is missing, false should be returned") (is (tagged? (tag (tag {} :foo) :bar) :foo :bar) "We should be able to add tags to an already tagged object") (is (false? (tagged? (tag {} :foo :bar) :cornflakes)) "`tagged?` should return an explicit `false` if a queried tag is missing.") + (is (= (tags (tag {} :foo)) #{:foo}) + "`tags` should return the tags on the object, if any.") + (is (every? nil? (map #(tags %) [1 :one "one" [:one] {:one 1}])) + "Things which don't have tags don't have tags, and that's not a problem.") (let [object (tag {} :foo :bar :ban :froboz)] (is (= (untag object :cornflakes) object) "Removing a missing tag should have no effect.")