Compare commits

...

40 commits

Author SHA1 Message Date
Simon Brooke fd15e41952 Builds and runs; output is crazily wrong... 2024-04-13 15:35:50 +01:00
Simon Brooke 4187b52c66 Can *probably* convert MicroWorld to STL
Code is written. It isn't tested.
2024-04-12 22:29:16 +01:00
Simon Brooke a0b2b93f6b Can now read back a superstructure written to a file. 2024-04-12 15:22:46 +01:00
Simon Brooke 733bc7768d Do parallel mapping over rows.
Not that it will make much difference, but performance on this is currently very poor.
2024-04-11 15:26:05 +01:00
Simon Brooke 18fbc61d2b Small amount more tidyup
`load-microworld-edn` now tested with a large data set.
2024-04-10 09:10:20 +01:00
Simon Brooke cb5041e684 Massive code clean-up, all tests still pass.
...but I'm still struggling to understand how it works and how I use it. Memo to self: document your code better.
2024-04-08 22:36:10 +01:00
Simon Brooke 156775fc79 Changed Gorilla dependency, since the canonical version no longer works 2024-04-04 12:20:05 +01:00
Simon Brooke 56566a9c1c Unwanted config files 2024-04-03 12:20:20 +01:00
Simon Brooke 311edb233b Ignoring a number of configuration files
belonging to things I don't have any special config for.
2024-04-03 12:18:45 +01:00
Simon Brooke a0cf33ac57
Whoops! Failed to add new file versions in last commit! 2020-11-15 21:12:34 +00:00
Simon Brooke cf0b70e816
Changes all namespaces by prefixing with 'cc.journeyman.'. Not all tests pass. 2020-11-15 19:06:28 +00:00
Simon Brooke 4161f4f04a
New developed Isle of Man maps; work on intersections. 2020-06-29 21:36:23 +01:00
Simon Brooke 48d9aacb69
Written, not yet working. 2020-06-05 13:09:23 +01:00
Simon Brooke 99a6c6824a
Enormous progress on routing, but not there yet.
All existing unit tests still pass, but new code is not instrumented yet.
2020-06-04 16:16:02 +01:00
Simon Brooke 777b8bc077
Solid start made on routing. 2020-06-03 21:53:27 +01:00
Simon Brooke 9687e57666
Woohoo! Now I can meaningfully search a superstructure! 2020-06-03 19:12:08 +01:00
Simon Brooke 4b76eb5e4f
More tests, all pass. 2020-06-03 16:26:30 +01:00
Simon Brooke 3ba8033be8
Started MicroWorld integration; more work on unit tests 2020-06-03 15:48:12 +01:00
Simon Brooke 5328e89c96
Work on test coverage. Tedious, but useful. 2020-05-31 17:00:02 +01:00
Simon Brooke e07dc7098c
Cloverage/ Kibit now working again
There was an - unterminated function in svg.clj, now removed.
2020-05-31 11:44:09 +01:00
Simon Brooke c7469051f4
Kibitsing, cleanup.
There's a problem here that both kibit and cloverage are reporting an unterminated file, but all tests run.
2020-05-31 11:31:36 +01:00
Simon Brooke 819aa0fbc4
Added: scaling and storing STL; beginnings of search 2020-05-31 10:33:56 +01:00
Simon Brooke 87177051da
Added: triangle?, gradient, vertex (vector) multiply. 2020-05-31 09:12:28 +01:00
Simon Brooke 989a8fe91d
: done 2020-05-30 23:46:55 +01:00
Simon Brooke 75899f8a4d
Merge branch 'feature/3' into develop 2020-05-30 23:02:10 +01:00
Simon Brooke fde35f636f
: All tests pass. 2020-05-30 23:01:55 +01:00
Simon Brooke 4c5867b390
Yet more unit tests, no new failures 2020-05-30 16:28:17 +01:00
Simon Brooke a0882f7ebd
: Written many unit tests (good). Some fail (bad). 2020-05-30 15:54:07 +01:00
Simon Brooke f93432a241
: Still problems in index-vertices, I think 2020-05-30 14:09:14 +01:00
Simon Brooke 7442673cbf
: Very close to working, but not quite! 2020-05-30 09:14:28 +01:00
Simon Brooke f2c39f9017
Can now adequately read paths from SVG
Not yet reading curvature, which will probably one day be necessary.
2020-05-29 11:23:24 +01:00
Simon Brooke 9892af65e3
: Good progress towards getting SVG reading going, but not there yet. 2020-05-28 17:48:01 +01:00
Simon Brooke 4df5c4dff4
Merge branch 'feature/3' into develop 2020-05-27 18:59:17 +01:00
Simon Brooke 1ab35dbe7d
Line intersection looking good. 2020-05-27 18:54:36 +01:00
Simon Brooke 79174af2c1
Inching forward, positively 2020-05-26 23:33:26 +01:00
Simon Brooke 9ee365b987
In the afternoon, he implemented tagging.
And he looked on his work, and saw that it was good.
2020-05-26 17:08:00 +01:00
Simon Brooke f4ca49f11b
Work on routing. 2020-05-26 11:40:44 +01:00
Simon Brooke f616992191
: Massive changes, superstructure now kind-of works
More unit tests now, and they all pass. More work needed, but this is very promising.
2020-05-25 23:55:52 +01:00
Simon Brooke f49a7495db
Fixed comments! 2020-05-25 12:16:11 +01:00
Simon Brooke 387d817e9b
Investigation of Dali performance issue 2020-05-25 12:11:06 +01:00
92 changed files with 2189794 additions and 1312 deletions

21
.gitignore vendored
View file

@ -10,9 +10,30 @@ pom.xml.asc
*.svg
/.lein-*
/.nrepl-port
.clj-kondo
.lsp
.hgignore
.hg/
resources/isle_of_man.svg
resources/small_hill.svg
s.edn
.eastwood
settlement_1.edn
small_hill.edn
small_hill.html
.calva/output-window/output.calva-repl
.classpath
.project
.settings/org.eclipse.jdt.apt.core.prefs
.settings/org.eclipse.jdt.core.prefs
.settings/org.eclipse.m2e.core.prefs
resources/superstructure-raw-20240410.edn

View file

@ -8,6 +8,96 @@ This library is written in support of work on
[The Great Game](https://simon-brooke.github.io/the-great-game/codox/Pathmaking.html), but is
separate because it may be of some use in other settings.
## Explanation
*I'm writing this becaue, having returned to this project after four years of
being distracted by other things, I couldn't even remember what it was for,
let alone how to use it.*
### 'STL files'
'STL' is not an acronym but an abbreviation; an abreviation of
'[stereolithography](https://en.wikipedia.org/wiki/Stereolithography)'. Even
that name is completely misleading, since there is absolutely no sense in
which this is printing with stone.
What an STL file is is in fact a representation of a mesh, originally intended
for use in 3d printing, and therefore taken to be the bounding mesh of a solid.
This makes it a better format for representing landforms for games than a
simple heightmap, since heightmaps cannot represent things like overhangs and
caves.
STL files come in two subformats: 'ASCII' (which this library can currently
read and write), and 'Binary' (which this library can read but not yet write).
STL files are commonly used in game development and can be imported by all of
* [Blender](https://docs.blender.org/manual/en/latest/files/import_export/stl.html)
* [Godot Engine](https://godotengine.org/asset-library/asset/961)
* [Unity](https://github.com/karl-/pb_Stl) (unofficial)
* [Unreal Engine](https://github.com/rdeioris/UnrealSTL) (unofficial)
Additionally, a number of programs exist to convert STL files into other 3D
model file formats.
### 'Superstructure'
I can't remember if 'superstructure' is a name which I found in reading the
literature on STL files, or whether it's one I came up with for my own
purposes, but essentially in my usage of it:
1. [MicroWorld](https://github.com/simon-brooke/mw-engine) is a two dimensional
cellular automaton, which I wrote, and which can be used (and which I use) to
model ecological processes up to and including human settlement;
2. As a two dimensional cellular automaton, it is necessarily essentially a
flat mesh, but I essentially drape that over a
[heightmap](https://github.com/simon-brooke/mw-engine/blob/master/src/mw_engine/heightmap.clj)
to give a sort of notional two-and-a-half dimensional representation;
3. As such MicroWorld is a moderately useful tool to transform an imagined land
form into a vegetated and populated landscape, with biomes and human habitation
distributed naturalistically.
A 'superstructure', then, in the terms I'm using it, is an intermediary
representation between a heightmap and a stereolithography model, which carries
data not only about shape, but about biomes, settlement, traversibility and so
on. Thus it is a surface across which routes can efficiently be planned.
A superstructure can currently be constructed from a MicroWorld world, read in
from an [Extensible Data Notation](https://github.com/edn-format/edn). There
isn't currently a function to construct a superstructure from an in-memory
MicroWorld world, because MicroWorld, when working with models of the size I'm
using, is hugely memory hungry; but there clearly could be and that is an
addition you should expect.
A superstructure cannot currently be constructed directly from a heightmap, but
that would also be a trivial enhancement and is planned.
```clojure
(use 'cc.journeyman.walkmap.microworld :reload)
(require '[cc.journeyman.walkmap.vertex :refer [vertex]])
(load-microworld-edn
"../the-great-game/resources/test/galloway-populated-20240407.edn")
```
or
```clojure
(use 'cc.journeyman.walkmap.microworld :reload)
(require '[cc.journeyman.walkmap.vertex :refer [vertex]])
(load-microworld-edn
"../the-great-game/resources/test/galloway-populated-20240407.edn" :mw {}
(vertex 1000 1000 10))
```
Note that this is a lot of processing and even on a fast machine is going to
take significant walkclock time. You cannot reasonably do it, except for
utterly trivial times, during game initialisation; instead you need to do it
in the 'baking' phase of game development, and consider the STL file as the
resoource to be shipped with the game.
However, although it is time-expensive, it is not, unlike MicroWorld, either
memory or processor hungry. This will not blow up your machine.
A superstructure can be written to an ASCII STL file.
## Usage
What works:

BIN
doc/Dali-performance.ods Normal file

Binary file not shown.

148
doc/dali-performance.md Normal file
View file

@ -0,0 +1,148 @@
# 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:
(defn- facet->svg-poly
[facet]
[:polygon
{:points (s/join " " (map #(str (:x %) "," (:y %)) (:vertices facet)))}])
we get this performance using the smaller `isle_of_man` map:
walkmap.svg=> (def ^:dynamic *preferred-svg-render* :hiccup)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=> (time (def hiccup (binary-stl-file->svg "resources/isle_of_man.stl" "resources/isle_of_man.svg")))
20-05-25 09:21:43 mason INFO [walkmap.svg:82] - Generating SVG for :hiccup renderer
20-05-25 09:21:43 mason INFO [walkmap.svg:96] - Emitting SVG with :hiccup renderer
"Elapsed time: 86.904891 msecs"
#'walkmap.svg/hiccup
walkmap.svg=> (def ^:dynamic *preferred-svg-render* :dali)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=> (time (def dali (binary-stl-file->svg "resources/isle_of_man.stl" "resources/isle_of_man.svg")))
20-05-25 09:22:17 mason INFO [walkmap.svg:82] - Generating SVG for :dali renderer
20-05-25 09:22:17 mason INFO [walkmap.svg:96] - Emitting SVG with :dali renderer
"Elapsed time: 890.863814 msecs"
#'walkmap.svg/dali
If we switch the Dali render to use my original version of `facet->svg-poly`, i.e. this one:
(defn- dali-facet->svg-poly
[facet]
(vec
(cons
:polygon
(map #(vec (list (:x %) (:y %))) (:vertices facet)))))
we get this performance:
walkmap.svg=> (def ^:dynamic *preferred-svg-render* :hiccup)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=> (time (def hiccup (binary-stl-file->svg "resources/isle_of_man.stl" "resources/isle_of_man.svg")))
20-05-25 09:35:33 mason INFO [walkmap.svg:82] - Generating SVG for :hiccup renderer
20-05-25 09:35:33 mason INFO [walkmap.svg:96] - Emitting SVG with :hiccup renderer
"Elapsed time: 84.09972 msecs"
#'walkmap.svg/hiccup
walkmap.svg=> (def ^:dynamic *preferred-svg-render* :dali)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=> (time (def dali (binary-stl-file->svg "resources/isle_of_man.stl" "resources/isle_of_man.svg")))
20-05-25 09:35:41 mason INFO [walkmap.svg:82] - Generating SVG for :dali renderer
20-05-25 09:35:41 mason INFO [walkmap.svg:96] - Emitting SVG with :dali renderer
"Elapsed time: 874.292007 msecs"
#'walkmap.svg/dali
No significant difference in performance.
If we generate but don't render, we get this:
walkmap.svg=> (def ^:dynamic *preferred-svg-render* :hiccup)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=> (time (def hiccup (binary-stl-file->svg "resources/isle_of_man.stl")))
20-05-25 09:37:44 mason INFO [walkmap.svg:82] - Generating SVG for :hiccup renderer
"Elapsed time: 52.614707 msecs"
#'walkmap.svg/hiccup
walkmap.svg=> (def ^:dynamic *preferred-svg-render* :dali)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=> (time (def dali (binary-stl-file->svg "resources/isle_of_man.stl")))
20-05-25 09:38:07 mason INFO [walkmap.svg:82] - Generating SVG for :dali renderer
"Elapsed time: 49.891043 msecs"
#'walkmap.svg/dali
This implies that the problem is not in the way polygons are formatted.
The difference between the two versions of `facet->svg-poly` is as follows:
### New version, works with both Hiccup and Dali:
walkmap.svg=> (def stl (decode-binary-stl "resources/isle_of_man.stl"))
#'walkmap.svg/stl
walkmap.svg=> (def facet (first (:facets stl)))
#'walkmap.svg/facet
walkmap.svg=> (pprint facet)
{:normal {:x -0.0, :y 0.0, :z 1.0},
:vertices
[{:x 3.0, :y 1.0, :z 1.0}
{:x 2.0, :y 3.0, :z 1.0}
{:x 0.0, :y 0.0, :z 1.0}],
:abc 0}
nil
walkmap.svg=> (pprint (facet->svg-poly facet))
[:polygon {:points "3.0,1.0 2.0,3.0 0.0,0.0"}]
nil
In other words, the new version constructs the `:points` attribute of the `:polygon` tag by string concatenation, and the renderer just needs to output it.
### Older version, works with Dali only:
walkmap.svg=> (pprint (dali-facet->svg-poly facet))
[:polygon [3.0 1.0] [2.0 3.0] [0.0 0.0]]
nil
This means that the renderer is actually doing more work, since it has to compose the `:points` attribute itself; nevertheless there doesn't seem to be an increased time penalty.
### Conclusion
It doesn't seem that formatting the polygons is the issue.
## Hypothesis two: Dali renderer scales non-linearly with number of objects drawn
To test this, we need some otherwise-similar test files with different numbers of objects:
walkmap.svg=> (count (:facets stl))
4416
walkmap.svg=> (def small-stl (assoc stl :facets (take 400 (:facets stl))))
#'walkmap.svg/small-stl
walkmap.svg=> (count (:facets small-stl))
400
walkmap.svg=> (def large-stl (decode-binary-stl "../the-great-game/resources/maps/heightmap.stl"))
#'walkmap.svg/large-stl
walkmap.svg=> (count (:facets large-stl))
746585
walkmap.svg=> (def ^:dynamic *preferred-svg-render* :dali)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=> (time (dali.io/render-svg (stl->svg small-stl) "dali-small.svg"))
20-05-25 10:12:25 mason INFO [walkmap.svg:92] - Generating SVG for :dali renderer
"Elapsed time: 32.55506 msecs"
nil
walkmap.svg=> (def ^:dynamic *preferred-svg-render* :hiccup)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=> (time (spit "hiccup-small.svg" (hiccup.core/html (stl->svg small-stl))))
20-05-25 10:14:07 mason INFO [walkmap.svg:92] - Generating SVG for :hiccup renderer
"Elapsed time: 10.026369 msecs"
So we have
| | Dali | | Hiccup | | |
| ----------- | ---------------- | ----------- | ------------ | ----------- | ------------------- |
| # of facets | time (msecs) | objets/msec | time (msecs) | objets/msec | ratio (Dali/Hiccup) |
| ----------- | ---------------- | ----------- | ------------ | ----------- | --------------------|
| 400 | 32.55506 | 12.29 | 10.026369 | 39.89 | 3.35 |
| 4416 | 874.292007 | 5.05 | 84.09972 | 52.51 | 10.40 |
| 746585 | 29,695,695.61 | 0.03 | 16724.848222 | 44.64 | 1775.54 |
### Conclusion
What we're seeing is that Hiccup renders more or less linearly by the number of objects (bear in mind that all of these objects are triangles, so essentially equally complex to render), whereas the performance of Dali degrades significantly as the number of objects increases.

View file

@ -14,135 +14,221 @@
<td class="with-number">Lines %</td>
<td class="with-number">Total</td><td class="with-number">Blank</td><td class="with-number">Instrumented</td>
</tr></thead>
<tr>
<td><a href="walkmap/core.clj.html">walkmap.core</a></td><td class="with-bar"><div class="covered"
style="width:12.244897959183673%;
float:left;"> 6 </div><div class="not-covered"
style="width:87.75510204081633%;
float:left;"> 43 </div></td>
<td class="with-number">12.24 %</td>
<td class="with-bar"><div class="covered"
style="width:38.46153846153846%;
float:left;"> 5 </div><div class="not-covered"
style="width:61.53846153846154%;
float:left;"> 8 </div></td>
<td class="with-number">38.46 %</td>
<td class="with-number">44</td><td class="with-number">6</td><td class="with-number">13</td>
</tr>
<tr>
<td><a href="walkmap/edge.clj.html">walkmap.edge</a></td><td class="with-bar"><div class="covered"
style="width:69.38775510204081%;
float:left;"> 136 </div><div class="not-covered"
style="width:30.612244897959183%;
float:left;"> 60 </div></td>
<td class="with-number">69.39 %</td>
style="width:98.37177747625509%;
float:left;"> 725 </div><div class="not-covered"
style="width:1.6282225237449117%;
float:left;"> 12 </div></td>
<td class="with-number">98.37 %</td>
<td class="with-bar"><div class="covered"
style="width:70.0%;
float:left;"> 35 </div><div class="partial"
style="width:2.0%;
float:left;"> 1 </div><div class="not-covered"
style="width:28.0%;
float:left;"> 14 </div></td>
<td class="with-number">72.00 %</td>
<td class="with-number">82</td><td class="with-number">7</td><td class="with-number">50</td>
style="width:95.32710280373831%;
float:left;"> 102 </div><div class="partial"
style="width:4.672897196261682%;
float:left;"> 5 </div></td>
<td class="with-number">100.00 %</td>
<td class="with-number">177</td><td class="with-number">17</td><td class="with-number">107</td>
</tr>
<tr>
<td><a href="walkmap/geometry.clj.html">walkmap.geometry</a></td><td class="with-bar"><div class="covered"
style="width:1.6260162601626016%;
float:left;"> 2 </div><div class="not-covered"
style="width:98.3739837398374%;
float:left;"> 121 </div></td>
<td class="with-number">1.63 %</td>
<td><a href="walkmap/id.clj.html">walkmap.id</a></td><td class="with-bar"><div class="covered"
style="width:100.0%;
float:left;"> 3 </div></td>
<td class="with-number">100.00 %</td>
<td class="with-bar"><div class="covered"
style="width:15.384615384615385%;
float:left;"> 2 </div><div class="not-covered"
style="width:84.61538461538461%;
float:left;"> 11 </div></td>
<td class="with-number">15.38 %</td>
<td class="with-number">24</td><td class="with-number">3</td><td class="with-number">13</td>
style="width:100.0%;
float:left;"> 2 </div></td>
<td class="with-number">100.00 %</td>
<td class="with-number">8</td><td class="with-number">2</td><td class="with-number">2</td>
</tr>
<tr>
<td><a href="walkmap/microworld.clj.html">walkmap.microworld</a></td><td class="with-bar"><div class="covered"
style="width:1.5957446808510638%;
float:left;"> 3 </div><div class="not-covered"
style="width:98.40425531914893%;
float:left;"> 185 </div></td>
<td class="with-number">1.60 %</td>
<td class="with-bar"><div class="covered"
style="width:7.5%;
float:left;"> 3 </div><div class="not-covered"
style="width:92.5%;
float:left;"> 37 </div></td>
<td class="with-number">7.50 %</td>
<td class="with-number">75</td><td class="with-number">6</td><td class="with-number">40</td>
</tr>
<tr>
<td><a href="walkmap/ocean.clj.html">walkmap.ocean</a></td><td class="with-bar"><div class="covered"
style="width:100.0%;
float:left;"> 28 </div></td>
<td class="with-number">100.00 %</td>
<td class="with-bar"><div class="covered"
style="width:100.0%;
float:left;"> 8 </div></td>
<td class="with-number">100.00 %</td>
<td class="with-number">25</td><td class="with-number">4</td><td class="with-number">8</td>
</tr>
<tr>
<td><a href="walkmap/path.clj.html">walkmap.path</a></td><td class="with-bar"><div class="covered"
style="width:5.555555555555555%;
float:left;"> 3 </div><div class="not-covered"
style="width:94.44444444444444%;
float:left;"> 51 </div></td>
<td class="with-number">5.56 %</td>
style="width:93.9622641509434%;
float:left;"> 249 </div><div class="not-covered"
style="width:6.037735849056604%;
float:left;"> 16 </div></td>
<td class="with-number">93.96 %</td>
<td class="with-bar"><div class="covered"
style="width:23.076923076923077%;
float:left;"> 3 </div><div class="not-covered"
style="width:76.92307692307692%;
float:left;"> 10 </div></td>
<td class="with-number">23.08 %</td>
<td class="with-number">30</td><td class="with-number">4</td><td class="with-number">13</td>
style="width:88.88888888888889%;
float:left;"> 32 </div><div class="partial"
style="width:11.11111111111111%;
float:left;"> 4 </div></td>
<td class="with-number">100.00 %</td>
<td class="with-number">93</td><td class="with-number">9</td><td class="with-number">36</td>
</tr>
<tr>
<td><a href="walkmap/polygon.clj.html">walkmap.polygon</a></td><td class="with-bar"><div class="covered"
style="width:7.407407407407407%;
float:left;"> 2 </div><div class="not-covered"
style="width:92.5925925925926%;
float:left;"> 25 </div></td>
<td class="with-number">7.41 %</td>
style="width:50.87976539589443%;
float:left;"> 347 </div><div class="not-covered"
style="width:49.12023460410557%;
float:left;"> 335 </div></td>
<td class="with-number">50.88 %</td>
<td class="with-bar"><div class="covered"
style="width:25.0%;
style="width:61.333333333333336%;
float:left;"> 46 </div><div class="partial"
style="width:9.333333333333334%;
float:left;"> 7 </div><div class="not-covered"
style="width:29.333333333333332%;
float:left;"> 22 </div></td>
<td class="with-number">70.67 %</td>
<td class="with-number">155</td><td class="with-number">14</td><td class="with-number">75</td>
</tr>
<tr>
<td><a href="walkmap/read_svg.clj.html">walkmap.read-svg</a></td><td class="with-bar"><div class="covered"
style="width:2.857142857142857%;
float:left;"> 7 </div><div class="not-covered"
style="width:97.14285714285714%;
float:left;"> 238 </div></td>
<td class="with-number">2.86 %</td>
<td class="with-bar"><div class="covered"
style="width:15.217391304347826%;
float:left;"> 7 </div><div class="not-covered"
style="width:84.78260869565217%;
float:left;"> 39 </div></td>
<td class="with-number">15.22 %</td>
<td class="with-number">100</td><td class="with-number">8</td><td class="with-number">46</td>
</tr>
<tr>
<td><a href="walkmap/routing.clj.html">walkmap.routing</a></td><td class="with-bar"><div class="covered"
style="width:5.678233438485805%;
float:left;"> 18 </div><div class="not-covered"
style="width:94.3217665615142%;
float:left;"> 299 </div></td>
<td class="with-number">5.68 %</td>
<td class="with-bar"><div class="covered"
style="width:17.56756756756757%;
float:left;"> 13 </div><div class="partial"
style="width:2.7027027027027026%;
float:left;"> 2 </div><div class="not-covered"
style="width:75.0%;
float:left;"> 6 </div></td>
<td class="with-number">25.00 %</td>
<td class="with-number">17</td><td class="with-number">3</td><td class="with-number">8</td>
style="width:79.72972972972973%;
float:left;"> 59 </div></td>
<td class="with-number">20.27 %</td>
<td class="with-number">201</td><td class="with-number">21</td><td class="with-number">74</td>
</tr>
<tr>
<td><a href="walkmap/stl.clj.html">walkmap.stl</a></td><td class="with-bar"><div class="covered"
style="width:17.228464419475657%;
float:left;"> 46 </div><div class="not-covered"
style="width:82.77153558052434%;
float:left;"> 221 </div></td>
<td class="with-number">17.23 %</td>
style="width:50.638297872340424%;
float:left;"> 238 </div><div class="not-covered"
style="width:49.361702127659576%;
float:left;"> 232 </div></td>
<td class="with-number">50.64 %</td>
<td class="with-bar"><div class="covered"
style="width:28.125%;
float:left;"> 18 </div><div class="not-covered"
style="width:71.875%;
float:left;"> 46 </div></td>
<td class="with-number">28.13 %</td>
<td class="with-number">126</td><td class="with-number">12</td><td class="with-number">64</td>
style="width:40.56603773584906%;
float:left;"> 43 </div><div class="partial"
style="width:9.433962264150944%;
float:left;"> 10 </div><div class="not-covered"
style="width:50.0%;
float:left;"> 53 </div></td>
<td class="with-number">50.00 %</td>
<td class="with-number">206</td><td class="with-number">16</td><td class="with-number">106</td>
</tr>
<tr>
<td><a href="walkmap/superstructure.clj.html">walkmap.superstructure</a></td><td class="with-bar"><div class="covered"
style="width:44.61538461538461%;
float:left;"> 261 </div><div class="not-covered"
style="width:55.38461538461539%;
float:left;"> 324 </div></td>
<td class="with-number">44.62 %</td>
<td class="with-bar"><div class="covered"
style="width:48.507462686567166%;
float:left;"> 65 </div><div class="partial"
style="width:2.985074626865672%;
float:left;"> 4 </div><div class="not-covered"
style="width:48.507462686567166%;
float:left;"> 65 </div></td>
<td class="with-number">51.49 %</td>
<td class="with-number">272</td><td class="with-number">22</td><td class="with-number">134</td>
</tr>
<tr>
<td><a href="walkmap/svg.clj.html">walkmap.svg</a></td><td class="with-bar"><div class="covered"
style="width:2.8776978417266186%;
float:left;"> 4 </div><div class="not-covered"
style="width:97.12230215827338%;
float:left;"> 135 </div></td>
<td class="with-number">2.88 %</td>
style="width:4.21455938697318%;
float:left;"> 11 </div><div class="not-covered"
style="width:95.78544061302682%;
float:left;"> 250 </div></td>
<td class="with-number">4.21 %</td>
<td class="with-bar"><div class="covered"
style="width:8.571428571428571%;
float:left;"> 3 </div><div class="not-covered"
style="width:91.42857142857143%;
float:left;"> 32 </div></td>
<td class="with-number">8.57 %</td>
<td class="with-number">50</td><td class="with-number">2</td><td class="with-number">35</td>
style="width:12.121212121212121%;
float:left;"> 8 </div><div class="not-covered"
style="width:87.87878787878788%;
float:left;"> 58 </div></td>
<td class="with-number">12.12 %</td>
<td class="with-number">110</td><td class="with-number">7</td><td class="with-number">66</td>
</tr>
<tr>
<td><a href="walkmap/tag.clj.html">walkmap.tag</a></td><td class="with-bar"><div class="covered"
style="width:100.0%;
float:left;"> 159 </div></td>
<td class="with-number">100.00 %</td>
<td class="with-bar"><div class="covered"
style="width:100.0%;
float:left;"> 34 </div></td>
<td class="with-number">100.00 %</td>
<td class="with-number">68</td><td class="with-number">8</td><td class="with-number">34</td>
</tr>
<tr>
<td><a href="walkmap/utils.clj.html">walkmap.utils</a></td><td class="with-bar"><div class="covered"
style="width:96.31043256997455%;
float:left;"> 757 </div><div class="not-covered"
style="width:3.6895674300254453%;
float:left;"> 29 </div></td>
<td class="with-number">96.31 %</td>
<td class="with-bar"><div class="covered"
style="width:80.43478260869566%;
float:left;"> 37 </div><div class="partial"
style="width:2.1739130434782608%;
float:left;"> 1 </div><div class="not-covered"
style="width:17.391304347826086%;
float:left;"> 8 </div></td>
<td class="with-number">82.61 %</td>
<td class="with-number">119</td><td class="with-number">10</td><td class="with-number">46</td>
</tr>
<tr>
<td><a href="walkmap/vertex.clj.html">walkmap.vertex</a></td><td class="with-bar"><div class="covered"
style="width:72.94117647058823%;
float:left;"> 62 </div><div class="not-covered"
style="width:27.058823529411764%;
float:left;"> 23 </div></td>
<td class="with-number">72.94 %</td>
style="width:89.45454545454545%;
float:left;"> 492 </div><div class="not-covered"
style="width:10.545454545454545%;
float:left;"> 58 </div></td>
<td class="with-number">89.45 %</td>
<td class="with-bar"><div class="covered"
style="width:63.63636363636363%;
float:left;"> 14 </div><div class="partial"
style="width:13.636363636363637%;
float:left;"> 3 </div><div class="not-covered"
style="width:22.727272727272727%;
float:left;"> 5 </div></td>
<td class="with-number">77.27 %</td>
<td class="with-number">43</td><td class="with-number">5</td><td class="with-number">22</td>
style="width:83.78378378378379%;
float:left;"> 62 </div><div class="partial"
style="width:13.513513513513514%;
float:left;"> 10 </div><div class="not-covered"
style="width:2.7027027027027026%;
float:left;"> 2 </div></td>
<td class="with-number">97.30 %</td>
<td class="with-number">151</td><td class="with-number">15</td><td class="with-number">74</td>
</tr>
<tr><td>Totals:</td>
<td class="with-bar"></td>
<td class="with-number">27.77 %</td>
<td class="with-number">62.51 %</td>
<td class="with-bar"></td>
<td class="with-number">39.45 %</td>
<td class="with-number">59.55 %</td>
</tr>
</table>
</body>

View file

@ -8,10 +8,10 @@
001&nbsp;&nbsp;(ns&nbsp;walkmap.core
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;At&nbsp;this&nbsp;stage,&nbsp;primarily&nbsp;utility&nbsp;functions&nbsp;dealing&nbsp;with&nbsp;stereolithography
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;This&nbsp;namespace&nbsp;mostly&nbsp;gets&nbsp;used&nbsp;as&nbsp;a&nbsp;scratchpad&nbsp;for&nbsp;ideas&nbsp;which&nbsp;haven&#x27;t&nbsp;yet
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;(STL)&nbsp;files.&nbsp;Not&nbsp;a&nbsp;stable&nbsp;API&nbsp;yet!&quot;
003&nbsp;&nbsp;&nbsp;&nbsp;solidified.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.java.io&nbsp;:as&nbsp;io&nbsp;:refer&nbsp;[file&nbsp;output-stream&nbsp;input-stream]]
@ -26,115 +26,10 @@
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[me.raynes.fs&nbsp;:as&nbsp;fs]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l&nbsp;:refer&nbsp;[info&nbsp;error&nbsp;spy]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.stl&nbsp;:refer&nbsp;[decode-binary-stl]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.svg&nbsp;:refer&nbsp;[stl-&gt;svg]]))
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l&nbsp;:refer&nbsp;[info&nbsp;error&nbsp;spy]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
011&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
012&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*sea-level*
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;sea&nbsp;level&nbsp;on&nbsp;heightmaps&nbsp;we&#x27;re&nbsp;currently&nbsp;handling.&nbsp;If&nbsp;characters&nbsp;are&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;be&nbsp;able&nbsp;to&nbsp;swin&nbsp;in&nbsp;the&nbsp;sea,&nbsp;we&nbsp;must&nbsp;model&nbsp;the&nbsp;sea&nbsp;bottom,&nbsp;so&nbsp;we&nbsp;need
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;heightmaps&nbsp;which&nbsp;cover&nbsp;at&nbsp;least&nbsp;the&nbsp;continental&nbsp;shelf.&nbsp;However,&nbsp;the&nbsp;sea
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;bottom&nbsp;is&nbsp;not&nbsp;walkable&nbsp;territory&nbsp;and&nbsp;can&nbsp;be&nbsp;culled&nbsp;from&nbsp;walkmaps.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
017&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;**Note**&nbsp;must&nbsp;be&nbsp;a&nbsp;floating&nbsp;point&nbsp;number.&nbsp;`(=&nbsp;0&nbsp;0.0)`&nbsp;returns&nbsp;`false`!&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;0.0)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
020&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
021&nbsp;&nbsp;(defn&nbsp;ocean?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;&quot;Of&nbsp;a&nbsp;`facet`,&nbsp;is&nbsp;the&nbsp;altitude&nbsp;of&nbsp;every&nbsp;vertice&nbsp;equal&nbsp;to&nbsp;`*sea-level*`?&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;[facet]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;(every?
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(=&nbsp;%&nbsp;*sea-level*)
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;:z&nbsp;(:vertices&nbsp;facet))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
027&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
028&nbsp;&nbsp;(defn&nbsp;cull-ocean-facets
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&quot;Ye&nbsp;cannae&nbsp;walk&nbsp;on&nbsp;water.&nbsp;Remove&nbsp;all&nbsp;facets&nbsp;from&nbsp;this&nbsp;`stl`&nbsp;structure&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;are&nbsp;at&nbsp;sea&nbsp;level.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;[stl]
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;stl&nbsp;:facets&nbsp;(remove&nbsp;ocean?&nbsp;(:facets&nbsp;stl))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
033&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
034&nbsp;&nbsp;(defn&nbsp;binary-stl-file-&gt;svg
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&quot;Given&nbsp;only&nbsp;an&nbsp;`in-filename`,&nbsp;parse&nbsp;the&nbsp;indicated&nbsp;file,&nbsp;expected&nbsp;to&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;binary&nbsp;STL,&nbsp;and&nbsp;return&nbsp;an&nbsp;equivalent&nbsp;SVG&nbsp;structure.&nbsp;Given&nbsp;both&nbsp;`in-filename`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;and&nbsp;`out-filename`,&nbsp;as&nbsp;side-effect&nbsp;write&nbsp;the&nbsp;SVG&nbsp;to&nbsp;the&nbsp;indicated&nbsp;output&nbsp;file.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;([in-filename]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(stl-&gt;svg&nbsp;(cull-ocean-facets&nbsp;(decode-binary-stl&nbsp;in-filename))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;([in-filename&nbsp;out-filename]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[s&nbsp;(binary-stl-file-&gt;svg&nbsp;in-filename)]
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(spit&nbsp;out-filename&nbsp;(html&nbsp;s))
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
044&nbsp;&nbsp;
009&nbsp;&nbsp;
</span><br/>
</body>
</html>

View file

@ -20,235 +20,520 @@
005&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.math.numeric-tower&nbsp;:as&nbsp;m]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.path&nbsp;:refer&nbsp;[path?&nbsp;polygon-&gt;path]]
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.utils&nbsp;:as&nbsp;u]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.polygon&nbsp;:refer&nbsp;[polygon?]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:refer&nbsp;[ensure3d&nbsp;vertex?]]))
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:refer&nbsp;[canonicalise&nbsp;check-vertex&nbsp;ensure2d&nbsp;ensure3d&nbsp;vertex&nbsp;vertex=&nbsp;vertex?]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
009&nbsp;&nbsp;
008&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
010&nbsp;&nbsp;(defn&nbsp;edge?
009&nbsp;&nbsp;(defn&nbsp;edge
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;satisfies&nbsp;the&nbsp;conditions&nbsp;for&nbsp;a&nbsp;path.&nbsp;A&nbsp;path&nbsp;shall&nbsp;be&nbsp;a&nbsp;map
010&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;an&nbsp;edge&nbsp;between&nbsp;vertices&nbsp;`v1`&nbsp;and&nbsp;`v2`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;having&nbsp;the&nbsp;keys&nbsp;`:start`&nbsp;and&nbsp;`:end`,&nbsp;such&nbsp;that&nbsp;the&nbsp;values&nbsp;of&nbsp;each&nbsp;of&nbsp;those
011&nbsp;&nbsp;&nbsp;&nbsp;[v1&nbsp;v2]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;keys&nbsp;shall&nbsp;be&nbsp;a&nbsp;vertex.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="partial" title="8 out of 9 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;o)
<span class="covered" title="6 out of 6 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;{:kind&nbsp;:edge
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex?&nbsp;(:start&nbsp;o))
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:walkmap.id&#x2F;id&nbsp;(keyword&nbsp;(gensym&nbsp;&quot;edge&quot;))
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex?&nbsp;(:end&nbsp;o))))
<span class="covered" title="16 out of 16 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:start&nbsp;(check-vertex&nbsp;v1)
</span><br/>
<span class="covered" title="16 out of 16 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:end&nbsp;(check-vertex&nbsp;v2)})
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
019&nbsp;&nbsp;
016&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
020&nbsp;&nbsp;(defn&nbsp;path-&gt;edges
017&nbsp;&nbsp;(defn&nbsp;edge?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&quot;if&nbsp;`o`&nbsp;is&nbsp;a&nbsp;path,&nbsp;a&nbsp;polygon,&nbsp;or&nbsp;a&nbsp;sequence&nbsp;of&nbsp;vertices,&nbsp;return&nbsp;a&nbsp;sequence&nbsp;of
018&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;satisfies&nbsp;the&nbsp;conditions&nbsp;for&nbsp;a&nbsp;edge.&nbsp;An&nbsp;edge&nbsp;shall&nbsp;be&nbsp;a&nbsp;map
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;edges&nbsp;representing&nbsp;that&nbsp;path,&nbsp;polygon&nbsp;or&nbsp;sequence.&quot;
019&nbsp;&nbsp;&nbsp;&nbsp;having&nbsp;the&nbsp;keys&nbsp;`:start`&nbsp;and&nbsp;`:end`,&nbsp;such&nbsp;that&nbsp;the&nbsp;values&nbsp;of&nbsp;each&nbsp;of&nbsp;those
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;[o]
020&nbsp;&nbsp;&nbsp;&nbsp;keys&nbsp;shall&nbsp;be&nbsp;a&nbsp;vertex.&quot;
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;(cond
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(seq?&nbsp;o)
<span class="covered" title="9 out of 9 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when
<span class="covered" title="3 out of 3 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;o)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
<span class="covered" title="5 out of 5 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex?&nbsp;(:start&nbsp;o))
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex?&nbsp;(first&nbsp;o))
<span class="covered" title="4 out of 4 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex?&nbsp;(:end&nbsp;o))))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex?&nbsp;(first&nbsp;(rest&nbsp;o))))
<span class="blank" title="0 out of 0 forms covered">
026&nbsp;&nbsp;
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons
<span class="covered" title="1 out of 1 forms covered">
027&nbsp;&nbsp;(defn&nbsp;length
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:start&nbsp;(first&nbsp;o)
<span class="not-tracked" title="0 out of 0 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;length&nbsp;of&nbsp;the&nbsp;edge&nbsp;`e`.&quot;
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:end&nbsp;(first&nbsp;(rest&nbsp;o))}
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;[e]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(path-&gt;edges&nbsp;(rest&nbsp;o))))
<span class="covered" title="6 out of 6 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[start&nbsp;(ensure3d&nbsp;(:start&nbsp;e))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(path?&nbsp;o)
<span class="covered" title="5 out of 5 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;(ensure3d&nbsp;(:end&nbsp;e))]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(path-&gt;edges&nbsp;(:nodes&nbsp;o))
<span class="covered" title="2 out of 2 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(m&#x2F;sqrt
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(polygon?&nbsp;o)
<span class="covered" title="2 out of 2 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(path-&gt;edges&nbsp;(polygon-&gt;path&nbsp;o))))
<span class="covered" title="1 out of 1 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="covered" title="11 out of 11 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(m&#x2F;expt&nbsp;(-&nbsp;(%&nbsp;end)&nbsp;(%&nbsp;start))&nbsp;2)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:x&nbsp;:y&nbsp;:z])))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
038&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
039&nbsp;&nbsp;(defn&nbsp;length
039&nbsp;&nbsp;(defn&nbsp;centre
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;length&nbsp;of&nbsp;the&nbsp;edge&nbsp;`e`.&quot;
040&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;vertex&nbsp;that&nbsp;represents&nbsp;the&nbsp;centre&nbsp;of&nbsp;this&nbsp;`edge`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;[e]
041&nbsp;&nbsp;&nbsp;&nbsp;[edge]
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[start&nbsp;(ensure3d&nbsp;(:start&nbsp;e))
042&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[s&nbsp;(ensure3d&nbsp;(:start&nbsp;edge))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;(ensure3d&nbsp;(:end&nbsp;e))]
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e&nbsp;(ensure3d&nbsp;(:end&nbsp;edge))]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(m&#x2F;sqrt
044&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex
</span><br/>
<span class="covered" title="16 out of 16 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+&nbsp;(:x&nbsp;s)&nbsp;(&#x2F;&nbsp;(-&nbsp;(:x&nbsp;e)&nbsp;(:x&nbsp;s))&nbsp;2))
</span><br/>
<span class="covered" title="16 out of 16 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+&nbsp;(:y&nbsp;s)&nbsp;(&#x2F;&nbsp;(-&nbsp;(:y&nbsp;e)&nbsp;(:y&nbsp;s))&nbsp;2))
</span><br/>
<span class="covered" title="16 out of 16 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+&nbsp;(:z&nbsp;s)&nbsp;(&#x2F;&nbsp;(-&nbsp;(:z&nbsp;e)&nbsp;(:z&nbsp;s))&nbsp;2)))))
</span><br/>
<span class="blank" title="4 out of 4 forms covered">
048&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
049&nbsp;&nbsp;(defn&nbsp;unit-vector
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;an&nbsp;vertex&nbsp;parallel&nbsp;to&nbsp;`e`&nbsp;starting&nbsp;from&nbsp;the&nbsp;coordinate&nbsp;origin.&nbsp;Two
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="covered" title="11 out of 11 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(m&#x2F;expt&nbsp;(-&nbsp;(%&nbsp;end)&nbsp;(%&nbsp;start))&nbsp;2)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:x&nbsp;:y&nbsp;:z])))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
050&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
051&nbsp;&nbsp;(defn&nbsp;unit-vector
051&nbsp;&nbsp;&nbsp;&nbsp;edges&nbsp;which&nbsp;are&nbsp;parallel&nbsp;will&nbsp;have&nbsp;the&nbsp;same&nbsp;unit&nbsp;vector.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;an&nbsp;vertex&nbsp;parallel&nbsp;to&nbsp;`e`&nbsp;starting&nbsp;from&nbsp;the&nbsp;coordinate&nbsp;origin.&nbsp;Two
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;edges&nbsp;which&nbsp;are&nbsp;parallel&nbsp;will&nbsp;have&nbsp;the&nbsp;same&nbsp;unit&nbsp;vector.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;[e]
052&nbsp;&nbsp;&nbsp;&nbsp;[e]
</span><br/>
<span class="covered" title="14 out of 14 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[e&#x27;&nbsp;{:start&nbsp;(ensure3d&nbsp;(:start&nbsp;e))&nbsp;:end&nbsp;(ensure3d&nbsp;(:end&nbsp;e))}
053&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[e&#x27;&nbsp;{:start&nbsp;(ensure3d&nbsp;(:start&nbsp;e))&nbsp;:end&nbsp;(ensure3d&nbsp;(:end&nbsp;e))}
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;l&nbsp;(length&nbsp;e&#x27;)]
054&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;l&nbsp;(length&nbsp;e&#x27;)]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;merge
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{}
055&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(canonicalise
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
056&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[k]
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;merge
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{}
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[k]
</span><br/>
<span class="covered" title="17 out of 17 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{k&nbsp;(&#x2F;&nbsp;(-&nbsp;(k&nbsp;(:end&nbsp;e&#x27;))&nbsp;(k&nbsp;(:start&nbsp;e&#x27;)))&nbsp;l)})
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{k&nbsp;(&#x2F;&nbsp;(-&nbsp;(k&nbsp;(:end&nbsp;e&#x27;))&nbsp;(k&nbsp;(:start&nbsp;e&#x27;)))&nbsp;l)})
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:x&nbsp;:y&nbsp;:z]))))
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:x&nbsp;:y&nbsp;:z])))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
064&nbsp;&nbsp;
063&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
065&nbsp;&nbsp;(defn&nbsp;parallel?
064&nbsp;&nbsp;(defn&nbsp;parallel?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;all&nbsp;`edges`&nbsp;passed&nbsp;are&nbsp;parallel&nbsp;with&nbsp;one&nbsp;another.&quot;
065&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;all&nbsp;`edges`&nbsp;passed&nbsp;are&nbsp;parallel&nbsp;with&nbsp;one&nbsp;another.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;TODO:&nbsp;this&nbsp;bears&nbsp;being&nbsp;wary&nbsp;about,&nbsp;dealing&nbsp;with&nbsp;floating&nbsp;point&nbsp;arithmetic.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;Keep&nbsp;an&nbsp;eye&nbsp;out&nbsp;for&nbsp;spurious&nbsp;errors.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;[&amp;&nbsp;edges]
066&nbsp;&nbsp;&nbsp;&nbsp;[&amp;&nbsp;edges]
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[uvs&nbsp;(map&nbsp;unit-vector&nbsp;edges)]
067&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[uvs&nbsp;(map&nbsp;unit-vector&nbsp;edges)]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(=&nbsp;%&nbsp;(first&nbsp;uvs))
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(vertex=&nbsp;%&nbsp;(first&nbsp;uvs))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(rest&nbsp;uvs))))
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(rest&nbsp;uvs))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
074&nbsp;&nbsp;
071&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
075&nbsp;&nbsp;(defn&nbsp;collinear?
072&nbsp;&nbsp;(defn&nbsp;collinear?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;edges&nbsp;`e1`&nbsp;and&nbsp;`e2`&nbsp;are&nbsp;collinear&nbsp;with&nbsp;one&nbsp;another.&quot;
073&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;edges&nbsp;`e1`&nbsp;and&nbsp;`e2`&nbsp;are&nbsp;collinear&nbsp;with&nbsp;one&nbsp;another.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;[e1&nbsp;e2]
074&nbsp;&nbsp;&nbsp;&nbsp;[e1&nbsp;e2]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;(parallel?
075&nbsp;&nbsp;&nbsp;&nbsp;(parallel?
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e1
076&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e1
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e2
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e2
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:start&nbsp;(:start&nbsp;e1)&nbsp;:end&nbsp;(:start&nbsp;e2)}))
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(vertex=&nbsp;(:start&nbsp;e1)&nbsp;(:start&nbsp;e2))
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:start&nbsp;(:start&nbsp;e1)&nbsp;:end&nbsp;(:end&nbsp;e2)}
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:start&nbsp;(:start&nbsp;e1)&nbsp;:end&nbsp;(:start&nbsp;e2)})))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
082&nbsp;&nbsp;
081&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
082&nbsp;&nbsp;(defn&nbsp;collinear2d?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;the&nbsp;projections&nbsp;of&nbsp;edges&nbsp;`e1`,&nbsp;`e2`&nbsp;onto&nbsp;the&nbsp;x,&nbsp;y&nbsp;plane&nbsp;are
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;collinear.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;[e1&nbsp;e2]
</span><br/>
<span class="covered" title="15 out of 15 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;(collinear?&nbsp;{:start&nbsp;(ensure2d&nbsp;(:start&nbsp;e1))&nbsp;:end&nbsp;(ensure2d&nbsp;(:end&nbsp;e1))}
</span><br/>
<span class="covered" title="13 out of 13 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:start&nbsp;(ensure2d&nbsp;(:start&nbsp;e2))&nbsp;:end&nbsp;(ensure2d&nbsp;(:end&nbsp;e2))}))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
088&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
089&nbsp;&nbsp;(defn&nbsp;minimaxd
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&quot;Apply&nbsp;function&nbsp;`f`&nbsp;to&nbsp;`coord`&nbsp;of&nbsp;the&nbsp;vertices&nbsp;at&nbsp;start&nbsp;and&nbsp;end&nbsp;of&nbsp;`edge`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;and&nbsp;return&nbsp;the&nbsp;result.&nbsp;Intended&nbsp;use&nbsp;case&nbsp;is&nbsp;`f`&nbsp;=&nbsp;`min`&nbsp;or&nbsp;`max`,&nbsp;`coord`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;is&nbsp;`:x`,&nbsp;`:y`&nbsp;or&nbsp;`:z`.&nbsp;No&nbsp;checks&nbsp;are&nbsp;made&nbsp;for&nbsp;sane&nbsp;arguments.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;[edge&nbsp;coord&nbsp;f]
</span><br/>
<span class="covered" title="15 out of 15 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;f&nbsp;(list&nbsp;(coord&nbsp;(:start&nbsp;edge))&nbsp;(coord&nbsp;(:end&nbsp;edge)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
095&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
096&nbsp;&nbsp;(defn&nbsp;on?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;the&nbsp;vertex&nbsp;`v`&nbsp;is&nbsp;on&nbsp;the&nbsp;edge&nbsp;`e`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;[e&nbsp;v]
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[p&nbsp;(ensure3d&nbsp;(:start&nbsp;e))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;q&nbsp;(ensure3d&nbsp;v)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;(ensure3d&nbsp;(:end&nbsp;e))]
</span><br/>
<span class="partial" title="20 out of 25 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(collinear?&nbsp;(edge&nbsp;p&nbsp;q)&nbsp;(edge&nbsp;q&nbsp;r))
</span><br/>
<span class="covered" title="13 out of 13 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;=&nbsp;(:x&nbsp;q)&nbsp;(max&nbsp;(:x&nbsp;p)&nbsp;(:x&nbsp;r)))
</span><br/>
<span class="covered" title="13 out of 13 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(:x&nbsp;q)&nbsp;(min&nbsp;(:x&nbsp;p)&nbsp;(:x&nbsp;r)))
</span><br/>
<span class="covered" title="13 out of 13 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;=&nbsp;(:y&nbsp;q)&nbsp;(max&nbsp;(:y&nbsp;p)&nbsp;(:y&nbsp;r)))
</span><br/>
<span class="covered" title="13 out of 13 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(:y&nbsp;q)&nbsp;(min&nbsp;(:y&nbsp;p)&nbsp;(:y&nbsp;r)))
</span><br/>
<span class="covered" title="13 out of 13 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;=&nbsp;(:z&nbsp;q)&nbsp;(max&nbsp;(:z&nbsp;p)&nbsp;(:z&nbsp;r)))
</span><br/>
<span class="covered" title="12 out of 12 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(:z&nbsp;q)&nbsp;(min&nbsp;(:z&nbsp;p)&nbsp;(:z&nbsp;r))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
110&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
111&nbsp;&nbsp;(defn&nbsp;on2d?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;vertex&nbsp;`v`&nbsp;is&nbsp;on&nbsp;edge&nbsp;`e`&nbsp;when&nbsp;projected&nbsp;onto&nbsp;the&nbsp;x,&nbsp;y&nbsp;plane.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;[e&nbsp;v]
</span><br/>
<span class="covered" title="15 out of 15 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;(on?&nbsp;(edge&nbsp;(ensure2d&nbsp;(:start&nbsp;e))&nbsp;(ensure2d&nbsp;(:end&nbsp;e)))&nbsp;v))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
115&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
116&nbsp;&nbsp;(defn&nbsp;overlaps2d?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;the&nbsp;recangle&nbsp;in&nbsp;the&nbsp;x,y&nbsp;plane&nbsp;bisected&nbsp;by&nbsp;edge&nbsp;`e1`&nbsp;overlaps&nbsp;that
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;bisected&nbsp;by&nbsp;edge&nbsp;`e2`.&nbsp;It&nbsp;is&nbsp;an&nbsp;error&nbsp;if&nbsp;either&nbsp;`e1`&nbsp;or&nbsp;`e2`&nbsp;is&nbsp;not&nbsp;an&nbsp;edge.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;[e1&nbsp;e2]
</span><br/>
<span class="partial" title="11 out of 12 forms covered">
120&nbsp;&nbsp;&nbsp;&nbsp;(when&nbsp;(and&nbsp;(edge?&nbsp;e1)&nbsp;(edge?&nbsp;e2))
</span><br/>
<span class="partial" title="11 out of 13 forms covered">
121&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="12 out of 12 forms covered">
122&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(minimaxd&nbsp;e1&nbsp;:x&nbsp;max)&nbsp;(minimaxd&nbsp;e2&nbsp;:x&nbsp;min))
</span><br/>
<span class="covered" title="12 out of 12 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(minimaxd&nbsp;e1&nbsp;:x&nbsp;min)&nbsp;(minimaxd&nbsp;e2&nbsp;:x&nbsp;max))
</span><br/>
<span class="covered" title="12 out of 12 forms covered">
124&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(minimaxd&nbsp;e1&nbsp;:y&nbsp;max)&nbsp;(minimaxd&nbsp;e2&nbsp;:y&nbsp;min))
</span><br/>
<span class="covered" title="11 out of 11 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(minimaxd&nbsp;e1&nbsp;:y&nbsp;min)&nbsp;(minimaxd&nbsp;e2&nbsp;:y&nbsp;max)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
126&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
127&nbsp;&nbsp;(defn&nbsp;intersection2d
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
128&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;probability&nbsp;of&nbsp;two&nbsp;lines&nbsp;intersecting&nbsp;in&nbsp;3d&nbsp;space&nbsp;is&nbsp;low,&nbsp;and&nbsp;actually
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;that&nbsp;is&nbsp;mostly&nbsp;not&nbsp;something&nbsp;we&#x27;re&nbsp;interested&nbsp;in.&nbsp;We&#x27;re&nbsp;interested&nbsp;in
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
130&nbsp;&nbsp;&nbsp;&nbsp;intersection&nbsp;in&nbsp;the&nbsp;`x,y`&nbsp;plane.&nbsp;This&nbsp;function&nbsp;returns&nbsp;a&nbsp;vertex&nbsp;representing
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
131&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;point&nbsp;vertically&nbsp;over&nbsp;the&nbsp;intersection&nbsp;of&nbsp;edges&nbsp;`e1`,&nbsp;`e2`&nbsp;in&nbsp;the&nbsp;`x,y`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;plane,&nbsp;whose&nbsp;`z`&nbsp;coordinate&nbsp;is
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
133&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;0&nbsp;if&nbsp;both&nbsp;edges&nbsp;are&nbsp;2d&nbsp;(i.e.&nbsp;have&nbsp;missing&nbsp;or&nbsp;zero&nbsp;`z`&nbsp;coordinates);
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
135&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;if&nbsp;one&nbsp;edge&nbsp;is&nbsp;2d,&nbsp;then&nbsp;the&nbsp;point&nbsp;on&nbsp;the&nbsp;other&nbsp;edge&nbsp;over&nbsp;the&nbsp;intersection;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
136&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;otherwise,&nbsp;the&nbsp;average&nbsp;of&nbsp;the&nbsp;z&nbsp;coordinates&nbsp;of&nbsp;the&nbsp;points&nbsp;on&nbsp;the&nbsp;two
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
137&nbsp;&nbsp;&nbsp;&nbsp;edges&nbsp;over&nbsp;the&nbsp;intersection.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
138&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
139&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;no&nbsp;such&nbsp;intersection&nbsp;exists,&nbsp;`nil`&nbsp;is&nbsp;returned.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
140&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
141&nbsp;&nbsp;&nbsp;&nbsp;It&nbsp;is&nbsp;an&nbsp;error,&nbsp;and&nbsp;an&nbsp;exception&nbsp;will&nbsp;be&nbsp;thrown,&nbsp;if&nbsp;either&nbsp;`e1`&nbsp;or&nbsp;`e2`&nbsp;is
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
142&nbsp;&nbsp;&nbsp;&nbsp;not&nbsp;an&nbsp;edge.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
143&nbsp;&nbsp;&nbsp;&nbsp;[e1&nbsp;e2]
</span><br/>
<span class="covered" title="11 out of 11 forms covered">
144&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(and&nbsp;(edge?&nbsp;e1)&nbsp;(edge?&nbsp;e2))
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
146&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(overlaps2d?&nbsp;e1&nbsp;e2)&nbsp;;;&nbsp;relatively&nbsp;cheap&nbsp;check
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
147&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
148&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(collinear2d?&nbsp;e1&nbsp;e2)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;any&nbsp;point&nbsp;within&nbsp;the&nbsp;overlap&nbsp;will&nbsp;do,&nbsp;but&nbsp;we&#x27;ll&nbsp;pick&nbsp;the&nbsp;end&nbsp;of&nbsp;e1
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;which&nbsp;is&nbsp;on&nbsp;e2
</span><br/>
<span class="partial" title="10 out of 13 forms covered">
151&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(on2d?&nbsp;e2&nbsp;(:start&nbsp;e1))&nbsp;(:start&nbsp;e1)&nbsp;(:end&nbsp;e1))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
152&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;blatantly&nbsp;stolen&nbsp;from
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
153&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;https:&#x2F;&#x2F;gist.github.com&#x2F;cassiel&#x2F;3e725b49670356a9b936
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
154&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[x1&nbsp;(:x&nbsp;(:start&nbsp;e1))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
155&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x2&nbsp;(:x&nbsp;(:end&nbsp;e1))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
156&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x3&nbsp;(:x&nbsp;(:start&nbsp;e2))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
157&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x4&nbsp;(:x&nbsp;(:end&nbsp;e2))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
158&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y1&nbsp;(:y&nbsp;(:start&nbsp;e1))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
159&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y2&nbsp;(:y&nbsp;(:end&nbsp;e1))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
160&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y3&nbsp;(:y&nbsp;(:start&nbsp;e2))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
161&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y4&nbsp;(:y&nbsp;(:end&nbsp;e2))
</span><br/>
<span class="covered" title="12 out of 12 forms covered">
162&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;denom&nbsp;(-&nbsp;(*&nbsp;(-&nbsp;x1&nbsp;x2)&nbsp;(-&nbsp;y3&nbsp;y4))
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
163&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*&nbsp;(-&nbsp;y1&nbsp;y2)&nbsp;(-&nbsp;x3&nbsp;x4)))
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
164&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x1y2-y1x2&nbsp;(-&nbsp;(*&nbsp;x1&nbsp;y2)&nbsp;(*&nbsp;y1&nbsp;x2))
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
165&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x3y4-y3x4&nbsp;(-&nbsp;(*&nbsp;x3&nbsp;y4)&nbsp;(*&nbsp;y3&nbsp;x4))
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
166&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;px-num&nbsp;(-&nbsp;(*&nbsp;x1y2-y1x2&nbsp;(-&nbsp;x3&nbsp;x4))
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
167&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*&nbsp;(-&nbsp;x1&nbsp;x2)&nbsp;x3y4-y3x4))
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
168&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;py-num&nbsp;(-&nbsp;(*&nbsp;x1y2-y1x2&nbsp;(-&nbsp;y3&nbsp;y4))
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
169&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*&nbsp;(-&nbsp;y1&nbsp;y2)&nbsp;x3y4-y3x4))
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
170&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;(when-not&nbsp;(zero?&nbsp;denom)
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
171&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex&nbsp;(&#x2F;&nbsp;px-num&nbsp;denom)&nbsp;(&#x2F;&nbsp;py-num&nbsp;denom)))]
</span><br/>
<span class="partial" title="19 out of 20 forms covered">
172&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when&nbsp;(and&nbsp;result&nbsp;(on2d?&nbsp;e1&nbsp;result)&nbsp;(on2d?&nbsp;e2&nbsp;result))&nbsp;result))))
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
173&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
174&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
175&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;Both&nbsp;`e1`&nbsp;and&nbsp;`e2`&nbsp;must&nbsp;be&nbsp;edges.&quot;
</span><br/>
<span class="covered" title="16 out of 16 forms covered">
176&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;#(or&nbsp;(:kind&nbsp;%)&nbsp;(type&nbsp;%))&nbsp;[e1&nbsp;e2]))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
177&nbsp;&nbsp;
</span><br/>
</body>
</html>

View file

@ -11,70 +11,49 @@
002&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.math.combinatorics&nbsp;:as&nbsp;combo]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.math.numeric-tower&nbsp;:as&nbsp;m]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.edge&nbsp;:as&nbsp;e]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.path&nbsp;:refer&nbsp;[path?&nbsp;polygon-&gt;path]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.polygon&nbsp;:refer&nbsp;[polygon?]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:as&nbsp;v]))
003&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.math.numeric-tower&nbsp;:as&nbsp;m]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
008&nbsp;&nbsp;
004&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
009&nbsp;&nbsp;(defn&nbsp;on?
005&nbsp;&nbsp;(defn&nbsp;=ish
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;the&nbsp;vertex&nbsp;`v`&nbsp;is&nbsp;on&nbsp;the&nbsp;edge&nbsp;`e`.&quot;
006&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;numbers&nbsp;`n1`,&nbsp;`n2`&nbsp;are&nbsp;roughly&nbsp;equal;&nbsp;that&nbsp;is&nbsp;to&nbsp;say,&nbsp;equal&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;[e&nbsp;v]
007&nbsp;&nbsp;&nbsp;&nbsp;within&nbsp;`tolerance`&nbsp;(defaults&nbsp;to&nbsp;one&nbsp;part&nbsp;in&nbsp;a&nbsp;million).&quot;
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[p&nbsp;(v&#x2F;ensure3d&nbsp;(:start&nbsp;e))
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;([n1&nbsp;n2]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;q&nbsp;(v&#x2F;ensure3d&nbsp;v)
<span class="covered" title="11 out of 11 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(and&nbsp;(number?&nbsp;n1)&nbsp;(number?&nbsp;n2))
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;(v&#x2F;ensure3d&nbsp;(:end&nbsp;e))]
<span class="covered" title="7 out of 7 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[m&nbsp;(m&#x2F;abs&nbsp;(min&nbsp;n1&nbsp;n2))
</span><br/>
<span class="not-covered" title="0 out of 25 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
<span class="covered" title="9 out of 9 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t&nbsp;(if&nbsp;(zero?&nbsp;m)&nbsp;0.000001&nbsp;(*&nbsp;0.000001&nbsp;m))]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(e&#x2F;collinear?&nbsp;p&nbsp;q&nbsp;r)
<span class="covered" title="5 out of 5 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=ish&nbsp;n1&nbsp;n2&nbsp;t))
</span><br/>
<span class="not-covered" title="0 out of 13 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;=&nbsp;(:x&nbsp;q)&nbsp;(max&nbsp;(:x&nbsp;p)&nbsp;(:x&nbsp;r)))
<span class="covered" title="4 out of 4 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;n1&nbsp;n2)))
</span><br/>
<span class="not-covered" title="0 out of 13 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(:x&nbsp;q)&nbsp;(min&nbsp;(:x&nbsp;p)&nbsp;(:x&nbsp;r)))
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;([n1&nbsp;n2&nbsp;tolerance]
</span><br/>
<span class="not-covered" title="0 out of 13 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;=&nbsp;(:y&nbsp;q)&nbsp;(max&nbsp;(:y&nbsp;p)&nbsp;(:y&nbsp;r)))
<span class="covered" title="11 out of 11 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(and&nbsp;(number?&nbsp;n1)&nbsp;(number?&nbsp;n2))
</span><br/>
<span class="not-covered" title="0 out of 13 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(:y&nbsp;q)&nbsp;(min&nbsp;(:y&nbsp;p)&nbsp;(:y&nbsp;r)))
<span class="covered" title="9 out of 9 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(m&#x2F;abs&nbsp;(-&nbsp;n1&nbsp;n2))&nbsp;tolerance)
</span><br/>
<span class="not-covered" title="0 out of 13 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;=&nbsp;(:z&nbsp;q)&nbsp;(max&nbsp;(:z&nbsp;p)&nbsp;(:z&nbsp;r)))
</span><br/>
<span class="not-covered" title="0 out of 12 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(:z&nbsp;q)&nbsp;(min&nbsp;(:z&nbsp;p)&nbsp;(:z&nbsp;r))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
023&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
024&nbsp;&nbsp;
<span class="covered" title="4 out of 4 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;n1&nbsp;n2))))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,32 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> walkmap/id.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;walkmap.id
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;namespace&nbsp;within&nbsp;which&nbsp;the&nbsp;privileged&nbsp;keyword&nbsp;`:walkmap.id&#x2F;id`&nbsp;is&nbsp;defined.&quot;)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
003&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
004&nbsp;&nbsp;(def&nbsp;^:const&nbsp;id
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;magic&nbsp;id&nbsp;key&nbsp;walkmap&nbsp;uses,&nbsp;to&nbsp;distinguish&nbsp;it&nbsp;from&nbsp;all&nbsp;other&nbsp;uses&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;unprotected&nbsp;keyword.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;::id)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
008&nbsp;&nbsp;
</span><br/>
</body>
</html>

View file

@ -0,0 +1,233 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> walkmap/microworld.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;walkmap.microworld
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;An&nbsp;interface&nbsp;between&nbsp;walkmap&nbsp;and&nbsp;microworld,&nbsp;to&nbsp;allow&nbsp;use&nbsp;of&nbsp;microworld
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;functionality&nbsp;to&nbsp;model&nbsp;things&nbsp;like&nbsp;rainfall,&nbsp;soil&nbsp;fertility,&nbsp;settlement
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;and&nbsp;so&nbsp;on.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.edn&nbsp;:as&nbsp;edn&nbsp;:only&nbsp;[read]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.java.io&nbsp;:as&nbsp;io]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.string&nbsp;:as&nbsp;s]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.edge&nbsp;:as&nbsp;e]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.polygon&nbsp;:as&nbsp;p&nbsp;:only&nbsp;[rectangle]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.superstructure&nbsp;:refer&nbsp;[store]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.tag&nbsp;:as&nbsp;t&nbsp;:only&nbsp;[tag]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:as&nbsp;v&nbsp;:only&nbsp;[check-vertex&nbsp;vertex&nbsp;vertex?]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.utils&nbsp;:as&nbsp;u&nbsp;:only&nbsp;[truncate]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
015&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
016&nbsp;&nbsp;(defn&nbsp;cell-&gt;polygon
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;&quot;From&nbsp;this&nbsp;MicroWorld&nbsp;`cell`,&nbsp;construct&nbsp;a&nbsp;walkmap&nbsp;polygon&nbsp;(specifically,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;rectangle.&nbsp;If&nbsp;`scale-vector`&nbsp;passed&nbsp;and&nbsp;is&nbsp;a&nbsp;vertex,&nbsp;scale&nbsp;all&nbsp;the&nbsp;vertices
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;in&nbsp;the&nbsp;cell&nbsp;by&nbsp;that&nbsp;vector.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;([cell]
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cell-&gt;polygon&nbsp;cell&nbsp;(v&#x2F;vertex&nbsp;1&nbsp;1&nbsp;1)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;([cell&nbsp;scale-vector]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(t&#x2F;tag
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell
</span><br/>
<span class="not-covered" title="0 out of 24 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[w&nbsp;(*&nbsp;(:x&nbsp;cell)&nbsp;(:x&nbsp;(v&#x2F;check-vertex&nbsp;scale-vector)))
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;(*&nbsp;(:y&nbsp;cell)&nbsp;(:y&nbsp;scale-vector))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e&nbsp;(+&nbsp;w&nbsp;(:x&nbsp;scale-vector))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n&nbsp;(+&nbsp;s&nbsp;(:y&nbsp;scale-vector))
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z&nbsp;(*&nbsp;(:altitude&nbsp;cell)&nbsp;(:z&nbsp;scale-vector))]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(p&#x2F;rectangle
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(v&#x2F;vertex&nbsp;s&nbsp;w&nbsp;z)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(v&#x2F;vertex&nbsp;n&nbsp;e&nbsp;z))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:walkmap.id&#x2F;id
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(keyword&nbsp;(gensym&nbsp;&quot;mw-cell&quot;)))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:state&nbsp;cell))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
038&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
039&nbsp;&nbsp;(defn&nbsp;load-microworld-edn
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;&quot;While&nbsp;it&nbsp;would&nbsp;be&nbsp;possible&nbsp;to&nbsp;call&nbsp;MicroWorld&nbsp;functions&nbsp;directly&nbsp;from
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;Walkmap,&nbsp;the&nbsp;fact&nbsp;is&nbsp;that&nbsp;running&nbsp;MicroWorld&nbsp;is&nbsp;so&nbsp;phenomenally
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;compute-heavy&nbsp;that&nbsp;it&#x27;s&nbsp;much&nbsp;more&nbsp;sensible&nbsp;to&nbsp;do&nbsp;it&nbsp;in&nbsp;batch&nbsp;mode.&nbsp;So&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;better&nbsp;plan&nbsp;is&nbsp;to&nbsp;be&nbsp;able&nbsp;to&nbsp;pull&nbsp;the&nbsp;output&nbsp;from&nbsp;MicroWorld&nbsp;-&nbsp;as&nbsp;an&nbsp;EDN
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;structure&nbsp;-&nbsp;into&nbsp;a&nbsp;walkmap&nbsp;superstructure.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;([filename]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(load-microworld-edn&nbsp;filename&nbsp;:mw))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;([filename&nbsp;map-kind]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when-not
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(keyword?&nbsp;map-kind)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(u&#x2F;truncate
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Must&nbsp;be&nbsp;a&nbsp;keyword:&nbsp;&quot;&nbsp;(or&nbsp;map-kind&nbsp;&quot;nil&quot;))&nbsp;80))))
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(load-microworld-edn&nbsp;filename&nbsp;map-kind&nbsp;nil))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;([filename&nbsp;mapkind&nbsp;superstucture]
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(load-microworld-edn&nbsp;filename&nbsp;mapkind&nbsp;superstucture&nbsp;(v&#x2F;vertex&nbsp;1&nbsp;1&nbsp;1)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;([filename&nbsp;map-kind&nbsp;superstructure&nbsp;scale-vertex]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[mw&nbsp;(try
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(with-open&nbsp;[r&nbsp;(io&#x2F;reader&nbsp;filename)]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(edn&#x2F;read&nbsp;(java.io.PushbackReader.&nbsp;r)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;RuntimeException&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 15 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;error&nbsp;&quot;Error&nbsp;parsing&nbsp;edn&nbsp;file&nbsp;&#x27;%s&#x27;:&nbsp;%s\n&quot;
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filename&nbsp;(.getMessage&nbsp;e))))
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;polys&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;concat
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;(fn&nbsp;[row]&nbsp;(map&nbsp;cell-&gt;polygon&nbsp;row))&nbsp;mw))]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(map?&nbsp;superstructure)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(store&nbsp;%2&nbsp;%1)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;superstructure
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;polys)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;polys))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
072&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
073&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
074&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
075&nbsp;&nbsp;
</span><br/>
</body>
</html>

View file

@ -0,0 +1,83 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> walkmap/ocean.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;walkmap.ocean
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Deal&nbsp;with&nbsp;(specifically,&nbsp;at&nbsp;this&nbsp;stage,&nbsp;cull)&nbsp;ocean&nbsp;areas&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[walkmap.utils&nbsp;:refer&nbsp;[=ish]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
004&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
005&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*sea-level*
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;sea&nbsp;level&nbsp;on&nbsp;heightmaps&nbsp;we&#x27;re&nbsp;currently&nbsp;handling.&nbsp;If&nbsp;characters&nbsp;are&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;be&nbsp;able&nbsp;to&nbsp;swin&nbsp;in&nbsp;the&nbsp;sea,&nbsp;we&nbsp;must&nbsp;model&nbsp;the&nbsp;sea&nbsp;bottom,&nbsp;so&nbsp;we&nbsp;need
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;heightmaps&nbsp;which&nbsp;cover&nbsp;at&nbsp;least&nbsp;the&nbsp;continental&nbsp;shelf.&nbsp;However,&nbsp;the&nbsp;sea
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;bottom&nbsp;is&nbsp;not&nbsp;walkable&nbsp;territory&nbsp;and&nbsp;can&nbsp;be&nbsp;culled&nbsp;from&nbsp;walkmaps.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
010&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;**Note**&nbsp;must&nbsp;be&nbsp;a&nbsp;floating&nbsp;point&nbsp;number.&nbsp;`(=&nbsp;0&nbsp;0.0)`&nbsp;returns&nbsp;`false`!&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;0.0)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
013&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
014&nbsp;&nbsp;(defn&nbsp;ocean?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;&quot;Of&nbsp;a&nbsp;`facet`,&nbsp;is&nbsp;the&nbsp;altitude&nbsp;of&nbsp;every&nbsp;vertice&nbsp;equal&nbsp;to&nbsp;`*sea-level*`?&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;[facet]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;(every?
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(=ish&nbsp;%&nbsp;*sea-level*)
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;:z&nbsp;(:vertices&nbsp;facet))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
020&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
021&nbsp;&nbsp;(defn&nbsp;cull-ocean-facets
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;&quot;Ye&nbsp;cannae&nbsp;walk&nbsp;on&nbsp;water.&nbsp;Remove&nbsp;all&nbsp;facets&nbsp;from&nbsp;this&nbsp;`stl`&nbsp;structure&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;are&nbsp;at&nbsp;sea&nbsp;level.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;[stl]
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;stl&nbsp;:facets&nbsp;(remove&nbsp;ocean?&nbsp;(:facets&nbsp;stl))))
</span><br/>
</body>
</html>

View file

@ -8,91 +8,280 @@
001&nbsp;&nbsp;(ns&nbsp;walkmap.path
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Essentially&nbsp;the&nbsp;specification&nbsp;for&nbsp;things&nbsp;we&nbsp;shall&nbsp;consider&nbsp;to&nbsp;be&nbsp;path.&quot;
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Essentially&nbsp;the&nbsp;specification&nbsp;for&nbsp;things&nbsp;we&nbsp;shall&nbsp;consider&nbsp;to&nbsp;be&nbsp;path.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[walkmap.polygon&nbsp;:refer&nbsp;[polygon?]]
003&nbsp;&nbsp;&nbsp;&nbsp;**Note&nbsp;that**&nbsp;for&nbsp;these&nbsp;purposes&nbsp;`path`&nbsp;means&nbsp;any&nbsp;continuous&nbsp;linear
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:refer&nbsp;[vertex?]]))
004&nbsp;&nbsp;&nbsp;&nbsp;feature,&nbsp;where&nbsp;such&nbsp;features&nbsp;specifically&nbsp;include&nbsp;watercourses.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.string&nbsp;:as&nbsp;s]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.edge&nbsp;:as&nbsp;e]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.polygon&nbsp;:refer&nbsp;[check-polygon&nbsp;polygon?]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.tag&nbsp;:refer&nbsp;[tag&nbsp;tags]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.utils&nbsp;:refer&nbsp;[check-kind-type&nbsp;check-kind-type-seq&nbsp;kind-type]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:refer&nbsp;[check-vertices&nbsp;vertex?]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
005&nbsp;&nbsp;
011&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
006&nbsp;&nbsp;(defn&nbsp;path?
012&nbsp;&nbsp;(defn&nbsp;path?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;satisfies&nbsp;the&nbsp;conditions&nbsp;for&nbsp;a&nbsp;path.&nbsp;A&nbsp;path&nbsp;shall&nbsp;be&nbsp;a&nbsp;map
013&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;satisfies&nbsp;the&nbsp;conditions&nbsp;for&nbsp;a&nbsp;path.&nbsp;A&nbsp;path&nbsp;shall&nbsp;be&nbsp;a&nbsp;map
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;having&nbsp;the&nbsp;key&nbsp;`:nodes`,&nbsp;whose&nbsp;value&nbsp;shall&nbsp;be&nbsp;a&nbsp;sequence&nbsp;of&nbsp;vertices&nbsp;as
014&nbsp;&nbsp;&nbsp;&nbsp;having&nbsp;the&nbsp;key&nbsp;`:vertices`,&nbsp;whose&nbsp;value&nbsp;shall&nbsp;be&nbsp;a&nbsp;sequence&nbsp;of&nbsp;vertices&nbsp;as
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;defined&nbsp;in&nbsp;`walkmap.vertex`.&quot;
015&nbsp;&nbsp;&nbsp;&nbsp;defined&nbsp;in&nbsp;`walkmap.vertex`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;(let
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[v&nbsp;(:nodes&nbsp;o)]
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(seq?&nbsp;v)
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(count&nbsp;v)&nbsp;2)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?&nbsp;vertex?&nbsp;v))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
017&nbsp;&nbsp;
016&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
018&nbsp;&nbsp;(defn&nbsp;polygon-&gt;path
017&nbsp;&nbsp;&nbsp;&nbsp;(let
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;a&nbsp;polygon,&nbsp;return&nbsp;an&nbsp;equivalent&nbsp;path.&nbsp;What&#x27;s&nbsp;different&nbsp;about
<span class="covered" title="3 out of 3 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[v&nbsp;(:vertices&nbsp;o)]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;path&nbsp;is&nbsp;that&nbsp;in&nbsp;polygons&nbsp;there&nbsp;is&nbsp;an&nbsp;implicit&nbsp;edge&nbsp;between&nbsp;the&nbsp;first
<span class="partial" title="19 out of 22 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;vertex&nbsp;and&nbsp;the&nbsp;last.&nbsp;In&nbsp;paths,&nbsp;there&nbsp;isn&#x27;t,&nbsp;so&nbsp;we&nbsp;need&nbsp;to&nbsp;add&nbsp;that
<span class="covered" title="3 out of 3 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(seq?&nbsp;v)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;edge&nbsp;explicitly.
<span class="covered" title="6 out of 6 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(count&nbsp;v)&nbsp;1)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?&nbsp;vertex?&nbsp;v)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:walkmap.id&#x2F;id&nbsp;o)
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(nil?&nbsp;(:kind&nbsp;o))&nbsp;(=&nbsp;(:kind&nbsp;o)&nbsp;:path)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
023&nbsp;&nbsp;
025&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
026&nbsp;&nbsp;(defn&nbsp;path
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;polygon,&nbsp;will&nbsp;throw&nbsp;an&nbsp;exception.&quot;
027&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;path&nbsp;constructed&nbsp;from&nbsp;these&nbsp;`vertices`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;[o]
028&nbsp;&nbsp;&nbsp;&nbsp;[&amp;&nbsp;vertices]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;(if
<span class="covered" title="1 out of 1 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;(if
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(polygon?&nbsp;o)
<span class="covered" title="30 out of 30 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(count&nbsp;(check-vertices&nbsp;vertices))&nbsp;1)
</span><br/>
<span class="not-covered" title="0 out of 19 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;(dissoc&nbsp;o&nbsp;:vertices)&nbsp;:nodes&nbsp;(concat&nbsp;(:vertices&nbsp;o)&nbsp;(list&nbsp;(first&nbsp;(:vertices&nbsp;o)))))
<span class="covered" title="11 out of 11 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:vertices&nbsp;vertices&nbsp;:walkmap.id&#x2F;id&nbsp;(keyword&nbsp;(gensym&nbsp;&quot;path&quot;))&nbsp;:kind&nbsp;:path}
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(Exception.&nbsp;&quot;Not&nbsp;a&nbsp;polygon!&quot;))))
<span class="covered" title="3 out of 3 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.&nbsp;&quot;Path&nbsp;must&nbsp;have&nbsp;more&nbsp;than&nbsp;one&nbsp;vertex.&quot;))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
030&nbsp;&nbsp;
033&nbsp;&nbsp;
</span><br/>
<span class="covered" title="22 out of 22 forms covered">
034&nbsp;&nbsp;(defmacro&nbsp;check-path
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;path,&nbsp;throw&nbsp;an&nbsp;`IllegalArgumentException`&nbsp;with&nbsp;an
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;appropriate&nbsp;message;&nbsp;otherwise,&nbsp;returns&nbsp;`o`.&nbsp;Macro,&nbsp;so&nbsp;exception&nbsp;is&nbsp;thrown
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;the&nbsp;calling&nbsp;function.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;`(check-kind-type&nbsp;~o&nbsp;path?&nbsp;:path))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
040&nbsp;&nbsp;
</span><br/>
<span class="covered" title="21 out of 21 forms covered">
041&nbsp;&nbsp;(defmacro&nbsp;check-paths
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;sequence&nbsp;of&nbsp;paths,&nbsp;throw&nbsp;an&nbsp;`IllegalArgumentException`&nbsp;with&nbsp;an
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;appropriate&nbsp;message;&nbsp;otherwise,&nbsp;returns&nbsp;`o`.&nbsp;Macro,&nbsp;so&nbsp;exception&nbsp;is&nbsp;thrown
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;the&nbsp;calling&nbsp;function.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;`(check-kind-type-seq&nbsp;~o&nbsp;path?&nbsp;:path))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
047&nbsp;&nbsp;
</span><br/>
<span class="partial" title="1 out of 3 forms covered">
048&nbsp;&nbsp;(defn&nbsp;polygon-&gt;path
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;a&nbsp;polygon,&nbsp;return&nbsp;an&nbsp;equivalent&nbsp;path.&nbsp;What&#x27;s&nbsp;different&nbsp;about
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;path&nbsp;is&nbsp;that&nbsp;in&nbsp;polygons&nbsp;there&nbsp;is&nbsp;an&nbsp;implicit&nbsp;edge&nbsp;between&nbsp;the&nbsp;first
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;vertex&nbsp;and&nbsp;the&nbsp;last.&nbsp;In&nbsp;paths,&nbsp;there&nbsp;isn&#x27;t,&nbsp;so&nbsp;we&nbsp;need&nbsp;to&nbsp;add&nbsp;that
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;edge&nbsp;explicitly.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
053&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;polygon,&nbsp;will&nbsp;throw&nbsp;an&nbsp;exception.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
056&nbsp;&nbsp;;;&nbsp;this&nbsp;is&nbsp;breaking,&nbsp;but&nbsp;I&nbsp;have&nbsp;NO&nbsp;IDEA&nbsp;why!
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
057&nbsp;&nbsp;;;&nbsp;&nbsp;(check-polygon&nbsp;o&nbsp;polygon?&nbsp;:polygon)
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;(dissoc&nbsp;o&nbsp;:vertices)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:kind&nbsp;:path
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;`concat`&nbsp;rather&nbsp;than&nbsp;`conj`&nbsp;because&nbsp;order&nbsp;matters.
</span><br/>
<span class="covered" title="12 out of 12 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:vertices&nbsp;(concat&nbsp;(:vertices&nbsp;o)&nbsp;(list&nbsp;(first&nbsp;(:vertices&nbsp;o))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
062&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
063&nbsp;&nbsp;(defn&nbsp;path-&gt;edges
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&quot;if&nbsp;`o`&nbsp;is&nbsp;a&nbsp;path,&nbsp;a&nbsp;polygon,&nbsp;or&nbsp;a&nbsp;sequence&nbsp;of&nbsp;vertices,&nbsp;return&nbsp;a&nbsp;sequence&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;edges&nbsp;representing&nbsp;that&nbsp;path,&nbsp;polygon&nbsp;or&nbsp;sequence.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
066&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;Throws&nbsp;`IllegalArgumentException`&nbsp;if&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;path,&nbsp;a&nbsp;polygon,&nbsp;or
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;sequence&nbsp;of&nbsp;vertices.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(seq?&nbsp;o)&nbsp;(when
</span><br/>
<span class="partial" title="13 out of 14 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex?&nbsp;(first&nbsp;o))
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex?&nbsp;(first&nbsp;(rest&nbsp;o))))
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;TODO:&nbsp;think&nbsp;about:&nbsp;when&nbsp;constructing&nbsp;an&nbsp;edge&nbsp;from&nbsp;a&nbsp;path,&nbsp;should&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;constructed&nbsp;edge&nbsp;be&nbsp;tagged&nbsp;with&nbsp;the&nbsp;tags&nbsp;of&nbsp;the&nbsp;path?
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(e&#x2F;edge&nbsp;(first&nbsp;o)&nbsp;(first&nbsp;(rest&nbsp;o)))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(path-&gt;edges&nbsp;(rest&nbsp;o))))
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(path?&nbsp;o)&nbsp;(path-&gt;edges&nbsp;(:vertices&nbsp;o))
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(polygon?&nbsp;o)&nbsp;(path-&gt;edges&nbsp;(polygon-&gt;path&nbsp;o))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;Not&nbsp;a&nbsp;path&nbsp;or&nbsp;sequence&nbsp;of&nbsp;vertices!&quot;))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
085&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
086&nbsp;&nbsp;(defn&nbsp;length
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;length&nbsp;of&nbsp;this&nbsp;path,&nbsp;in&nbsp;metres.&nbsp;**Note&nbsp;that**
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;This&nbsp;is&nbsp;not&nbsp;the&nbsp;same&nbsp;as&nbsp;the&nbsp;distance&nbsp;from&nbsp;the&nbsp;start&nbsp;to&nbsp;the&nbsp;end&nbsp;of&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;path,&nbsp;which,&nbsp;except&nbsp;for&nbsp;absolutely&nbsp;straight&nbsp;paths,&nbsp;will&nbsp;be&nbsp;shorter;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;It&nbsp;is&nbsp;not&nbsp;even&nbsp;quite&nbsp;the&nbsp;same&nbsp;as&nbsp;the&nbsp;length&nbsp;of&nbsp;the&nbsp;path&nbsp;*as&nbsp;rendered*,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;since&nbsp;paths&nbsp;will&nbsp;generally&nbsp;be&nbsp;rendered&nbsp;as&nbsp;spline&nbsp;curves.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;[path]
</span><br/>
<span class="partial" title="14 out of 24 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;(reduce&nbsp;+&nbsp;(map&nbsp;e&#x2F;length&nbsp;(path-&gt;edges&nbsp;(check-path&nbsp;path)))))
</span><br/>
</body>
</html>

View file

@ -11,49 +11,463 @@
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Essentially&nbsp;the&nbsp;specification&nbsp;for&nbsp;things&nbsp;we&nbsp;shall&nbsp;consider&nbsp;to&nbsp;be&nbsp;polygons.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[walkmap.vertex&nbsp;:refer&nbsp;[vertex?]]))
003&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.string&nbsp;:as&nbsp;s]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.edge&nbsp;:as&nbsp;e]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.tag&nbsp;:as&nbsp;t]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.utils&nbsp;:refer&nbsp;[check-kind-type
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;check-kind-type-seq
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kind-type
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;not-yet-implemented]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:refer&nbsp;[check-vertex&nbsp;check-vertices&nbsp;vertex&nbsp;vertex?]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
004&nbsp;&nbsp;
011&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
005&nbsp;&nbsp;(defn&nbsp;polygon?
012&nbsp;&nbsp;(defn&nbsp;polygon?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;satisfies&nbsp;the&nbsp;conditions&nbsp;for&nbsp;a&nbsp;polygon.&nbsp;A&nbsp;polygon&nbsp;shall&nbsp;be&nbsp;a
013&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;satisfies&nbsp;the&nbsp;conditions&nbsp;for&nbsp;a&nbsp;polygon.&nbsp;A&nbsp;polygon&nbsp;shall&nbsp;be&nbsp;a
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;map&nbsp;which&nbsp;has&nbsp;a&nbsp;value&nbsp;for&nbsp;the&nbsp;key&nbsp;`:vertices`,&nbsp;where&nbsp;that&nbsp;value&nbsp;is&nbsp;a&nbsp;sequence
014&nbsp;&nbsp;&nbsp;&nbsp;map&nbsp;which&nbsp;has&nbsp;a&nbsp;value&nbsp;for&nbsp;the&nbsp;key&nbsp;`:vertices`,&nbsp;where&nbsp;that&nbsp;value&nbsp;is&nbsp;a&nbsp;sequence
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;of&nbsp;vertices.&quot;
015&nbsp;&nbsp;&nbsp;&nbsp;of&nbsp;vertices.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;[o]
016&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;(let
<span class="covered" title="1 out of 1 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;(let
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[v&nbsp;(:vertices&nbsp;o)]
</span><br/>
<span class="partial" title="18 out of 22 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(coll?&nbsp;v)
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(count&nbsp;v)&nbsp;2)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?&nbsp;vertex?&nbsp;v)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:walkmap.id&#x2F;id&nbsp;o)
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(nil?&nbsp;(:kind&nbsp;o))&nbsp;(=&nbsp;(:kind&nbsp;o)&nbsp;:polygon)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
025&nbsp;&nbsp;
</span><br/>
<span class="covered" title="22 out of 22 forms covered">
026&nbsp;&nbsp;(defmacro&nbsp;check-polygon
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;polygon,&nbsp;throw&nbsp;an&nbsp;`IllegalArgumentException`&nbsp;with&nbsp;an
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;appropriate&nbsp;message;&nbsp;otherwise,&nbsp;returns&nbsp;`o`.&nbsp;Macro,&nbsp;so&nbsp;exception&nbsp;is&nbsp;thrown
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;the&nbsp;calling&nbsp;function.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;`(check-kind-type&nbsp;~o&nbsp;polygon?&nbsp;:polygon))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
032&nbsp;&nbsp;
</span><br/>
<span class="covered" title="21 out of 21 forms covered">
033&nbsp;&nbsp;(defmacro&nbsp;check-polygons
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;sequence&nbsp;of&nbsp;polygons,&nbsp;throw&nbsp;an&nbsp;`IllegalArgumentException`&nbsp;with&nbsp;an
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;appropriate&nbsp;message;&nbsp;otherwise,&nbsp;returns&nbsp;`o`.&nbsp;Macro,&nbsp;so&nbsp;exception&nbsp;is&nbsp;thrown
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;the&nbsp;calling&nbsp;function.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;`(check-kind-type-seq&nbsp;~o&nbsp;polygon?&nbsp;:polygon))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
039&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
040&nbsp;&nbsp;(defn&nbsp;triangle?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;satisfies&nbsp;the&nbsp;conditions&nbsp;for&nbsp;a&nbsp;triangle.&nbsp;A&nbsp;triangle&nbsp;shall&nbsp;be&nbsp;a
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;polygon&nbsp;with&nbsp;exactly&nbsp;three&nbsp;vertices.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="partial" title="5 out of 6 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(coll?&nbsp;o)
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;(count&nbsp;(:vertices&nbsp;o))&nbsp;3)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
047&nbsp;&nbsp;
</span><br/>
<span class="partial" title="25 out of 33 forms covered">
048&nbsp;&nbsp;(defmacro&nbsp;check-triangle
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;triangle,&nbsp;throw&nbsp;an&nbsp;`IllegalArgumentException`&nbsp;with&nbsp;an
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;appropriate&nbsp;message;&nbsp;otherwise,&nbsp;returns&nbsp;`o`.&nbsp;Macro,&nbsp;so&nbsp;exception&nbsp;is&nbsp;thrown
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;the&nbsp;calling&nbsp;function.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;`(check-kind-type&nbsp;~o&nbsp;triangle?&nbsp;:triangle))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
054&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
055&nbsp;&nbsp;(defn&nbsp;polygon
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;polygon&nbsp;constructed&nbsp;from&nbsp;these&nbsp;`vertices`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;[&amp;&nbsp;vertices]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;(if
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(count&nbsp;vertices)&nbsp;2)
</span><br/>
<span class="covered" title="30 out of 30 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:vertices&nbsp;(check-vertices&nbsp;vertices)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:walkmap.id&#x2F;id&nbsp;(keyword&nbsp;(gensym&nbsp;&quot;poly&quot;))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:kind&nbsp;:polygon}
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;A&nbsp;polygon&nbsp;must&nbsp;have&nbsp;at&nbsp;least&nbsp;3&nbsp;vertices.&quot;))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
065&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
066&nbsp;&nbsp;(defn&nbsp;rectangle
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;rectangle,&nbsp;with&nbsp;edges&nbsp;aligned&nbsp;east-west&nbsp;and&nbsp;north-south,&nbsp;whose
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;south-west&nbsp;corner&nbsp;is&nbsp;the&nbsp;vertex&nbsp;`vsw`&nbsp;and&nbsp;whose&nbsp;north-east&nbsp;corner&nbsp;is&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;vertex&nbsp;`vne`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;[vsw&nbsp;vne]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;we&nbsp;can&nbsp;actually&nbsp;create&nbsp;any&nbsp;rectangle&nbsp;in&nbsp;the&nbsp;xy&nbsp;plane&nbsp;based&nbsp;on&nbsp;two&nbsp;opposite
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;corners,&nbsp;but&nbsp;the&nbsp;maths&nbsp;are&nbsp;a&nbsp;bit&nbsp;to&nbsp;advanced&nbsp;for&nbsp;me&nbsp;today.&nbsp;TODO:&nbsp;do&nbsp;it!
</span><br/>
<span class="not-covered" title="0 out of 21 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[vnw&nbsp;(vertex&nbsp;(:x&nbsp;(check-vertex&nbsp;vsw))
</span><br/>
<span class="not-covered" title="0 out of 18 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:y&nbsp;(check-vertex&nbsp;vne))
</span><br/>
<span class="not-covered" title="0 out of 20 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&#x2F;&nbsp;(reduce&nbsp;+&nbsp;(map&nbsp;#(or&nbsp;(:z&nbsp;%)&nbsp;0)&nbsp;[vsw&nbsp;vne]))&nbsp;2))
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vse&nbsp;(vertex&nbsp;(:x&nbsp;vne)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[v&nbsp;(:vertices&nbsp;o)]
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:y&nbsp;vsw)
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(seq?&nbsp;v)
<span class="not-covered" title="0 out of 20 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&#x2F;&nbsp;(reduce&nbsp;+&nbsp;(map&nbsp;#(or&nbsp;(:z&nbsp;%)&nbsp;0)&nbsp;[vsw&nbsp;vne]))&nbsp;2))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(count&nbsp;v)&nbsp;2)
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;height-order&nbsp;(sort-by&nbsp;:z&nbsp;[vsw&nbsp;vne])]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?&nbsp;vertex?&nbsp;v))))
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(t&#x2F;tag
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(polygon&nbsp;vsw&nbsp;vnw&nbsp;vne&nbsp;vse)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:gradient
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(e&#x2F;unit-vector&nbsp;(e&#x2F;edge&nbsp;(first&nbsp;height-order)&nbsp;(last&nbsp;height-order)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:centre
</span><br/>
<span class="not-covered" title="0 out of 18 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex&nbsp;(+&nbsp;(:x&nbsp;vsw)&nbsp;(&#x2F;&nbsp;(-&nbsp;(:x&nbsp;vne)&nbsp;(:x&nbsp;vsw))&nbsp;2))
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+&nbsp;(:x&nbsp;vsw)&nbsp;(&#x2F;&nbsp;(-&nbsp;(:y&nbsp;vne)&nbsp;(:y&nbsp;vsw))&nbsp;2))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:z&nbsp;vse)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:rectangle)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
016&nbsp;&nbsp;
090&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;;;&nbsp;(rectangle&nbsp;(vertex&nbsp;1&nbsp;2&nbsp;3)&nbsp;(vertex&nbsp;7&nbsp;9&nbsp;4))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
017&nbsp;&nbsp;
092&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
093&nbsp;&nbsp;(defn&nbsp;gradient
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;polygon&nbsp;like&nbsp;`triangle`&nbsp;but&nbsp;with&nbsp;a&nbsp;key&nbsp;`:gradient`&nbsp;whose&nbsp;value&nbsp;is&nbsp;a
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;unit&nbsp;vector&nbsp;representing&nbsp;the&nbsp;gradient&nbsp;across&nbsp;`triangle`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;[triangle]
</span><br/>
<span class="covered" title="12 out of 12 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[order&nbsp;(sort&nbsp;#(max&nbsp;(:z&nbsp;%1)&nbsp;(:z&nbsp;%2))
</span><br/>
<span class="partial" title="8 out of 18 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:vertices&nbsp;(check-triangle&nbsp;triangle)))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;highest&nbsp;(first&nbsp;order)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lowest&nbsp;(last&nbsp;order)]
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;triangle&nbsp;:gradient&nbsp;(e&#x2F;unit-vector&nbsp;(e&#x2F;edge&nbsp;lowest&nbsp;highest)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
102&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
103&nbsp;&nbsp;(defn&nbsp;triangle-centre
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;canonicalised&nbsp;`facet`&nbsp;(i.e.&nbsp;a&nbsp;triangular&nbsp;polygon)&nbsp;with&nbsp;an&nbsp;added
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;key&nbsp;`:centre`&nbsp;whose&nbsp;value&nbsp;represents&nbsp;the&nbsp;centre&nbsp;of&nbsp;this&nbsp;facet&nbsp;in&nbsp;3
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;dimensions.&nbsp;This&nbsp;only&nbsp;works&nbsp;for&nbsp;triangles,&nbsp;so&nbsp;is&nbsp;here&nbsp;not&nbsp;in
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;`walkmap.polygon`.&nbsp;It&nbsp;is&nbsp;an&nbsp;error&nbsp;(although&nbsp;no&nbsp;exception&nbsp;is&nbsp;currently
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;thrown)&nbsp;if&nbsp;the&nbsp;object&nbsp;past&nbsp;is&nbsp;not&nbsp;a&nbsp;triangular&nbsp;polygon.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;[facet]
</span><br/>
<span class="partial" title="9 out of 19 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[vs&nbsp;(:vertices&nbsp;(check-triangle&nbsp;facet))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v1&nbsp;(first&nbsp;vs)
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;opposite&nbsp;(e&#x2F;edge&nbsp;(nth&nbsp;vs&nbsp;1)&nbsp;(nth&nbsp;vs&nbsp;2))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oc&nbsp;(e&#x2F;centre&nbsp;opposite)]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;facet
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:centre
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex
</span><br/>
<span class="covered" title="16 out of 16 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+&nbsp;(:x&nbsp;v1)&nbsp;(*&nbsp;(-&nbsp;(:x&nbsp;oc)&nbsp;(:x&nbsp;v1))&nbsp;2&#x2F;3))
</span><br/>
<span class="covered" title="16 out of 16 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+&nbsp;(:y&nbsp;v1)&nbsp;(*&nbsp;(-&nbsp;(:y&nbsp;oc)&nbsp;(:y&nbsp;v1))&nbsp;2&#x2F;3))
</span><br/>
<span class="covered" title="16 out of 16 forms covered">
120&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+&nbsp;(:z&nbsp;v1)&nbsp;(*&nbsp;(-&nbsp;(:z&nbsp;oc)&nbsp;(:z&nbsp;v1))&nbsp;2&#x2F;3))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
121&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
122&nbsp;&nbsp;(defn&nbsp;centre
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;[poly]
</span><br/>
<span class="covered" title="22 out of 22 forms covered">
124&nbsp;&nbsp;&nbsp;&nbsp;(case&nbsp;(count&nbsp;(:vertices&nbsp;(check-polygon&nbsp;poly)))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;(triangle-centre&nbsp;poly)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;else
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
127&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(UnsupportedOperationException.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;general&nbsp;case&nbsp;of&nbsp;centre&nbsp;for&nbsp;polygons&nbsp;is&nbsp;not&nbsp;yet&nbsp;implemented.&quot;))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
130&nbsp;&nbsp;
</span><br/>
<span class="partial" title="4 out of 16 forms covered">
131&nbsp;&nbsp;(defmacro&nbsp;on2dtriangle?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;&quot;Is&nbsp;the&nbsp;projection&nbsp;of&nbsp;this&nbsp;`vertex`&nbsp;on&nbsp;the&nbsp;x,&nbsp;y&nbsp;plane&nbsp;within&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
133&nbsp;&nbsp;&nbsp;&nbsp;projection&nbsp;of&nbsp;this&nbsp;triangle&nbsp;on&nbsp;that&nbsp;plane?&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;[vertex&nbsp;poly]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
135&nbsp;&nbsp;&nbsp;&nbsp;`(not-yet-implemented&nbsp;&quot;on2d?&nbsp;for&nbsp;triangles.&quot;))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
136&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
137&nbsp;&nbsp;(defn&nbsp;on2drectangle?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
138&nbsp;&nbsp;&nbsp;&nbsp;&quot;Is&nbsp;the&nbsp;projection&nbsp;of&nbsp;this&nbsp;`vertex`&nbsp;on&nbsp;the&nbsp;x,&nbsp;y&nbsp;plane&nbsp;within&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
139&nbsp;&nbsp;&nbsp;&nbsp;projection&nbsp;of&nbsp;this&nbsp;rectangle&nbsp;on&nbsp;that&nbsp;plane?&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
140&nbsp;&nbsp;&nbsp;&nbsp;[vertex&nbsp;rectangle]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
141&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[xo&nbsp;(sort-by&nbsp;:x&nbsp;(:vertices&nbsp;rectangle))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
142&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yo&nbsp;(sort-by&nbsp;:x&nbsp;(:vertices&nbsp;rectangle))]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
143&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 15 forms covered">
144&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(:x&nbsp;(first&nbsp;xo))&nbsp;(:x&nbsp;vertex)&nbsp;(:x&nbsp;(last&nbsp;xo)))
</span><br/>
<span class="not-covered" title="0 out of 14 forms covered">
145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(:y&nbsp;(first&nbsp;yo))&nbsp;(:y&nbsp;vertex)&nbsp;(:y&nbsp;(last&nbsp;yo))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
146&nbsp;&nbsp;
</span><br/>
<span class="partial" title="4 out of 86 forms covered">
147&nbsp;&nbsp;(defmacro&nbsp;on2d?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
148&nbsp;&nbsp;&nbsp;&nbsp;&quot;Is&nbsp;the&nbsp;projection&nbsp;of&nbsp;this&nbsp;`vertex`&nbsp;on&nbsp;the&nbsp;x,&nbsp;y&nbsp;plane&nbsp;within&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
149&nbsp;&nbsp;&nbsp;&nbsp;projection&nbsp;of&nbsp;this&nbsp;polygon&nbsp;`poly`&nbsp;on&nbsp;that&nbsp;plane?&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
150&nbsp;&nbsp;&nbsp;&nbsp;[vertex&nbsp;poly]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
151&nbsp;&nbsp;&nbsp;&nbsp;`(cond
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
152&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(rectangle?&nbsp;~poly)&nbsp;(on2drectangle?&nbsp;~vertex&nbsp;~poly)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
153&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(triangle?&nbsp;~poly)&nbsp;(on2dtriangle?&nbsp;~vertex&nbsp;~poly)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
154&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
155&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(not-yet-implemented&nbsp;&quot;general&nbsp;case&nbsp;of&nbsp;on2d?&nbsp;for&nbsp;polygons.&quot;)))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,308 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> walkmap/read_svg.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;walkmap.read-svg
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Utility&nbsp;functions&nbsp;for&nbsp;&nbsp;scalable&nbsp;vector&nbsp;graphics&nbsp;(SVG)&nbsp;into&nbsp;walkmap
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;structures.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.data.zip&nbsp;:as&nbsp;dz]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.data.zip.xml&nbsp;:as&nbsp;zx]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.java.io&nbsp;:as&nbsp;io]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.string&nbsp;:as&nbsp;s]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.xml&nbsp;:as&nbsp;x]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.zip&nbsp;:as&nbsp;z]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.path&nbsp;:refer&nbsp;[path]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.tag&nbsp;:refer&nbsp;[tag]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.utils&nbsp;:refer&nbsp;[kind-type&nbsp;truncate]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:refer&nbsp;[vertex&nbsp;vertex?]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
015&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
016&nbsp;&nbsp;(defn&nbsp;upper-case?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;[s]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;(every?&nbsp;#(Character&#x2F;isUpperCase&nbsp;%)&nbsp;s))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
019&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
020&nbsp;&nbsp;(defn&nbsp;match-&gt;vertex
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;[match-vector&nbsp;x&nbsp;y]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;(when-not&nbsp;(empty?&nbsp;match-vector)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[command&nbsp;(nth&nbsp;match-vector&nbsp;1)
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xcoord&nbsp;(read-string&nbsp;(nth&nbsp;match-vector&nbsp;2))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ycoord&nbsp;(read-string&nbsp;(nth&nbsp;match-vector&nbsp;3))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;upper&nbsp;case&nbsp;command&nbsp;letters&nbsp;mean&nbsp;the&nbsp;coordinates&nbsp;that&nbsp;follow&nbsp;are
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;absolute;&nbsp;lower&nbsp;case,&nbsp;relative.
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&#x27;&nbsp;(if&nbsp;(upper-case?&nbsp;command)&nbsp;xcoord&nbsp;(+&nbsp;x&nbsp;xcoord))
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y&#x27;&nbsp;(if&nbsp;(upper-case?&nbsp;command)&nbsp;ycoord&nbsp;(+&nbsp;y&nbsp;ycoord))]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(case&nbsp;(s&#x2F;lower-case&nbsp;command)
</span><br/>
<span class="not-covered" title="0 out of 20 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&quot;m&quot;&nbsp;&quot;l&quot;)&nbsp;{:vertex&nbsp;(vertex&nbsp;x&#x27;&nbsp;y&#x27;)&nbsp;:x&nbsp;x&#x27;&nbsp;:y&nbsp;y&#x27;}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
033&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
034&nbsp;&nbsp;(defn&nbsp;command-string-&gt;vertices
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;destination&nbsp;of&nbsp;each&nbsp;successive&nbsp;line&nbsp;(`l`,&nbsp;`L`)&nbsp;and&nbsp;move&nbsp;(`m`,&nbsp;`M`)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;command&nbsp;in&nbsp;this&nbsp;string&nbsp;`s`,&nbsp;expected&nbsp;to&nbsp;be&nbsp;an&nbsp;SVG&nbsp;path&nbsp;command&nbsp;string.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;[s]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[cmd-matcher&nbsp;;;&nbsp;matches&nbsp;a&nbsp;&#x27;command&#x27;&nbsp;in&nbsp;the&nbsp;string:&nbsp;a&nbsp;letter&nbsp;followed&nbsp;by
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;spaces&nbsp;and&nbsp;numbers
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(re-matcher&nbsp;#&quot;[a-zA-Z][^a-zA-Z]*&quot;&nbsp;s)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;seg-pattern&nbsp;;;&nbsp;matches&nbsp;a&nbsp;command&nbsp;which&nbsp;initiates&nbsp;a&nbsp;move&nbsp;of&nbsp;the&nbsp;current
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;position.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&quot;([a-zA-Z])&nbsp;+([-+]?[0-9]*\.?[0-9]+)&nbsp;+([-+]?[0-9]*\.?[0-9]+)&nbsp;+&quot;]
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(loop&nbsp;[match&nbsp;(re-find&nbsp;cmd-matcher)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;[]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;0
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y&nbsp;0]
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if-not&nbsp;match
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(filter&nbsp;vertex?&nbsp;result)
</span><br/>
<span class="not-covered" title="0 out of 18 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[m&nbsp;(match-&gt;vertex&nbsp;(re-find&nbsp;seg-pattern&nbsp;match)&nbsp;x&nbsp;y)]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(recur&nbsp;(re-find&nbsp;cmd-matcher)&nbsp;&nbsp;&nbsp;&nbsp;;loop&nbsp;with&nbsp;2&nbsp;new&nbsp;arguments
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(conj&nbsp;result&nbsp;(:vertex&nbsp;m))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(:x&nbsp;m)&nbsp;x)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(:y&nbsp;m)&nbsp;y)))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
055&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
056&nbsp;&nbsp;(defn&nbsp;path-elt-&gt;path
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&quot;Given&nbsp;the&nbsp;SVG&nbsp;path&nbsp;element&nbsp;`elt`,&nbsp;return&nbsp;a&nbsp;walkmap&nbsp;path&nbsp;structure
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;representing&nbsp;the&nbsp;line&nbsp;(`l`,&nbsp;`L`)&nbsp;and&nbsp;move&nbsp;(`m`,&nbsp;`M`)&nbsp;commands&nbsp;in
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;that&nbsp;path.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;[elt]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(=&nbsp;(:tag&nbsp;elt)&nbsp;:path)
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[vs&nbsp;(command-string-&gt;vertices&nbsp;(-&gt;&nbsp;elt&nbsp;:attrs&nbsp;:d))
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;&nbsp;(when-not&nbsp;(empty?&nbsp;vs)&nbsp;(apply&nbsp;path&nbsp;vs))]
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(and&nbsp;p&nbsp;(-&gt;&nbsp;elt&nbsp;:attrs&nbsp;:class))
</span><br/>
<span class="not-covered" title="0 out of 14 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(tag&nbsp;p&nbsp;(map&nbsp;keyword&nbsp;(s&#x2F;split&nbsp;(-&gt;&nbsp;elt&nbsp;:attrs&nbsp;:class)&nbsp;#&quot;&nbsp;&quot;)))
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p))
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Must&nbsp;be&nbsp;an&nbsp;SVG&nbsp;`path`&nbsp;element:&nbsp;&quot;&nbsp;elt)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
069&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
070&nbsp;&nbsp;(defn&nbsp;progeny
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;all&nbsp;the&nbsp;nodes&nbsp;in&nbsp;the&nbsp;XML&nbsp;structure&nbsp;below&nbsp;this&nbsp;`elt`&nbsp;which&nbsp;match
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;`predicate`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;the&nbsp;name&nbsp;`descendants`&nbsp;is&nbsp;bound&nbsp;in&nbsp;`clojure.core`&nbsp;for&nbsp;something&nbsp;quite
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;different,&nbsp;and&nbsp;I&nbsp;chose&nbsp;not&nbsp;to&nbsp;rebind&nbsp;it.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;[elt&nbsp;predicate]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;(if
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;predicate&nbsp;(list&nbsp;elt))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(list&nbsp;elt)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;concat
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(remove
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;empty?
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(progeny&nbsp;%&nbsp;predicate)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:content&nbsp;elt))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
086&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
087&nbsp;&nbsp;(defn&nbsp;read-svg
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;I&nbsp;tried&nbsp;to&nbsp;get&nbsp;this&nbsp;working&nbsp;with&nbsp;all&nbsp;the&nbsp;clever&nbsp;zip&nbsp;stuff&nbsp;in
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;`clojure.zip`,&nbsp;`clojure.data.zip`,&nbsp;and&nbsp;so&nbsp;on.&nbsp;It&nbsp;would&nbsp;probably&nbsp;have
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;been&nbsp;more&nbsp;elegant,&nbsp;but&nbsp;it&nbsp;kept&nbsp;crashing&nbsp;out&nbsp;of&nbsp;heap&nbsp;space&nbsp;on&nbsp;even
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;quite&nbsp;small&nbsp;XML&nbsp;files.&nbsp;So&nbsp;I&#x27;ve&nbsp;implemented&nbsp;my&nbsp;own&nbsp;solution.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;([file-name]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(read-svg&nbsp;file-name&nbsp;nil))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;([file-name&nbsp;map-kind]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[xml&nbsp;(x&#x2F;parse&nbsp;(io&#x2F;file&nbsp;file-name))
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;paths&nbsp;(progeny&nbsp;xml&nbsp;#(=&nbsp;(:tag&nbsp;%)&nbsp;:path))]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(remove&nbsp;nil?&nbsp;(map&nbsp;path-elt-&gt;path&nbsp;paths)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
098&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
099&nbsp;&nbsp;;;&nbsp;(read-svg&nbsp;&quot;resources&#x2F;iom&#x2F;manual_roads.svg&quot;)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
100&nbsp;&nbsp;
</span><br/>
</body>
</html>

View file

@ -0,0 +1,611 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> walkmap/routing.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;walkmap.routing
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Finding&nbsp;optimal&nbsp;routes&nbsp;to&nbsp;traverse&nbsp;a&nbsp;map.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.math.numeric-tower&nbsp;:as&nbsp;m&nbsp;:only&nbsp;[expt]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.set&nbsp;:refer&nbsp;[intersection]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.edge&nbsp;:as&nbsp;e]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.path&nbsp;:as&nbsp;p]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.polygon&nbsp;:as&nbsp;q]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.superstructure&nbsp;:as&nbsp;s]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.tag&nbsp;:as&nbsp;t]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.utils&nbsp;:as&nbsp;u]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:as&nbsp;v]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
012&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;;;&nbsp;Breadth&nbsp;first&nbsp;search&nbsp;is&nbsp;a&nbsp;good&nbsp;algorithm&nbsp;for&nbsp;terrain&nbsp;in&nbsp;which&nbsp;all&nbsp;steps&nbsp;have
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;;;&nbsp;equal,&nbsp;but&nbsp;in&nbsp;our&nbsp;world&nbsp;(like&nbsp;the&nbsp;real&nbsp;world),&nbsp;they&nbsp;don&#x27;t.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
015&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;;;&nbsp;Reading&nbsp;list:
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;;;&nbsp;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;A*_search_algorithm
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;;;&nbsp;https:&#x2F;&#x2F;www.redblobgames.com&#x2F;pathfinding&#x2F;a-star&#x2F;introduction.html
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;;;&nbsp;https:&#x2F;&#x2F;faculty.nps.edu&#x2F;ncrowe&#x2F;opmpaper2.htm
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;;;&nbsp;See&nbsp;https:&#x2F;&#x2F;simon-brooke.github.io&#x2F;the-great-game&#x2F;codox&#x2F;Pathmaking.html
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
023&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
024&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*gradient-exponent*
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;exponent&nbsp;to&nbsp;be&nbsp;applied&nbsp;to&nbsp;`(inc&nbsp;(:z&nbsp;(unit-vector&nbsp;from&nbsp;to)))`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;of&nbsp;a&nbsp;path&nbsp;segment&nbsp;to&nbsp;calculate&nbsp;the&nbsp;gradient-related&nbsp;part&nbsp;of&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;cost&nbsp;of&nbsp;traversal.&nbsp;Dynamic,&nbsp;because&nbsp;we&nbsp;will&nbsp;want&nbsp;to&nbsp;tune&nbsp;this.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;2)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
029&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
030&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*traversals-exponent*
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&quot;The&nbsp;(expected&nbsp;to&nbsp;be&nbsp;negative)&nbsp;exponent&nbsp;to&nbsp;be&nbsp;applied&nbsp;to&nbsp;the&nbsp;number
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;of&nbsp;traversals&nbsp;of&nbsp;a&nbsp;path&nbsp;to&nbsp;compute&nbsp;the&nbsp;road&nbsp;bonus.&nbsp;Paths&nbsp;more&nbsp;travelled&nbsp;by
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;should&nbsp;have&nbsp;larger&nbsp;bonuses,&nbsp;but&nbsp;not&nbsp;dramatically&nbsp;so&nbsp;-&nbsp;so&nbsp;the&nbsp;increase&nbsp;in
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;bonus&nbsp;needs&nbsp;to&nbsp;scale&nbsp;significantly&nbsp;less&nbsp;than&nbsp;linearly&nbsp;with&nbsp;the&nbsp;number
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;of&nbsp;traversals.&nbsp;Dynamic,&nbsp;because&nbsp;we&nbsp;will&nbsp;want&nbsp;to&nbsp;tune&nbsp;this.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;-2)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
037&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
038&nbsp;&nbsp;(defn&nbsp;traversable?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;this&nbsp;object&nbsp;can&nbsp;be&nbsp;considered&nbsp;as&nbsp;part&nbsp;of&nbsp;the&nbsp;walkmap.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;[object]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(q&#x2F;polygon?&nbsp;object)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:centre&nbsp;object))
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(p&#x2F;path?&nbsp;object))
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(not&nbsp;(t&#x2F;tagged?&nbsp;object&nbsp;:no-traversal))))
</span><br/>
<span class="blank" title="0 out of 2 forms covered">
048&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
049&nbsp;&nbsp;(declare&nbsp;traversal-cost)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
050&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
051&nbsp;&nbsp;(defn&nbsp;vertices-traversal-cost
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;[vertices&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(traversal-cost&nbsp;%1&nbsp;%2&nbsp;s)
</span><br/>
<span class="not-covered" title="0 out of 25 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(v&#x2F;check-vertices&nbsp;vertices)
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(rest&nbsp;vertices))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
059&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
060&nbsp;&nbsp;(defn&nbsp;path-traversal-cost
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;[path&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 21 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;(vertices-traversal-cost&nbsp;(:vertices&nbsp;(p&#x2F;check-path&nbsp;path))&nbsp;s))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
063&nbsp;&nbsp;
</span><br/>
<span class="partial" title="1 out of 2 forms covered">
064&nbsp;&nbsp;(defn&nbsp;barriers-crossed
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&quot;Search&nbsp;superstructure&nbsp;`s`&nbsp;and&nbsp;return&nbsp;a&nbsp;sequence&nbsp;of&nbsp;barriers,&nbsp;if&nbsp;any,&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;obstruct&nbsp;traversal&nbsp;from&nbsp;vertex&nbsp;`from`&nbsp;to&nbsp;vertex&nbsp;`to`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;[from&nbsp;to&nbsp;s]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;TODO:&nbsp;implement
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&#x27;())
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
070&nbsp;&nbsp;
</span><br/>
<span class="partial" title="1 out of 2 forms covered">
071&nbsp;&nbsp;(defn&nbsp;crossing-penalty
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&quot;TODO:&nbsp;should&nbsp;return&nbsp;the&nbsp;cost&nbsp;of&nbsp;crossing&nbsp;this&nbsp;`barrier`,&nbsp;initially&nbsp;mainly
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;watercourse,&nbsp;on&nbsp;the&nbsp;axis&nbsp;from&nbsp;vertex&nbsp;`from`&nbsp;to&nbsp;vertex&nbsp;`to`.&nbsp;in&nbsp;the&nbsp;context
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;of&nbsp;superstructure&nbsp;`s`.&nbsp;If&nbsp;there&#x27;s&nbsp;a&nbsp;bridge,&nbsp;ferry&nbsp;or&nbsp;other&nbsp;crossing&nbsp;mechanism
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;in&nbsp;`s`&nbsp;at&nbsp;the&nbsp;intersection&nbsp;of&nbsp;the&nbsp;vertex&nbsp;and&nbsp;the&nbsp;barrier,&nbsp;then&nbsp;the&nbsp;penalty
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;should&nbsp;be&nbsp;substantially&nbsp;less&nbsp;than&nbsp;it&nbsp;would&nbsp;otherwise&nbsp;be.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;[barrier&nbsp;from&nbsp;to&nbsp;s]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;TODO:&nbsp;implement
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;0)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
080&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
081&nbsp;&nbsp;(defn&nbsp;gradient-cost
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&quot;Compute&nbsp;the&nbsp;per-unit-distance&nbsp;cost&nbsp;of&nbsp;traversing&nbsp;this&nbsp;`edge`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;[edge]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[g&nbsp;(:z&nbsp;(e&#x2F;unit-vector&nbsp;edge))]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(pos?&nbsp;g)
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(m&#x2F;expt&nbsp;(inc&nbsp;g)&nbsp;*gradient-exponent*)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
088&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
089&nbsp;&nbsp;;;&nbsp;(gradient-cost&nbsp;(e&#x2F;edge&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;0&nbsp;0)&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;1&nbsp;0)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;;;&nbsp;(gradient-cost&nbsp;(e&#x2F;edge&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;0&nbsp;0)&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;2&nbsp;0)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;;;&nbsp;(gradient-cost&nbsp;(e&#x2F;edge&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;0&nbsp;0)&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;1&nbsp;1)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
092&nbsp;&nbsp;;;&nbsp;(gradient-cost&nbsp;(e&#x2F;edge&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;0&nbsp;0)&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;2&nbsp;1)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
093&nbsp;&nbsp;;;&nbsp;(gradient-cost&nbsp;(e&#x2F;edge&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;0&nbsp;0)&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;1&nbsp;0.0001)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
094&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
095&nbsp;&nbsp;(defn&nbsp;best-road
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;&quot;Find&nbsp;the&nbsp;best&nbsp;traversable&nbsp;path&nbsp;which&nbsp;links&nbsp;the&nbsp;vertices&nbsp;`from`&nbsp;and&nbsp;`to`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;in&nbsp;this&nbsp;superstructure&nbsp;`s`,&nbsp;or&nbsp;nil&nbsp;if&nbsp;there&nbsp;are&nbsp;none.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;[from&nbsp;to&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[f&nbsp;(fn&nbsp;[v]&nbsp;(set&nbsp;(s&#x2F;touching&nbsp;v&nbsp;p&#x2F;path?&nbsp;s)))]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(first
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sort-by
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;;&nbsp;I...&nbsp;chose&nbsp;the&nbsp;path&nbsp;more&nbsp;travelled&nbsp;by.
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(or&nbsp;(:traversals&nbsp;%)&nbsp;0)
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(filter&nbsp;traversable?&nbsp;(intersection&nbsp;(f&nbsp;from)&nbsp;(f&nbsp;to)))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
105&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
106&nbsp;&nbsp;(defn&nbsp;road-bonus
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;&quot;Calculate&nbsp;the&nbsp;road&nbsp;bonus&nbsp;of&nbsp;the&nbsp;edge&nbsp;represented&nbsp;by&nbsp;the&nbsp;vertices&nbsp;`from`,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;`to`,&nbsp;in&nbsp;the&nbsp;context&nbsp;of&nbsp;the&nbsp;superstructure&nbsp;`s`.&nbsp;Obviously&nbsp;there&nbsp;only&nbsp;is
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;such&nbsp;a&nbsp;bonus&nbsp;if&nbsp;there&nbsp;actually&nbsp;is&nbsp;an&nbsp;existing&nbsp;thoroughfare&nbsp;to&nbsp;use.&nbsp;Road
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;bonuses&nbsp;scale&nbsp;with&nbsp;some&nbsp;fractional&nbsp;exponent&nbsp;of&nbsp;the&nbsp;number&nbsp;of&nbsp;traversals
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;which&nbsp;have&nbsp;been&nbsp;made&nbsp;of&nbsp;the&nbsp;road&nbsp;segment&nbsp;in&nbsp;question.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;[from&nbsp;to&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[best&nbsp;(best-road&nbsp;from&nbsp;to&nbsp;s)]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when&nbsp;(:traversals&nbsp;best)
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(m&#x2F;expt&nbsp;(:traversals&nbsp;best)&nbsp;*traversals-exponent*))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
116&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
117&nbsp;&nbsp;(defn&nbsp;traversal-cost
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;traversal&nbsp;cost&nbsp;of&nbsp;the&nbsp;edge&nbsp;represented&nbsp;by&nbsp;the&nbsp;vertices&nbsp;`from`,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;`to`,&nbsp;in&nbsp;the&nbsp;context&nbsp;of&nbsp;the&nbsp;superstructure&nbsp;`s`.&nbsp;It&nbsp;is&nbsp;legitimate&nbsp;to&nbsp;pass
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
120&nbsp;&nbsp;&nbsp;&nbsp;`nil`&nbsp;as&nbsp;the&nbsp;`to`&nbsp;argument,&nbsp;in&nbsp;which&nbsp;case&nbsp;the&nbsp;result&nbsp;will&nbsp;be&nbsp;zero,&nbsp;in&nbsp;order
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
121&nbsp;&nbsp;&nbsp;&nbsp;to&nbsp;allow&nbsp;`reduce`&nbsp;to&nbsp;be&nbsp;used&nbsp;to&nbsp;compute&nbsp;total&nbsp;path&nbsp;costs.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
122&nbsp;&nbsp;&nbsp;&nbsp;[from&nbsp;to&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(nil?&nbsp;to)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
124&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[edge&nbsp;(e&#x2F;edge&nbsp;from&nbsp;to)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;distance&nbsp;(e&#x2F;length&nbsp;edge)]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
127&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&#x2F;
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*&nbsp;distance
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
130&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(gradient-cost&nbsp;edge))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
131&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce&nbsp;+
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
133&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(crossing-penalty&nbsp;[%&nbsp;from&nbsp;to&nbsp;s])
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(barriers-crossed&nbsp;from&nbsp;to&nbsp;s))))
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
135&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(road-bonus&nbsp;from&nbsp;to&nbsp;s)&nbsp;1)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
136&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
137&nbsp;&nbsp;;;&nbsp;(def&nbsp;p&nbsp;&#x27;({:x&nbsp;1.40625,&nbsp;:y&nbsp;0,&nbsp;:kind&nbsp;:vertex,&nbsp;:walkmap.id&#x2F;id&nbsp;:vert_1-40625_0}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
138&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:x&nbsp;1.40625,&nbsp;:y&nbsp;-10.703125,&nbsp;:kind&nbsp;:vertex,&nbsp;:walkmap.id&#x2F;id&nbsp;:vert_1-40625_-10-703125}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
139&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:x&nbsp;7.578125,&nbsp;:y&nbsp;-10.703125,&nbsp;:kind&nbsp;:vertex,&nbsp;:walkmap.id&#x2F;id&nbsp;:vert_7-578125_-10-703125}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
140&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:x&nbsp;7.578125,&nbsp;:y&nbsp;0,&nbsp;:kind&nbsp;:vertex,&nbsp;:walkmap.id&#x2F;id&nbsp;:vert_7-578125_0}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
141&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:x&nbsp;2.171875,&nbsp;:y&nbsp;-0.765625,&nbsp;:kind&nbsp;:vertex,&nbsp;:walkmap.id&#x2F;id&nbsp;:vert_2-171875_-0-765625}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
142&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:x&nbsp;6.8125,&nbsp;:y&nbsp;-0.765625,&nbsp;:kind&nbsp;:vertex,&nbsp;:walkmap.id&#x2F;id&nbsp;:vert_6-8125_-0-765625}))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
143&nbsp;&nbsp;;;&nbsp;(v&#x2F;check-vertices&nbsp;p)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
144&nbsp;&nbsp;;;&nbsp;(def&nbsp;p&#x27;&nbsp;(p&#x2F;path&nbsp;p))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
145&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
146&nbsp;&nbsp;;;&nbsp;(traversal-cost&nbsp;(first&nbsp;p)&nbsp;(nth&nbsp;p&nbsp;1)&nbsp;{})
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
147&nbsp;&nbsp;;;&nbsp;(vertices-traversal-cost&nbsp;p&nbsp;{})
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
148&nbsp;&nbsp;;;&nbsp;(path-traversal-cost&nbsp;(p&#x2F;path&nbsp;p))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
149&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
150&nbsp;&nbsp;(defn&nbsp;extend-frontier
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
151&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;sequence&nbsp;like&nbsp;`frontier`&nbsp;with&nbsp;all&nbsp;of&nbsp;these&nbsp;`candidates`&nbsp;which&nbsp;are
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
152&nbsp;&nbsp;&nbsp;&nbsp;not&nbsp;already&nbsp;members&nbsp;either&nbsp;of&nbsp;`frontier`&nbsp;or&nbsp;of&nbsp;`rejects`&nbsp;appended.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
153&nbsp;&nbsp;&nbsp;&nbsp;([frontier&nbsp;candidates]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
154&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(extend-frontier&nbsp;frontier&nbsp;candidates&nbsp;nil))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
155&nbsp;&nbsp;&nbsp;&nbsp;([frontier&nbsp;candidates&nbsp;rejects]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
156&nbsp;&nbsp;&nbsp;&nbsp;(if
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
157&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(empty?&nbsp;frontier)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
158&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;candidates
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
159&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[fs&nbsp;(set&nbsp;(concat&nbsp;frontier&nbsp;rejects))]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
160&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(concat&nbsp;frontier&nbsp;(remove&nbsp;fs&nbsp;candidates))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
161&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
162&nbsp;&nbsp;;;&nbsp;(extend-frontier&nbsp;&#x27;(1&nbsp;2&nbsp;3&nbsp;4&nbsp;5)&nbsp;&#x27;(7&nbsp;3&nbsp;6&nbsp;2&nbsp;9&nbsp;8)&nbsp;&#x27;(6&nbsp;8))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
163&nbsp;&nbsp;;;&nbsp;(extend-frontier&nbsp;&#x27;(1&nbsp;2&nbsp;3&nbsp;4&nbsp;5)&nbsp;&#x27;(7&nbsp;3&nbsp;6&nbsp;2&nbsp;9&nbsp;8))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
164&nbsp;&nbsp;;;&nbsp;(extend-frontier&nbsp;&#x27;(1&nbsp;2&nbsp;3&nbsp;4&nbsp;5)&nbsp;&#x27;())
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
165&nbsp;&nbsp;;;&nbsp;(extend-frontier&nbsp;&#x27;(1&nbsp;2&nbsp;3&nbsp;4&nbsp;5)&nbsp;nil)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
166&nbsp;&nbsp;;;&nbsp;(extend-frontier&nbsp;nil&nbsp;&#x27;(1&nbsp;2&nbsp;3&nbsp;4&nbsp;5))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
167&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
168&nbsp;&nbsp;(defn&nbsp;route
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
169&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;NOT&nbsp;YET&nbsp;GOOD&nbsp;ENOUGH!&nbsp;Simple&nbsp;breadth&nbsp;first,&nbsp;and&nbsp;although&nbsp;it&nbsp;will
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
170&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;reach&nbsp;the&nbsp;goal
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
171&nbsp;&nbsp;&nbsp;&nbsp;([from&nbsp;to&nbsp;s&nbsp;search-radius]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
172&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(loop&nbsp;[f&nbsp;from
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
173&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t&nbsp;to
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
174&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;frontier&nbsp;(extend-frontier
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
175&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
176&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;neighbour-ids
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
177&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;nearest&nbsp;s&nbsp;from&nbsp;:centre&nbsp;search-radius)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
178&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;traversable?
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
179&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
180&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;visited&nbsp;nil
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
181&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;track&nbsp;nil]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
182&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[here&nbsp;(s&#x2F;retrieve&nbsp;(first&nbsp;frontier)&nbsp;s)]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
183&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
184&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(e&#x2F;length&nbsp;(e&#x2F;edge&nbsp;(:centre&nbsp;here))&nbsp;to)&nbsp;search-radius)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
185&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;close&nbsp;enough
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
186&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;p&#x2F;path&nbsp;(cons&nbsp;(:centre&nbsp;here)&nbsp;track))
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
187&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(empty?&nbsp;(rest&nbsp;frontier))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
188&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;failed
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
189&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
190&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
191&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(recur
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
192&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
193&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
194&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(extend-frontier
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
195&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(rest&nbsp;frontier)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
196&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;neighbour-ids&nbsp;here&nbsp;traversable?&nbsp;s)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
197&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;visited)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
198&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons&nbsp;here&nbsp;visited)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
199&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;this&nbsp;is&nbsp;going&nbsp;to&nbsp;be&nbsp;wrong,&nbsp;and&nbsp;I&nbsp;need&nbsp;to&nbsp;think&nbsp;about&nbsp;how&nbsp;to&nbsp;fix.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
200&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons&nbsp;here&nbsp;track)))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
201&nbsp;&nbsp;
</span><br/>
</body>
</html>

View file

@ -23,364 +23,604 @@
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[org.clojars.smee.binary.core&nbsp;:as&nbsp;b]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l&nbsp;:refer&nbsp;[info&nbsp;error&nbsp;spy]]
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.polygon&nbsp;:refer&nbsp;[polygon?]])
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.edge&nbsp;:as&nbsp;e]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;(:import&nbsp;org.clojars.smee.binary.core.BinaryIO
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.ocean&nbsp;:as&nbsp;o]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.io.DataInput))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
011&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
012&nbsp;&nbsp;(defn&nbsp;stl?
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.polygon&nbsp;:refer&nbsp;[centre&nbsp;gradient&nbsp;polygon?]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;is&nbsp;recogniseable&nbsp;as&nbsp;an&nbsp;STL&nbsp;structure.&nbsp;An&nbsp;STL&nbsp;structure&nbsp;must
011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.superstructure&nbsp;:refer&nbsp;[store]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;have&nbsp;a&nbsp;key&nbsp;`:facets`,&nbsp;whose&nbsp;value&nbsp;must&nbsp;be&nbsp;a&nbsp;sequence&nbsp;of&nbsp;polygons;&nbsp;and
012&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.tag&nbsp;:refer&nbsp;[tag]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;may&nbsp;have&nbsp;a&nbsp;key&nbsp;`:header`&nbsp;whose&nbsp;value&nbsp;should&nbsp;be&nbsp;a&nbsp;string,&nbsp;and&#x2F;or&nbsp;a&nbsp;key
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.utils&nbsp;:as&nbsp;u]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;`:count`,&nbsp;whose&nbsp;value&nbsp;should&nbsp;be&nbsp;a&nbsp;positive&nbsp;integer.
014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:as&nbsp;v])
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;(:import&nbsp;org.clojars.smee.binary.core.BinaryIO
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.io.DataInput))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
017&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;`verify-count?`&nbsp;is&nbsp;passed&nbsp;and&nbsp;is&nbsp;not&nbsp;`false`,&nbsp;verify&nbsp;that&nbsp;the&nbsp;value&nbsp;of
<span class="covered" title="1 out of 1 forms covered">
018&nbsp;&nbsp;(defn&nbsp;stl?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;`:count`&nbsp;header&nbsp;is&nbsp;equal&nbsp;to&nbsp;the&nbsp;number&nbsp;of&nbsp;facets.&quot;
019&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;is&nbsp;recogniseable&nbsp;as&nbsp;an&nbsp;STL&nbsp;structure.&nbsp;An&nbsp;STL&nbsp;structure&nbsp;must
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;([o]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(stl?&nbsp;o&nbsp;false))
020&nbsp;&nbsp;&nbsp;&nbsp;have&nbsp;a&nbsp;key&nbsp;`:facets`,&nbsp;whose&nbsp;value&nbsp;must&nbsp;be&nbsp;a&nbsp;sequence&nbsp;of&nbsp;polygons;&nbsp;and
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;([o&nbsp;verify-count?]
021&nbsp;&nbsp;&nbsp;&nbsp;may&nbsp;have&nbsp;a&nbsp;key&nbsp;`:header`&nbsp;whose&nbsp;value&nbsp;should&nbsp;be&nbsp;a&nbsp;string,&nbsp;and&#x2F;or&nbsp;a&nbsp;key
</span><br/>
<span class="not-covered" title="0 out of 22 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;o)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;o)
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?&nbsp;polygon?&nbsp;(:facets&nbsp;o))
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(:header&nbsp;o)&nbsp;(string?&nbsp;(:header&nbsp;o))&nbsp;true)
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(:count&nbsp;o)&nbsp;(integer?&nbsp;(:count&nbsp;o))&nbsp;true)
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;verify-count?&nbsp;(=&nbsp;(:count&nbsp;o)&nbsp;(count&nbsp;(:facets&nbsp;o)))&nbsp;true))))
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;`:count`,&nbsp;whose&nbsp;value&nbsp;should&nbsp;be&nbsp;a&nbsp;positive&nbsp;integer.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
030&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
031&nbsp;&nbsp;(def&nbsp;vect
023&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;&quot;A&nbsp;codec&nbsp;for&nbsp;vectors&nbsp;within&nbsp;a&nbsp;binary&nbsp;STL&nbsp;file.&quot;
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;(b&#x2F;ordered-map
024&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;`verify-count?`&nbsp;is&nbsp;passed&nbsp;and&nbsp;is&nbsp;not&nbsp;`false`,&nbsp;verify&nbsp;that&nbsp;the&nbsp;value&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:x&nbsp;:float-le
025&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;`:count`&nbsp;header&nbsp;is&nbsp;equal&nbsp;to&nbsp;the&nbsp;number&nbsp;of&nbsp;facets.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:y&nbsp;:float-le
026&nbsp;&nbsp;&nbsp;&nbsp;([o]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(stl?&nbsp;o&nbsp;false))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:z&nbsp;:float-le))
028&nbsp;&nbsp;&nbsp;&nbsp;([o&nbsp;verify-count?]
</span><br/>
<span class="partial" title="20 out of 26 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;o)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;o)
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?&nbsp;polygon?&nbsp;(:facets&nbsp;o))
</span><br/>
<span class="partial" title="9 out of 10 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(:header&nbsp;o)&nbsp;(string?&nbsp;(:header&nbsp;o))&nbsp;true)
</span><br/>
<span class="partial" title="9 out of 10 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(:count&nbsp;o)&nbsp;(integer?&nbsp;(:count&nbsp;o))&nbsp;true)
</span><br/>
<span class="partial" title="14 out of 15 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(nil?&nbsp;(:kind&nbsp;o))&nbsp;(=&nbsp;(:kind&nbsp;o)&nbsp;:stl))
</span><br/>
<span class="partial" title="1 out of 11 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;verify-count?&nbsp;(=&nbsp;(:count&nbsp;o)&nbsp;(count&nbsp;(:facets&nbsp;o)))&nbsp;true))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
037&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
038&nbsp;&nbsp;(def&nbsp;facet
038&nbsp;&nbsp;(def&nbsp;vect
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&quot;A&nbsp;codec&nbsp;for&nbsp;a&nbsp;facet&nbsp;(triangle)&nbsp;within&nbsp;a&nbsp;binary&nbsp;STL&nbsp;file.&quot;
039&nbsp;&nbsp;&nbsp;&nbsp;&quot;A&nbsp;codec&nbsp;for&nbsp;vectors&nbsp;within&nbsp;a&nbsp;binary&nbsp;STL&nbsp;file.&quot;
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
<span class="covered" title="8 out of 8 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;(b&#x2F;ordered-map
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:normal&nbsp;vect
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:vertices&nbsp;[vect&nbsp;vect&nbsp;vect]
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:x&nbsp;:float-le
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:abc&nbsp;:ushort-le))
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:y&nbsp;:float-le
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:z&nbsp;:float-le))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
044&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
045&nbsp;&nbsp;(def&nbsp;binary-stl
045&nbsp;&nbsp;(def&nbsp;facet
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&quot;A&nbsp;codec&nbsp;for&nbsp;binary&nbsp;STL&nbsp;files&quot;
046&nbsp;&nbsp;&nbsp;&nbsp;&quot;A&nbsp;codec&nbsp;for&nbsp;a&nbsp;facet&nbsp;(triangle)&nbsp;within&nbsp;a&nbsp;binary&nbsp;STL&nbsp;file.&quot;
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;(b&#x2F;ordered-map
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:header&nbsp;(b&#x2F;string&nbsp;&quot;ISO-8859-1&quot;&nbsp;:length&nbsp;80)&nbsp;;;&nbsp;for&nbsp;the&nbsp;time&nbsp;being&nbsp;we&nbsp;neither&nbsp;know&nbsp;nor&nbsp;care&nbsp;what&#x27;s&nbsp;in&nbsp;this.
<span class="covered" title="1 out of 1 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:normal&nbsp;vect
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:vertices&nbsp;[vect&nbsp;vect&nbsp;vect]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:count&nbsp;:uint-le
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:facets&nbsp;(b&#x2F;repeated&nbsp;facet)))
050&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:abc&nbsp;:ushort-le))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
051&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
052&nbsp;&nbsp;(defn&nbsp;decode-binary-stl
052&nbsp;&nbsp;(def&nbsp;binary-stl
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;&quot;Parse&nbsp;a&nbsp;binary&nbsp;STL&nbsp;file&nbsp;from&nbsp;this&nbsp;`filename`&nbsp;and&nbsp;return&nbsp;an&nbsp;STL&nbsp;structure
053&nbsp;&nbsp;&nbsp;&nbsp;&quot;A&nbsp;codec&nbsp;for&nbsp;binary&nbsp;STL&nbsp;files&quot;
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;(b&#x2F;ordered-map
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:header&nbsp;(b&#x2F;string&nbsp;&quot;ISO-8859-1&quot;&nbsp;:length&nbsp;80)&nbsp;;;&nbsp;for&nbsp;the&nbsp;time&nbsp;being&nbsp;we&nbsp;neither&nbsp;know&nbsp;nor&nbsp;care&nbsp;what&#x27;s&nbsp;in&nbsp;this.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;representing&nbsp;its&nbsp;contents.
056&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:count&nbsp;:uint-le
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:facets&nbsp;(b&#x2F;repeated&nbsp;facet)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
055&nbsp;&nbsp;
058&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
059&nbsp;&nbsp;(defn&nbsp;canonicalise
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;**NOTE**&nbsp;that&nbsp;we&#x27;ve&nbsp;no&nbsp;way&nbsp;of&nbsp;verifying&nbsp;that&nbsp;the&nbsp;input&nbsp;file&nbsp;is&nbsp;binary&nbsp;STL
060&nbsp;&nbsp;&nbsp;&nbsp;&quot;Objects&nbsp;read&nbsp;in&nbsp;from&nbsp;STL&nbsp;won&#x27;t&nbsp;have&nbsp;all&nbsp;the&nbsp;keys&#x2F;values&nbsp;we&nbsp;need&nbsp;them&nbsp;to&nbsp;have.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;data,&nbsp;if&nbsp;it&nbsp;is&nbsp;not&nbsp;this&nbsp;will&nbsp;run&nbsp;but&nbsp;will&nbsp;return&nbsp;garbage.&quot;
061&nbsp;&nbsp;&nbsp;&nbsp;`o`&nbsp;may&nbsp;be&nbsp;a&nbsp;map&nbsp;(representing&nbsp;a&nbsp;facet&nbsp;or&nbsp;a&nbsp;vertex),&nbsp;or&nbsp;a&nbsp;sequence&nbsp;of&nbsp;such&nbsp;maps;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;[filename]
062&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;it&nbsp;isn&#x27;t&nbsp;recognised&nbsp;it&nbsp;is&nbsp;at&nbsp;present&nbsp;just&nbsp;returned&nbsp;unchanged.&nbsp;`map-kind`,&nbsp;if
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[in&nbsp;(io&#x2F;input-stream&nbsp;filename)]
<span class="not-tracked" title="0 out of 0 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;passed,&nbsp;must&nbsp;be&nbsp;a&nbsp;keyword&nbsp;indicating&nbsp;the&nbsp;value&nbsp;represented&nbsp;by&nbsp;the&nbsp;`z`&nbsp;axis
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(b&#x2F;decode&nbsp;binary-stl&nbsp;in)))
<span class="not-tracked" title="0 out of 0 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;(defaults&nbsp;to&nbsp;`:height`).&nbsp;It&nbsp;is&nbsp;an&nbsp;error,&nbsp;and&nbsp;an&nbsp;exception&nbsp;will&nbsp;be&nbsp;thrown,&nbsp;if
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
061&nbsp;&nbsp;
<span class="not-tracked" title="0 out of 0 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;`map-kind`&nbsp;is&nbsp;not&nbsp;a&nbsp;keyword.&quot;
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;([o]&nbsp;(canonicalise&nbsp;o&nbsp;:height))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;([o&nbsp;map-kind]
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(canonicalise&nbsp;o&nbsp;map-kind&nbsp;(v&#x2F;vertex&nbsp;1&nbsp;1&nbsp;1)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;([o&nbsp;map-kind&nbsp;scale-vertex]
</span><br/>
<span class="partial" title="2 out of 3 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when-not
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(keyword?&nbsp;map-kind)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-covered" title="0 out of 12 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(u&#x2F;truncate&nbsp;(str&nbsp;&quot;Must&nbsp;be&nbsp;a&nbsp;keyword:&nbsp;&quot;&nbsp;(or&nbsp;map-kind&nbsp;&quot;nil&quot;))&nbsp;80))))
</span><br/>
<span class="partial" title="4 out of 5 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="partial" title="19 out of 20 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(coll?&nbsp;o)&nbsp;(not&nbsp;(map?&nbsp;o)))&nbsp;(map&nbsp;#(canonicalise&nbsp;%&nbsp;map-kind)&nbsp;o)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;if&nbsp;it&nbsp;has&nbsp;:facets&nbsp;it&#x27;s&nbsp;an&nbsp;STL&nbsp;structure,&nbsp;but&nbsp;it&nbsp;doesn&#x27;t&nbsp;yet&nbsp;conform&nbsp;to&nbsp;`stl?`
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;o)&nbsp;(assoc&nbsp;o
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:kind&nbsp;:stl
</span><br/>
<span class="partial" title="11 out of 12 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:walkmap.id&#x2F;id&nbsp;(or&nbsp;(:walkmap.id&#x2F;id&nbsp;o)&nbsp;(keyword&nbsp;(gensym&nbsp;&quot;stl&quot;)))
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:facets&nbsp;(canonicalise&nbsp;(:facets&nbsp;o)&nbsp;map-kind))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;if&nbsp;it&nbsp;has&nbsp;:vertices&nbsp;it&#x27;s&nbsp;a&nbsp;polygon,&nbsp;but&nbsp;it&nbsp;may&nbsp;not&nbsp;yet&nbsp;conform&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;`polygon?`
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:vertices&nbsp;o)&nbsp;(let&nbsp;[f&nbsp;(gradient
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
062&nbsp;&nbsp;(defn-&nbsp;vect-&gt;str&nbsp;[prefix&nbsp;v]
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(centre
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(tag
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;o
</span><br/>
<span class="partial" title="4 out of 5 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:walkmap.id&#x2F;id&nbsp;(or
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:walkmap.id&#x2F;id&nbsp;o)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(keyword&nbsp;(gensym&nbsp;&quot;poly&quot;)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:kind&nbsp;:polygon
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:vertices&nbsp;(canonicalise
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:vertices&nbsp;o)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map-kind))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:facet&nbsp;map-kind)))]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(o&#x2F;ocean?&nbsp;f)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(tag&nbsp;f&nbsp;:ocean&nbsp;:no-traversal)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;if&nbsp;it&nbsp;has&nbsp;a&nbsp;value&nbsp;for&nbsp;:x&nbsp;it&#x27;s&nbsp;a&nbsp;vertex,&nbsp;but&nbsp;it&nbsp;may&nbsp;not&nbsp;yet&nbsp;conform
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;to&nbsp;`vertex?`;&nbsp;it&nbsp;should&nbsp;also&nbsp;be&nbsp;scaled&nbsp;using&nbsp;the&nbsp;scale-vertex,&nbsp;if&nbsp;any.
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:x&nbsp;o)&nbsp;(let&nbsp;[c&nbsp;(v&#x2F;canonicalise&nbsp;o)]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;scale-vertex
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(v&#x2F;vertex*&nbsp;c&nbsp;scale-vertex)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;shouldn&#x27;t&nbsp;happen
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else&nbsp;o)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
106&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
107&nbsp;&nbsp;(defn&nbsp;decode-binary-stl
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&quot;Parse&nbsp;a&nbsp;binary&nbsp;STL&nbsp;file&nbsp;from&nbsp;this&nbsp;`filename`&nbsp;and&nbsp;return&nbsp;an&nbsp;STL&nbsp;structure
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;representing&nbsp;its&nbsp;contents.&nbsp;`map-kind`,&nbsp;if&nbsp;passed,&nbsp;must&nbsp;be&nbsp;a&nbsp;keyword
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;or&nbsp;sequence&nbsp;of&nbsp;keywords&nbsp;indicating&nbsp;the&nbsp;semantic&nbsp;value&nbsp;represented&nbsp;by&nbsp;the&nbsp;`z`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;axis&nbsp;(defaults&nbsp;to&nbsp;`:height`).
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
112&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;`superstructure`&nbsp;is&nbsp;supplied&nbsp;and&nbsp;is&nbsp;a&nbsp;map,&nbsp;the&nbsp;generated&nbsp;STL&nbsp;structure
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;will&nbsp;be&nbsp;stored&nbsp;in&nbsp;that&nbsp;superstructure,&nbsp;which&nbsp;will&nbsp;be&nbsp;returned.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
115&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;`scale-vertex`&nbsp;is&nbsp;supplied,&nbsp;it&nbsp;must&nbsp;be&nbsp;a&nbsp;three&nbsp;dimensional&nbsp;vertex&nbsp;(i.e.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;`:z`&nbsp;key&nbsp;must&nbsp;have&nbsp;a&nbsp;numeric&nbsp;value)&nbsp;representing&nbsp;the&nbsp;amount&nbsp;by&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;each&nbsp;of&nbsp;the&nbsp;vertices&nbsp;read&nbsp;from&nbsp;the&nbsp;STL&nbsp;will&nbsp;be&nbsp;scaled.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
119&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
120&nbsp;&nbsp;&nbsp;&nbsp;It&nbsp;is&nbsp;an&nbsp;error,&nbsp;and&nbsp;an&nbsp;exception&nbsp;will&nbsp;be&nbsp;thrown,&nbsp;if&nbsp;`map-kind`&nbsp;is&nbsp;not&nbsp;a
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
121&nbsp;&nbsp;&nbsp;&nbsp;keyword&nbsp;or&nbsp;sequence&nbsp;of&nbsp;keywords.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
122&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;**NOTE**&nbsp;that&nbsp;we&#x27;ve&nbsp;no&nbsp;way&nbsp;of&nbsp;verifying&nbsp;that&nbsp;the&nbsp;input&nbsp;file&nbsp;is&nbsp;binary&nbsp;STL
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
124&nbsp;&nbsp;&nbsp;&nbsp;data,&nbsp;if&nbsp;it&nbsp;is&nbsp;not&nbsp;this&nbsp;will&nbsp;run&nbsp;but&nbsp;will&nbsp;return&nbsp;garbage.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;([filename]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(decode-binary-stl&nbsp;filename&nbsp;:height))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
127&nbsp;&nbsp;&nbsp;&nbsp;([filename&nbsp;map-kind]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when-not
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(keyword?&nbsp;map-kind)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
130&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-covered" title="0 out of 12 forms covered">
131&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(u&#x2F;truncate&nbsp;(str&nbsp;&quot;Must&nbsp;be&nbsp;a&nbsp;keyword:&nbsp;&quot;&nbsp;(or&nbsp;map-kind&nbsp;&quot;nil&quot;))&nbsp;80))))
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(decode-binary-stl&nbsp;filename&nbsp;map-kind&nbsp;nil))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
133&nbsp;&nbsp;&nbsp;&nbsp;([filename&nbsp;mapkind&nbsp;superstucture]
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(decode-binary-stl&nbsp;filename&nbsp;mapkind&nbsp;superstucture&nbsp;(v&#x2F;vertex&nbsp;1&nbsp;1&nbsp;1)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
135&nbsp;&nbsp;&nbsp;&nbsp;([filename&nbsp;map-kind&nbsp;superstructure&nbsp;scale-vertex]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
136&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[in&nbsp;(io&#x2F;input-stream&nbsp;filename)
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
137&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stl&nbsp;(canonicalise&nbsp;(b&#x2F;decode&nbsp;binary-stl&nbsp;in)&nbsp;map-kind&nbsp;scale-vertex)]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
138&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
139&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;superstructure)
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
140&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(store&nbsp;stl&nbsp;superstructure)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
141&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stl))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
142&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
143&nbsp;&nbsp;(defn-&nbsp;vect-&gt;str&nbsp;[prefix&nbsp;v]
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;prefix&nbsp;&quot;&nbsp;&quot;&nbsp;(:x&nbsp;v)&nbsp;&quot;&nbsp;&quot;&nbsp;(:y&nbsp;v)&nbsp;&quot;&nbsp;&quot;&nbsp;(:z&nbsp;v)&nbsp;&quot;\n&quot;))
144&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;prefix&nbsp;&quot;&nbsp;&quot;&nbsp;(:x&nbsp;v)&nbsp;&quot;&nbsp;&quot;&nbsp;(:y&nbsp;v)&nbsp;&quot;&nbsp;&quot;&nbsp;(:z&nbsp;v)&nbsp;&quot;\n&quot;))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
064&nbsp;&nbsp;
145&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
065&nbsp;&nbsp;(defn-&nbsp;facet2str&nbsp;[tri]
146&nbsp;&nbsp;(defn-&nbsp;facet2str&nbsp;[tri]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;(str
147&nbsp;&nbsp;&nbsp;&nbsp;(str
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vect-&gt;str&nbsp;&quot;facet&nbsp;normal&quot;&nbsp;(:normal&nbsp;tri))
148&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vect-&gt;str&nbsp;&quot;facet&nbsp;normal&quot;&nbsp;(:normal&nbsp;tri))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;outer&nbsp;loop\n&quot;
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;outer&nbsp;loop\n&quot;
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;join
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;str
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
151&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(vect-&gt;str&nbsp;&quot;vertex&quot;&nbsp;%)
152&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(vect-&gt;str&nbsp;&quot;vertex&quot;&nbsp;%)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:vertices&nbsp;tri)))
153&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:vertices&nbsp;tri)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;endloop\nendfacet\n&quot;))
154&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;endloop\nendfacet\n&quot;))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
074&nbsp;&nbsp;
155&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
075&nbsp;&nbsp;(defn&nbsp;stl-&gt;ascii
156&nbsp;&nbsp;(defn&nbsp;stl-&gt;ascii
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;as&nbsp;a&nbsp;string&nbsp;an&nbsp;ASCII&nbsp;rendering&nbsp;of&nbsp;the&nbsp;`stl`&nbsp;structure.&quot;
157&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;as&nbsp;a&nbsp;string&nbsp;an&nbsp;ASCII&nbsp;rendering&nbsp;of&nbsp;the&nbsp;`stl`&nbsp;structure.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;([stl]
158&nbsp;&nbsp;&nbsp;&nbsp;([stl]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(stl-&gt;ascii&nbsp;stl&nbsp;&quot;unknown&quot;))
159&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(stl-&gt;ascii&nbsp;stl&nbsp;&quot;unknown&quot;))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;([stl&nbsp;solidname]
160&nbsp;&nbsp;&nbsp;&nbsp;([stl&nbsp;solidname]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str
161&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;solid&nbsp;&quot;
162&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;solid&nbsp;&quot;
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;solidname
163&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;solidname
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;trim&nbsp;(:header&nbsp;stl))
164&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;trim&nbsp;(:header&nbsp;stl))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;\n&quot;
165&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;\n&quot;
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;str
166&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;join
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
167&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;facet2str
168&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;facet2str
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl)))
169&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;endsolid&nbsp;&quot;
170&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;endsolid&nbsp;&quot;
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;solidname
171&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;solidname
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;\n&quot;)))
172&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;\n&quot;)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
093&nbsp;&nbsp;
173&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
094&nbsp;&nbsp;(defn&nbsp;write-ascii-stl
174&nbsp;&nbsp;(defn&nbsp;write-ascii-stl
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;&quot;Write&nbsp;an&nbsp;`stl`&nbsp;structure&nbsp;as&nbsp;read&nbsp;by&nbsp;`decode-binary-stl`&nbsp;to&nbsp;this
175&nbsp;&nbsp;&nbsp;&nbsp;&quot;Write&nbsp;an&nbsp;`stl`&nbsp;structure&nbsp;as&nbsp;read&nbsp;by&nbsp;`decode-binary-stl`&nbsp;to&nbsp;this
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;`filename`&nbsp;as&nbsp;ASCII&nbsp;encoded&nbsp;STL.&quot;
176&nbsp;&nbsp;&nbsp;&nbsp;`filename`&nbsp;as&nbsp;ASCII&nbsp;encoded&nbsp;STL.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;([filename&nbsp;stl]
177&nbsp;&nbsp;&nbsp;&nbsp;([filename&nbsp;stl]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[b&nbsp;(fs&#x2F;base-name&nbsp;filename&nbsp;true)]
178&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[b&nbsp;(fs&#x2F;base-name&nbsp;filename&nbsp;true)]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(write-ascii-stl
179&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(write-ascii-stl
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filename&nbsp;stl
180&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filename&nbsp;stl
</span><br/>
<span class="not-covered" title="0 out of 15 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(subs&nbsp;b&nbsp;0&nbsp;(or&nbsp;(s&#x2F;index-of&nbsp;b&nbsp;&quot;.&quot;)&nbsp;(count&nbsp;b))))))
181&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(subs&nbsp;b&nbsp;0&nbsp;(or&nbsp;(s&#x2F;index-of&nbsp;b&nbsp;&quot;.&quot;)&nbsp;(count&nbsp;b))))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;([filename&nbsp;stl&nbsp;solidname]
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;debug&nbsp;&quot;Solid&nbsp;name&nbsp;is&nbsp;&quot;&nbsp;solidname)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(spit
182&nbsp;&nbsp;&nbsp;&nbsp;([filename&nbsp;stl&nbsp;solidname]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filename
183&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;debug&nbsp;&quot;Solid&nbsp;name&nbsp;is&nbsp;&quot;&nbsp;solidname)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
184&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(spit
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
185&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filename
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(stl-&gt;ascii&nbsp;stl&nbsp;solidname))))
186&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(stl-&gt;ascii&nbsp;stl&nbsp;solidname))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
107&nbsp;&nbsp;
187&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
108&nbsp;&nbsp;(defn&nbsp;binary-stl-to-ascii
188&nbsp;&nbsp;(defn&nbsp;binary-stl-to-ascii
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&quot;Convert&nbsp;the&nbsp;binary&nbsp;STL&nbsp;file&nbsp;indicated&nbsp;by&nbsp;`in-filename`,&nbsp;and&nbsp;write&nbsp;it&nbsp;to
189&nbsp;&nbsp;&nbsp;&nbsp;&quot;Convert&nbsp;the&nbsp;binary&nbsp;STL&nbsp;file&nbsp;indicated&nbsp;by&nbsp;`in-filename`,&nbsp;and&nbsp;write&nbsp;it&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;`out-filename`,&nbsp;if&nbsp;specified;&nbsp;otherwise,&nbsp;to&nbsp;a&nbsp;file&nbsp;with&nbsp;the&nbsp;same&nbsp;basename
190&nbsp;&nbsp;&nbsp;&nbsp;`out-filename`,&nbsp;if&nbsp;specified;&nbsp;otherwise,&nbsp;to&nbsp;a&nbsp;file&nbsp;with&nbsp;the&nbsp;same&nbsp;basename
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;as&nbsp;`in-filename`&nbsp;but&nbsp;the&nbsp;extension&nbsp;`.ascii.stl`.&quot;
191&nbsp;&nbsp;&nbsp;&nbsp;as&nbsp;`in-filename`&nbsp;but&nbsp;the&nbsp;extension&nbsp;`.ascii.stl`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;([in-filename]
192&nbsp;&nbsp;&nbsp;&nbsp;([in-filename]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[[_&nbsp;ext]&nbsp;(fs&#x2F;split-ext&nbsp;in-filename)]
193&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[[_&nbsp;ext]&nbsp;(fs&#x2F;split-ext&nbsp;in-filename)]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(binary-stl-to-ascii
194&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(binary-stl-to-ascii
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in-filename
195&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in-filename
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str
196&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(subs
197&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(subs
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in-filename
198&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in-filename
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0
199&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
120&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or
200&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
121&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;last-index-of&nbsp;in-filename&nbsp;&quot;.&quot;)
201&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;last-index-of&nbsp;in-filename&nbsp;&quot;.&quot;)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
122&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(count&nbsp;in-filename)))
202&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(count&nbsp;in-filename)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;.ascii&quot;
203&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;.ascii&quot;
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
124&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ext))))
204&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ext))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;([in-filename&nbsp;out-filename]
205&nbsp;&nbsp;&nbsp;&nbsp;([in-filename&nbsp;out-filename]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(write-ascii-stl&nbsp;out-filename&nbsp;(decode-binary-stl&nbsp;in-filename))))
206&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(write-ascii-stl&nbsp;out-filename&nbsp;(decode-binary-stl&nbsp;in-filename))))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,824 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> walkmap/superstructure.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;walkmap.superstructure
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;single&nbsp;indexing&nbsp;structure&nbsp;for&nbsp;walkmap&nbsp;objects&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.walk&nbsp;:refer&nbsp;[postwalk]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.edge&nbsp;:refer&nbsp;[edge&nbsp;length]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.path&nbsp;:as&nbsp;p]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.polygon&nbsp;:as&nbsp;q]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.utils&nbsp;:as&nbsp;u]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:as&nbsp;v]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
010&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;;;&nbsp;TODO:&nbsp;Think&nbsp;about&nbsp;reification&#x2F;dereification.&nbsp;How&nbsp;can&nbsp;we&nbsp;cull&nbsp;a&nbsp;polygon,&nbsp;if
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;;;&nbsp;some&nbsp;vertices&nbsp;still&nbsp;index&nbsp;it?&nbsp;I&nbsp;*think*&nbsp;that&nbsp;what&#x27;s&nbsp;needed&nbsp;is&nbsp;that&nbsp;when
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;;;&nbsp;we&nbsp;store&nbsp;something&nbsp;in&nbsp;the&nbsp;superstructure,&nbsp;we&nbsp;replace&nbsp;all&nbsp;its&nbsp;vertices&nbsp;(and
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;;;&nbsp;other&nbsp;dependent&nbsp;structures,&nbsp;if&nbsp;any&nbsp;with&nbsp;their&nbsp;ids&nbsp;-&nbsp;as&nbsp;well&nbsp;as,&nbsp;obviously,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;;;&nbsp;adding&#x2F;merging&nbsp;those&nbsp;vertices&#x2F;dependent&nbsp;structures&nbsp;into&nbsp;the&nbsp;superstructure
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;;;&nbsp;as&nbsp;first&nbsp;class&nbsp;objects&nbsp;in&nbsp;themselves.&nbsp;That&nbsp;means,&nbsp;for&nbsp;each&nbsp;identified&nbsp;thing,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;;;&nbsp;the&nbsp;superstructure&nbsp;only&nbsp;contains&nbsp;one&nbsp;copy&nbsp;of&nbsp;it.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;;;&nbsp;The&nbsp;question&nbsp;then&nbsp;is,&nbsp;when&nbsp;we&nbsp;want&nbsp;to&nbsp;do&nbsp;things&nbsp;with&nbsp;those&nbsp;objects,&nbsp;do&nbsp;we
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;;;&nbsp;exteract&nbsp;a&nbsp;copy&nbsp;with&nbsp;its&nbsp;dependent&nbsp;structures&nbsp;fixed&nbsp;back&nbsp;up&nbsp;(reification),
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;;;&nbsp;or&nbsp;do&nbsp;we&nbsp;indirect&nbsp;through&nbsp;the&nbsp;superstructure&nbsp;every&nbsp;time&nbsp;we&nbsp;want&nbsp;to&nbsp;access
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;;;&nbsp;them?&nbsp;In&nbsp;a&nbsp;sense,&nbsp;the&nbsp;copy&nbsp;in&nbsp;the&nbsp;superstructure&nbsp;is&nbsp;the&nbsp;&#x27;one&nbsp;true&nbsp;copy&#x27;,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;;;&nbsp;but&nbsp;it&nbsp;may&nbsp;become&nbsp;very&nbsp;difficult&nbsp;then&nbsp;to&nbsp;have&nbsp;one&nbsp;true&nbsp;copy&nbsp;of&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;;;&nbsp;superstructure&nbsp;-&nbsp;unless&nbsp;we&nbsp;replace&nbsp;the&nbsp;superstructure&nbsp;altogether&nbsp;with&nbsp;a
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;;;&nbsp;database,&nbsp;which&nbsp;may&nbsp;be&nbsp;the&nbsp;Right&nbsp;Thing&nbsp;To&nbsp;Do.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
026&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
027&nbsp;&nbsp;(def&nbsp;vertex-index&nbsp;::vertex-index)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
028&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
029&nbsp;&nbsp;(defn&nbsp;vertices
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;an&nbsp;object&nbsp;with&nbsp;vertices,&nbsp;return&nbsp;those&nbsp;vertices,&nbsp;else&nbsp;nil.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;(when&nbsp;(map?&nbsp;o)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;concat
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(remove
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil?
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(cond
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(v&#x2F;vertex?&nbsp;%)&nbsp;(list&nbsp;%)
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(coll?&nbsp;%)&nbsp;(every?&nbsp;v&#x2F;vertex?&nbsp;%))&nbsp;%)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vals&nbsp;o))))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(v&#x2F;vertex?&nbsp;o)&nbsp;(list&nbsp;o)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
044&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(q&#x2F;polygon?&nbsp;o)&nbsp;(:vertices&nbsp;o)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
045&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(p&#x2F;path?&nbsp;o)&nbsp;(:vertices&nbsp;o))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
046&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
047&nbsp;&nbsp;
</span><br/>
<span class="partial" title="1 out of 5 forms covered">
048&nbsp;&nbsp;(defn&nbsp;index-vertex
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;superstructure&nbsp;like&nbsp;`s`&nbsp;in&nbsp;which&nbsp;object&nbsp;`o`&nbsp;is&nbsp;indexed&nbsp;by&nbsp;vertex
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;`v`.&nbsp;It&nbsp;is&nbsp;an&nbsp;error&nbsp;(and&nbsp;an&nbsp;exception&nbsp;may&nbsp;be&nbsp;thrown)&nbsp;if
</span><br/>
<span class="blank" title="0 out of 2 forms covered">
051&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;`s`&nbsp;is&nbsp;not&nbsp;a&nbsp;map;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;map;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;3.&nbsp;`o`&nbsp;does&nbsp;not&nbsp;have&nbsp;a&nbsp;value&nbsp;for&nbsp;the&nbsp;key&nbsp;`:walkmap.id&#x2F;id`;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;4.&nbsp;`v`&nbsp;is&nbsp;not&nbsp;a&nbsp;vertex.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;[s&nbsp;o&nbsp;v]
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;(if-not&nbsp;(v&#x2F;vertex?&nbsp;o)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(:walkmap.id&#x2F;id&nbsp;o)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(v&#x2F;vertex?&nbsp;v)
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[vi&nbsp;(or&nbsp;(::vertex-index&nbsp;s)&nbsp;{})
</span><br/>
<span class="partial" title="9 out of 10 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current&nbsp;(or&nbsp;(vi&nbsp;(:walkmap.id&#x2F;id&nbsp;v))&nbsp;{})]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;deep-merge&nbsp;doesn&#x27;t&nbsp;merge&nbsp;sets,&nbsp;only&nbsp;maps;&nbsp;so&nbsp;at&nbsp;this
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;stage&nbsp;we&nbsp;need&nbsp;to&nbsp;build&nbsp;a&nbsp;map.
</span><br/>
<span class="covered" title="15 out of 15 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;vi&nbsp;(:walkmap.id&#x2F;id&nbsp;v)&nbsp;(assoc&nbsp;current&nbsp;(:walkmap.id&#x2F;id&nbsp;o)&nbsp;(:walkmap.id&#x2F;id&nbsp;v))))
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.&nbsp;&quot;Not&nbsp;a&nbsp;vertex:&nbsp;&quot;&nbsp;v)))
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.&nbsp;(u&#x2F;truncate&nbsp;(str&nbsp;&quot;No&nbsp;`:walkmap.id&#x2F;id`&nbsp;value:&nbsp;&quot;&nbsp;o)&nbsp;80))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;it&nbsp;shouldn&#x27;t&nbsp;actually&nbsp;be&nbsp;an&nbsp;error&nbsp;to&nbsp;try&nbsp;to&nbsp;index&nbsp;a&nbsp;vertex,&nbsp;but&nbsp;it
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;also&nbsp;isn&#x27;t&nbsp;useful&nbsp;to&nbsp;do&nbsp;so,&nbsp;so&nbsp;I&#x27;d&nbsp;be&nbsp;inclined&nbsp;to&nbsp;ignore&nbsp;it.
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(::vertex-index&nbsp;s)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
070&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
071&nbsp;&nbsp;(defn&nbsp;index-vertices
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;superstructure&nbsp;like&nbsp;`s`&nbsp;in&nbsp;which&nbsp;object&nbsp;`o`&nbsp;is&nbsp;indexed&nbsp;by&nbsp;its
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;vertices.&nbsp;It&nbsp;is&nbsp;an&nbsp;error&nbsp;(and&nbsp;an&nbsp;exception&nbsp;may&nbsp;be&nbsp;thrown)&nbsp;if
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
074&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;`s`&nbsp;is&nbsp;not&nbsp;a&nbsp;map;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;map;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;3.&nbsp;`o`&nbsp;does&nbsp;not&nbsp;have&nbsp;a&nbsp;value&nbsp;for&nbsp;the&nbsp;key&nbsp;`:walkmap.id&#x2F;id`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;[s&nbsp;o]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;(u&#x2F;deep-merge
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{::vertex-index
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u&#x2F;deep-merge
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{}
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(index-vertex&nbsp;s&nbsp;o&nbsp;%)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:vertices&nbsp;o)))}))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
088&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
089&nbsp;&nbsp;(defn&nbsp;in-retrieve
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&quot;Internal&nbsp;guts&nbsp;of&nbsp;`retrieve`,&nbsp;q.v.&nbsp;`x`&nbsp;can&nbsp;be&nbsp;anything;&nbsp;`s`&nbsp;must&nbsp;be&nbsp;a
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;walkmap&nbsp;superstructure.&nbsp;TODO:&nbsp;recursive,&nbsp;quite&nbsp;likely&nbsp;to&nbsp;blow&nbsp;the&nbsp;fragile
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;Clojure&nbsp;stack.&nbsp;Probably&nbsp;better&nbsp;to&nbsp;do&nbsp;this&nbsp;with&nbsp;`walk`,&nbsp;but&nbsp;I&nbsp;don&#x27;t&nbsp;yet
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;understand&nbsp;that.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;[x&nbsp;s]
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;if&nbsp;it&#x27;s&nbsp;a&nbsp;keyword&nbsp;identifying&nbsp;something&nbsp;in&nbsp;s,&nbsp;retrieve&nbsp;that&nbsp;something.
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(keyword?&nbsp;x)&nbsp;(if&nbsp;(s&nbsp;x)
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(in-retrieve&nbsp;(s&nbsp;x)&nbsp;s)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;if&nbsp;it&#x27;s&nbsp;a&nbsp;map,&nbsp;for&nbsp;every&nbsp;key&nbsp;which&nbsp;is&nbsp;not&nbsp;`:walkmap.id&#x2F;id`,&nbsp;recurse.
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;x)&nbsp;(let&nbsp;[v&nbsp;(reduce
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[m&nbsp;k]
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;m&nbsp;k&nbsp;(in-retrieve&nbsp;(x&nbsp;k)&nbsp;s)))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{}
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(keys&nbsp;(dissoc&nbsp;x&nbsp;:walkmap.id&#x2F;id)))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;(:walkmap.id&#x2F;id&nbsp;x)]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;if&nbsp;it&nbsp;has&nbsp;an&nbsp;id,&nbsp;bind&nbsp;it&nbsp;to&nbsp;that&nbsp;id&nbsp;in&nbsp;the&nbsp;returned&nbsp;value.
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;id
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:walkmap.id&#x2F;id
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:walkmap.id&#x2F;id&nbsp;x))
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v))
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(set?&nbsp;x)&nbsp;x&nbsp;;;&nbsp;TODO:&nbsp;should&nbsp;I&nbsp;search&nbsp;in&nbsp;sets&nbsp;for&nbsp;objects&nbsp;when&nbsp;storing?
</span><br/>
<span class="covered" title="11 out of 11 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(coll?&nbsp;x)&nbsp;(map&nbsp;#(in-retrieve&nbsp;%&nbsp;s)&nbsp;x)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else&nbsp;x))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
117&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
118&nbsp;&nbsp;(defn&nbsp;retrieve
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;&quot;Retrieve&nbsp;the&nbsp;canonical&nbsp;representation&nbsp;of&nbsp;the&nbsp;object&nbsp;with&nbsp;this&nbsp;`id`&nbsp;from&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
120&nbsp;&nbsp;&nbsp;&nbsp;superstructure&nbsp;`s`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
121&nbsp;&nbsp;&nbsp;&nbsp;[id&nbsp;s]
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
122&nbsp;&nbsp;&nbsp;&nbsp;(in-retrieve&nbsp;(id&nbsp;s)&nbsp;s))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
123&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
124&nbsp;&nbsp;(defn&nbsp;in-store-find-objects
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;an&nbsp;id&nbsp;-&gt;&nbsp;object&nbsp;map&nbsp;of&nbsp;every&nbsp;object&nbsp;within&nbsp;`o`.&nbsp;Internal&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;`in-store`,&nbsp;q.v.&nbsp;Use&nbsp;at&nbsp;your&nbsp;own&nbsp;peril.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
127&nbsp;&nbsp;&nbsp;&nbsp;([o]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(in-store-find-objects&nbsp;o&nbsp;{}))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;([o&nbsp;s]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
130&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;debug&nbsp;&quot;Finding&nbsp;objects&nbsp;in:&quot;&nbsp;o)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
131&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(set?&nbsp;o)&nbsp;s&nbsp;;;&nbsp;TODO:&nbsp;should&nbsp;I&nbsp;search&nbsp;in&nbsp;sets&nbsp;for&nbsp;objects&nbsp;when&nbsp;storing?
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
133&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;o)&nbsp;(if&nbsp;(:walkmap.id&#x2F;id&nbsp;o)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
135&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(in-store-find-objects&nbsp;(vals&nbsp;o)&nbsp;s)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
136&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:walkmap.id&#x2F;id&nbsp;o)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
137&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;o)
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
138&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(in-store-find-objects&nbsp;(vals&nbsp;o)&nbsp;s))
</span><br/>
<span class="covered" title="15 out of 15 forms covered">
139&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(coll?&nbsp;o)&nbsp;(reduce&nbsp;merge&nbsp;s&nbsp;(map&nbsp;#(in-store-find-objects&nbsp;%&nbsp;s)&nbsp;o))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
140&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else&nbsp;s)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
141&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
142&nbsp;&nbsp;(defn&nbsp;in-store-replace-with-keys
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
143&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;copy&nbsp;of&nbsp;`o`&nbsp;in&nbsp;which&nbsp;each&nbsp;reified&nbsp;walkmap&nbsp;object&nbsp;within&nbsp;`o`&nbsp;has
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
144&nbsp;&nbsp;&nbsp;&nbsp;been&nbsp;replaced&nbsp;with&nbsp;the&nbsp;`:walkmap.id&#x2F;id`&nbsp;of&nbsp;that&nbsp;object.&nbsp;Internal&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
145&nbsp;&nbsp;&nbsp;&nbsp;`in-store`,&nbsp;q.v.&nbsp;Use&nbsp;at&nbsp;your&nbsp;own&nbsp;peril.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
146&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
147&nbsp;&nbsp;&nbsp;&nbsp;(assoc
</span><br/>
<span class="covered" title="15 out of 15 forms covered">
148&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(postwalk&nbsp;#(or&nbsp;(:walkmap.id&#x2F;id&nbsp;%)&nbsp;%)&nbsp;(dissoc&nbsp;o&nbsp;:walkmap.id&#x2F;id))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:walkmap.id&#x2F;id
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:walkmap.id&#x2F;id&nbsp;o)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
151&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
152&nbsp;&nbsp;;;&nbsp;(in-store-replace-with-keys&nbsp;(p&#x2F;path&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;0&nbsp;0)&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;1&nbsp;2)&nbsp;(v&#x2F;vertex&nbsp;3&nbsp;3&nbsp;3)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
153&nbsp;&nbsp;;;&nbsp;(in-store-find-objects&nbsp;(p&#x2F;path&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;0&nbsp;0)&nbsp;(v&#x2F;vertex&nbsp;0&nbsp;1&nbsp;2)&nbsp;(v&#x2F;vertex&nbsp;3&nbsp;3&nbsp;3)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
154&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
155&nbsp;&nbsp;(defn&nbsp;store
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
156&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;superstructure&nbsp;like&nbsp;`s`&nbsp;with&nbsp;object&nbsp;`o`&nbsp;added.&nbsp;If&nbsp;only&nbsp;one
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
157&nbsp;&nbsp;&nbsp;&nbsp;argument&nbsp;is&nbsp;supplied&nbsp;it&nbsp;will&nbsp;be&nbsp;assumed&nbsp;to&nbsp;represent&nbsp;`o`&nbsp;and&nbsp;a&nbsp;new
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
158&nbsp;&nbsp;&nbsp;&nbsp;superstructure&nbsp;will&nbsp;be&nbsp;returned.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
159&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
160&nbsp;&nbsp;&nbsp;&nbsp;It&nbsp;is&nbsp;an&nbsp;error&nbsp;(and&nbsp;an&nbsp;exception&nbsp;may&nbsp;be&nbsp;thrown)&nbsp;if
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
161&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
162&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;`s`&nbsp;is&nbsp;not&nbsp;a&nbsp;map;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
163&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;recognisable&nbsp;walkmap&nbsp;object&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
164&nbsp;&nbsp;&nbsp;&nbsp;([o]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
165&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(store&nbsp;o&nbsp;{}))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
166&nbsp;&nbsp;&nbsp;&nbsp;([o&nbsp;s]
</span><br/>
<span class="partial" title="5 out of 6 forms covered">
167&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when-not&nbsp;(:walkmap.id&#x2F;id&nbsp;o)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
168&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
169&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
170&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Not&nbsp;a&nbsp;walkmap&nbsp;object:&nbsp;no&nbsp;value&nbsp;for&nbsp;`:walkmap.id&#x2F;id`:&nbsp;&quot;
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
171&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(u&#x2F;kind-type&nbsp;o)))))
</span><br/>
<span class="partial" title="5 out of 6 forms covered">
172&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when-not&nbsp;(map?&nbsp;s)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
173&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
174&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
175&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Superstructure&nbsp;must&nbsp;be&nbsp;a&nbsp;map:&nbsp;&quot;&nbsp;(u&#x2F;kind-type&nbsp;s)))))
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
176&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
177&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(u&#x2F;deep-merge&nbsp;s&nbsp;(in-store-find-objects&nbsp;o)&nbsp;(index-vertices&nbsp;s&nbsp;o))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
178&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:walkmap.id&#x2F;id&nbsp;o)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
179&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(in-store-replace-with-keys&nbsp;o))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
180&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
181&nbsp;&nbsp;(defn&nbsp;search-vertices
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
182&nbsp;&nbsp;&nbsp;&nbsp;&quot;Search&nbsp;superstructure&nbsp;`s`&nbsp;for&nbsp;vertices&nbsp;within&nbsp;the&nbsp;box&nbsp;defined&nbsp;by&nbsp;vertices
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
183&nbsp;&nbsp;&nbsp;&nbsp;`minv`&nbsp;and&nbsp;`maxv`.&nbsp;Every&nbsp;coordinate&nbsp;in&nbsp;`minv`&nbsp;must&nbsp;have&nbsp;a&nbsp;lower&nbsp;value&nbsp;than
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
184&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;equivalent&nbsp;coordinate&nbsp;in&nbsp;`maxv`.&nbsp;If&nbsp;`d2?`&nbsp;is&nbsp;supplied&nbsp;and&nbsp;not&nbsp;false,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
185&nbsp;&nbsp;&nbsp;&nbsp;search&nbsp;only&nbsp;in&nbsp;the&nbsp;x,y&nbsp;projection.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
186&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
187&nbsp;&nbsp;&nbsp;&nbsp;**NOTE&nbsp;THAT**&nbsp;this&nbsp;depends&nbsp;on&nbsp;the&nbsp;fact&nbsp;that&nbsp;vertices&nbsp;do&nbsp;not&nbsp;currently
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
188&nbsp;&nbsp;&nbsp;&nbsp;have&nbsp;properties&nbsp;which&nbsp;will&nbsp;be&nbsp;denormalised&nbsp;by&nbsp;`store`,&nbsp;and&nbsp;therefore&nbsp;do&nbsp;not
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
189&nbsp;&nbsp;&nbsp;&nbsp;have&nbsp;to&nbsp;restored&nbsp;with&nbsp;`retrieve`.&nbsp;If&nbsp;properties&nbsp;are&nbsp;added&nbsp;to&nbsp;vertices
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
190&nbsp;&nbsp;&nbsp;&nbsp;whose&nbsp;values&nbsp;are&nbsp;objects,&nbsp;then&nbsp;this&nbsp;will&nbsp;have&nbsp;to&nbsp;be&nbsp;rewritten.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
191&nbsp;&nbsp;&nbsp;&nbsp;([s&nbsp;minv&nbsp;maxv]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
192&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(search-vertices&nbsp;s&nbsp;minv&nbsp;maxv&nbsp;false))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
193&nbsp;&nbsp;&nbsp;&nbsp;([s&nbsp;minv&nbsp;maxv&nbsp;d2?]
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
194&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[minv&#x27;&nbsp;(if&nbsp;d2?&nbsp;(assoc&nbsp;minv&nbsp;:z&nbsp;Double&#x2F;NEGATIVE_INFINITY)&nbsp;minv)
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
195&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxv&#x27;&nbsp;(if&nbsp;d2?&nbsp;(assoc&nbsp;maxv&nbsp;:z&nbsp;Double&#x2F;POSITIVE_INFINITY)&nbsp;maxv)]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
196&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(filter
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
197&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(v&#x2F;within-box?&nbsp;%&nbsp;minv&nbsp;maxv)
</span><br/>
<span class="not-covered" title="0 out of 12 forms covered">
198&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(filter&nbsp;#(=&nbsp;(:kind&nbsp;%)&nbsp;:vertex)&nbsp;(vals&nbsp;s))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
199&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
200&nbsp;&nbsp;(defn&nbsp;nearest
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
201&nbsp;&nbsp;&nbsp;&nbsp;&quot;Search&nbsp;superstructure&nbsp;`s`&nbsp;for&nbsp;the&nbsp;nearest&nbsp;object&nbsp;matching&nbsp;`filter-fn`&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
202&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;`target`&nbsp;vertex.&nbsp;Searches&nbsp;only&nbsp;with&nbsp;`radius`&nbsp;(slight&nbsp;misnomer,&nbsp;area
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
203&nbsp;&nbsp;&nbsp;&nbsp;actually&nbsp;searched&nbsp;is&nbsp;a&nbsp;cube).&nbsp;Returns&nbsp;one&nbsp;object,&nbsp;or&nbsp;`nil`&nbsp;if&nbsp;no&nbsp;matching
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
204&nbsp;&nbsp;&nbsp;&nbsp;object&nbsp;found.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
205&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
206&nbsp;&nbsp;&nbsp;&nbsp;WARNING:&nbsp;currently&nbsp;only&nbsp;returns&nbsp;objects&nbsp;which&nbsp;have&nbsp;a&nbsp;defined&nbsp;`:centre`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
207&nbsp;&nbsp;&nbsp;&nbsp;(but&nbsp;most&nbsp;of&nbsp;the&nbsp;significant&nbsp;objects&nbsp;we&nbsp;have&nbsp;do).&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
208&nbsp;&nbsp;&nbsp;&nbsp;[s&nbsp;target&nbsp;filter-fn&nbsp;radius]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
209&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[minv&nbsp;(v&#x2F;vertex
</span><br/>
<span class="not-covered" title="0 out of 21 forms covered">
210&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(-&nbsp;(:x&nbsp;(v&#x2F;check-vertex&nbsp;target))&nbsp;radius)
</span><br/>
<span class="not-covered" title="0 out of 17 forms covered">
211&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(-&nbsp;(:y&nbsp;target)&nbsp;radius)&nbsp;(-&nbsp;(or&nbsp;(:z&nbsp;target)&nbsp;0)&nbsp;radius))
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
212&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxv&nbsp;(v&#x2F;vertex
</span><br/>
<span class="not-covered" title="0 out of 12 forms covered">
213&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+&nbsp;(:x&nbsp;target)&nbsp;0.5)&nbsp;(+&nbsp;(:y&nbsp;target)&nbsp;0.5)
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
214&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+&nbsp;(or&nbsp;(:z&nbsp;target)&nbsp;0)&nbsp;0.5))]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
215&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;filter&nbsp;those&nbsp;objects&nbsp;with&nbsp;the&nbsp;filter&nbsp;function,&nbsp;then&nbsp;sort&nbsp;that&nbsp;list
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
216&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;by&nbsp;the&nbsp;edge&nbsp;distance&nbsp;from&nbsp;the&nbsp;target&nbsp;to&nbsp;the&nbsp;`:centre`&nbsp;of&nbsp;the&nbsp;object
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
217&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;and&nbsp;take&nbsp;the&nbsp;first
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
218&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(first
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
219&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sort-by
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
220&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(length&nbsp;(edge&nbsp;target&nbsp;(:centre&nbsp;%)))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
221&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(filter
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
222&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:centre
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
223&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;#(retrieve&nbsp;%&nbsp;s)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
224&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;for&nbsp;each&nbsp;vertex&nbsp;id&nbsp;in&nbsp;vids,&nbsp;get&nbsp;the&nbsp;objects&nbsp;associated&nbsp;with&nbsp;that&nbsp;id
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
225&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;in&nbsp;the&nbsp;vertex&nbsp;index&nbsp;as&nbsp;a&nbsp;single&nbsp;flat&nbsp;list
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
226&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
227&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;concat
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
228&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(remove
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
229&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil?
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
230&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
231&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(-&gt;&nbsp;s&nbsp;::vertex-index&nbsp;%&nbsp;keys)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
232&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;get&nbsp;all&nbsp;the&nbsp;vertex&nbsp;ids&nbsp;within&nbsp;radius&nbsp;of&nbsp;the&nbsp;target
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
233&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(set
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
234&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
235&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:walkmap.id&#x2F;id
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
236&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(search-vertices&nbsp;s&nbsp;minv&nbsp;maxv))))))))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
237&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
238&nbsp;&nbsp;(defn&nbsp;touching
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
239&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;sequence&nbsp;of&nbsp;all&nbsp;objects&nbsp;in&nbsp;superstructure&nbsp;`s`&nbsp;which&nbsp;are
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
240&nbsp;&nbsp;&nbsp;&nbsp;indexed&nbsp;as&nbsp;touching&nbsp;the&nbsp;vertex&nbsp;`v`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
241&nbsp;&nbsp;&nbsp;&nbsp;([vertex&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
242&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
243&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(retrieve&nbsp;%&nbsp;s)
</span><br/>
<span class="not-covered" title="0 out of 25 forms covered">
244&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(set&nbsp;(-&gt;&nbsp;s&nbsp;:vertex-index&nbsp;(:walkmap.id&#x2F;id&nbsp;(v&#x2F;check-vertex&nbsp;vertex))&nbsp;keys))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
245&nbsp;&nbsp;&nbsp;&nbsp;([vertex&nbsp;filter-fn&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
246&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(filter
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
247&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filter-fn
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
248&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(touching&nbsp;vertex&nbsp;s))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
249&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
250&nbsp;&nbsp;(defn&nbsp;neighbours
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
251&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;sequence&nbsp;of&nbsp;all&nbsp;those&nbsp;objects&nbsp;in&nbsp;superstructure&nbsp;`s`&nbsp;which&nbsp;share
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
252&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;least&nbsp;one&nbsp;vertex&nbsp;with&nbsp;`target`,&nbsp;and&nbsp;which&nbsp;are&nbsp;matched&nbsp;by&nbsp;`filter-fn`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
253&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;supplied.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
254&nbsp;&nbsp;&nbsp;&nbsp;([target&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
255&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(neighbours&nbsp;identity&nbsp;s))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
256&nbsp;&nbsp;&nbsp;&nbsp;([target&nbsp;filter-fn&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
257&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(remove
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
258&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(=&nbsp;target&nbsp;%)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
259&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
260&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;concat
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
261&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(remove
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
262&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil?
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
263&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;#(touching&nbsp;%&nbsp;filter-fn&nbsp;s)&nbsp;(vertices&nbsp;target)))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
264&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
265&nbsp;&nbsp;(defn&nbsp;neighbour-ids
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
266&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;sequence&nbsp;of&nbsp;the&nbsp;ids&nbsp;all&nbsp;those&nbsp;objects&nbsp;in&nbsp;superstructure&nbsp;`s`&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
267&nbsp;&nbsp;&nbsp;&nbsp;share&nbsp;at&nbsp;least&nbsp;one&nbsp;vertex&nbsp;with&nbsp;`target`,&nbsp;and&nbsp;which&nbsp;are&nbsp;matched&nbsp;by
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
268&nbsp;&nbsp;&nbsp;&nbsp;`filter-fn`&nbsp;if&nbsp;supplied.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
269&nbsp;&nbsp;&nbsp;&nbsp;([target&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
270&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(neighbour-ids&nbsp;target&nbsp;identity&nbsp;s))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
271&nbsp;&nbsp;&nbsp;&nbsp;([target&nbsp;filter-fn&nbsp;s]
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
272&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;:walkmap.id&#x2F;id&nbsp;(neighbours&nbsp;target&nbsp;filter-fn&nbsp;s))))
</span><br/>
</body>
</html>

View file

@ -17,142 +17,322 @@
004&nbsp;&nbsp;&nbsp;&nbsp;(SVG).&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.string&nbsp;:as&nbsp;s]
005&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.java.io&nbsp;:as&nbsp;io]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l&nbsp;:refer&nbsp;[info&nbsp;error&nbsp;spy]]
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.string&nbsp;:as&nbsp;s]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.polygon&nbsp;:refer&nbsp;[polygon?]]
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.xml&nbsp;:as&nbsp;x]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:refer&nbsp;[vertex?]]))
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[dali.io&nbsp;:as&nbsp;neatly-folded-clock]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[hiccup.core&nbsp;:refer&nbsp;[html]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l&nbsp;:refer&nbsp;[info&nbsp;error&nbsp;spy]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.ocean&nbsp;:refer&nbsp;[cull-ocean-facets]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.polygon&nbsp;:refer&nbsp;[polygon?]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.stl&nbsp;:refer&nbsp;[decode-binary-stl]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.vertex&nbsp;:refer&nbsp;[vertex?]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
009&nbsp;&nbsp;
015&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
010&nbsp;&nbsp;(defn-&nbsp;facet-&gt;svg-poly
016&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*preferred-svg-render*
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;[facet]
017&nbsp;&nbsp;&nbsp;&nbsp;&quot;Mainly&nbsp;for&nbsp;debugging&nbsp;dali;&nbsp;switch&nbsp;SVG&nbsp;renderer&nbsp;to&nbsp;use.&nbsp;Expected&nbsp;values:
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;[:polygon
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;`:dali`,&nbsp;`:hiccup`.&quot;
</span><br/>
<span class="not-covered" title="0 out of 20 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:points&nbsp;(s&#x2F;join&nbsp;&quot;&nbsp;&quot;&nbsp;(map&nbsp;#(str&nbsp;(:x&nbsp;%)&nbsp;&quot;,&quot;&nbsp;(:y&nbsp;%))&nbsp;(:vertices&nbsp;facet)))}])
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;:dali)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
014&nbsp;&nbsp;
020&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
021&nbsp;&nbsp;(defn-&nbsp;facet-&gt;svg-poly
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;[facet]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;[:polygon
</span><br/>
<span class="not-covered" title="0 out of 20 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:points&nbsp;(s&#x2F;join&nbsp;&quot;&nbsp;&quot;&nbsp;(map&nbsp;#(str&nbsp;(:x&nbsp;%)&nbsp;&quot;,&quot;&nbsp;(:y&nbsp;%))&nbsp;(:vertices&nbsp;facet)))}])
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
025&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
026&nbsp;&nbsp;(defn-&nbsp;dali-facet-&gt;svg-poly
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;[facet]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;(vec
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:polygon
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;#(vec&nbsp;(list&nbsp;(:x&nbsp;%)&nbsp;(:y&nbsp;%)))&nbsp;(:vertices&nbsp;facet)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
032&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
015&nbsp;&nbsp;(defn&nbsp;stl-&gt;svg
033&nbsp;&nbsp;(defn&nbsp;dali-stl-&gt;svg
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;&quot;Convert&nbsp;this&nbsp;in-memory&nbsp;`stl`&nbsp;structure,&nbsp;as&nbsp;read&nbsp;by&nbsp;`decode-binary-stl`,&nbsp;into
034&nbsp;&nbsp;&nbsp;&nbsp;&quot;Format&nbsp;this&nbsp;`stl`&nbsp;as&nbsp;SVG&nbsp;for&nbsp;the&nbsp;`dali`&nbsp;renderer&nbsp;on&nbsp;a&nbsp;page&nbsp;with&nbsp;these
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;an&nbsp;in-memory&nbsp;hiccup&nbsp;representation&nbsp;of&nbsp;SVG&nbsp;structure,&nbsp;and&nbsp;return&nbsp;it.&quot;
035&nbsp;&nbsp;&nbsp;&nbsp;bounds.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;[stl]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[minx&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;min
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(reduce&nbsp;min&nbsp;(map&nbsp;:x&nbsp;(:vertices&nbsp;%)))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl)))
036&nbsp;&nbsp;&nbsp;&nbsp;[stl&nbsp;minx&nbsp;maxx&nbsp;miny&nbsp;maxy]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxx&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(reduce&nbsp;max&nbsp;(map&nbsp;:x&nbsp;(:vertices&nbsp;%)))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl)))
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;miny&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;min
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(reduce&nbsp;min&nbsp;(map&nbsp;:y&nbsp;(:vertices&nbsp;%)))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl)))
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxy&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(reduce&nbsp;max&nbsp;(map&nbsp;:y&nbsp;(:vertices&nbsp;%)))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl)))]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:svg
037&nbsp;&nbsp;&nbsp;&nbsp;[:dali&#x2F;page
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:xmlns&nbsp;&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
038&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:xmlns&nbsp;&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:version&nbsp;&quot;1.2&quot;
039&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:version&nbsp;&quot;1.2&quot;
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:width&nbsp;(-&nbsp;maxx&nbsp;minx)
040&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:width&nbsp;(-&nbsp;maxx&nbsp;minx)
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:height&nbsp;(-&nbsp;maxy&nbsp;miny)
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:height&nbsp;(-&nbsp;maxy&nbsp;miny)
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:viewBox&nbsp;(s&#x2F;join&nbsp;&quot;&nbsp;&quot;&nbsp;(map&nbsp;str&nbsp;[minx&nbsp;miny&nbsp;maxx&nbsp;maxy]))}
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:viewBox&nbsp;(s&#x2F;join&nbsp;&quot;&nbsp;&quot;&nbsp;(map&nbsp;str&nbsp;[minx&nbsp;miny&nbsp;maxx&nbsp;maxy]))}
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vec
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vec
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons
044&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:g
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:g
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;facet-&gt;svg-poly
047&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dali-facet-&gt;svg-poly
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl))))]))
048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl))))])
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
049&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
050&nbsp;&nbsp;(defn&nbsp;hiccup-stl-&gt;svg
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;&quot;Format&nbsp;this&nbsp;`stl`&nbsp;as&nbsp;SVG&nbsp;for&nbsp;the&nbsp;`hiccup`&nbsp;renderer&nbsp;on&nbsp;a&nbsp;page&nbsp;with&nbsp;these
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;bounds.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;[stl&nbsp;minx&nbsp;maxx&nbsp;miny&nbsp;maxy]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;[:svg
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:xmlns&nbsp;&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:version&nbsp;&quot;1.2&quot;
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:width&nbsp;(-&nbsp;maxx&nbsp;minx)
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:height&nbsp;(-&nbsp;maxy&nbsp;miny)
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:viewBox&nbsp;(s&#x2F;join&nbsp;&quot;&nbsp;&quot;&nbsp;(map&nbsp;str&nbsp;[minx&nbsp;miny&nbsp;maxx&nbsp;maxy]))}
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vec
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:g
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;facet-&gt;svg-poly
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl))))])
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
066&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
067&nbsp;&nbsp;(defn&nbsp;stl-&gt;svg
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&quot;Convert&nbsp;this&nbsp;in-memory&nbsp;`stl`&nbsp;structure,&nbsp;as&nbsp;read&nbsp;by&nbsp;`decode-binary-stl`,&nbsp;into
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;an&nbsp;in-memory&nbsp;hiccup&nbsp;representation&nbsp;of&nbsp;SVG&nbsp;structure,&nbsp;and&nbsp;return&nbsp;it.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;[stl]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[minx&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;min
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(reduce&nbsp;min&nbsp;(map&nbsp;:x&nbsp;(:vertices&nbsp;%)))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl)))
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxx&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(reduce&nbsp;max&nbsp;(map&nbsp;:x&nbsp;(:vertices&nbsp;%)))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl)))
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;miny&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;min
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(reduce&nbsp;min&nbsp;(map&nbsp;:y&nbsp;(:vertices&nbsp;%)))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl)))
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxy&nbsp;(reduce
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(reduce&nbsp;max&nbsp;(map&nbsp;:y&nbsp;(:vertices&nbsp;%)))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:facets&nbsp;stl)))]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;info&nbsp;&quot;Generating&nbsp;SVG&nbsp;for&nbsp;&quot;&nbsp;*preferred-svg-render*&nbsp;&quot;&nbsp;renderer&quot;)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(case&nbsp;*preferred-svg-render*
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:hiccup&nbsp;(hiccup-stl-&gt;svg&nbsp;stl&nbsp;minx&nbsp;maxx&nbsp;miny&nbsp;maxy)
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:dali&nbsp;(dali-stl-&gt;svg&nbsp;stl&nbsp;minx&nbsp;maxx&nbsp;miny&nbsp;maxy)
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(Exception.&nbsp;&quot;Unexpected&nbsp;renderer&nbsp;value:&nbsp;&quot;&nbsp;*preferred-svg-render*)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
096&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
097&nbsp;&nbsp;(defn&nbsp;binary-stl-file-&gt;svg
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&quot;Given&nbsp;only&nbsp;an&nbsp;`in-filename`,&nbsp;parse&nbsp;the&nbsp;indicated&nbsp;file,&nbsp;expected&nbsp;to&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;binary&nbsp;STL,&nbsp;and&nbsp;return&nbsp;an&nbsp;equivalent&nbsp;SVG&nbsp;structure.&nbsp;Given&nbsp;both&nbsp;`in-filename`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;and&nbsp;`out-filename`,&nbsp;as&nbsp;side-effect&nbsp;write&nbsp;the&nbsp;SVG&nbsp;to&nbsp;the&nbsp;indicated&nbsp;output&nbsp;file.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;([in-filename]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(stl-&gt;svg&nbsp;(cull-ocean-facets&nbsp;(decode-binary-stl&nbsp;in-filename))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;([in-filename&nbsp;out-filename]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[s&nbsp;(binary-stl-file-&gt;svg&nbsp;in-filename)]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;info&nbsp;&quot;Emitting&nbsp;SVG&nbsp;with&nbsp;&quot;&nbsp;*preferred-svg-render*&nbsp;&quot;&nbsp;renderer&quot;)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(case&nbsp;*preferred-svg-render*
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:dali&nbsp;(neatly-folded-clock&#x2F;render-svg&nbsp;s&nbsp;out-filename)
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:hiccup&nbsp;(spit&nbsp;out-filename&nbsp;(html&nbsp;s))
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(Exception.&nbsp;&quot;Unexpected&nbsp;renderer&nbsp;value:&nbsp;&quot;&nbsp;*preferred-svg-render*)))
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s)))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,212 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> walkmap/tag.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;walkmap.tag
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Code&nbsp;for&nbsp;tagging,&nbsp;untagging,&nbsp;and&nbsp;finding&nbsp;tags&nbsp;on&nbsp;objects.&nbsp;Note&nbsp;the&nbsp;use&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;namespaced&nbsp;keyword,&nbsp;`:walkmap.tag&#x2F;tags`,&nbsp;denoted&nbsp;in&nbsp;this&nbsp;file&nbsp;`::tags`.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;This&nbsp;is&nbsp;in&nbsp;an&nbsp;attempt&nbsp;to&nbsp;avoid&nbsp;name&nbsp;clashes&nbsp;with&nbsp;other&nbsp;uses&nbsp;of&nbsp;this&nbsp;key.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.set&nbsp;:refer&nbsp;[difference&nbsp;union]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.utils&nbsp;:refer&nbsp;[kind-type]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
008&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
009&nbsp;&nbsp;(defn&nbsp;tagged?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;this&nbsp;`object`&nbsp;is&nbsp;tagged&nbsp;with&nbsp;each&nbsp;of&nbsp;these&nbsp;`tags`.&nbsp;It&nbsp;is&nbsp;an&nbsp;error
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;an&nbsp;exception&nbsp;will&nbsp;be&nbsp;thrown)&nbsp;if
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
012&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;`object`&nbsp;is&nbsp;not&nbsp;a&nbsp;map;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;any&nbsp;of&nbsp;`tags`&nbsp;is&nbsp;not&nbsp;a&nbsp;keyword.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;[object&nbsp;&amp;&nbsp;tags]
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;(when-not&nbsp;(map?&nbsp;object)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Must&nbsp;be&nbsp;a&nbsp;map:&nbsp;&quot;&nbsp;(kind-type&nbsp;object)))))
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[tags&#x27;&nbsp;(flatten&nbsp;tags)]
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when-not&nbsp;(every?&nbsp;keyword?&nbsp;tags&#x27;)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Must&nbsp;be&nbsp;keywords:&nbsp;&quot;&nbsp;(map&nbsp;kind-type&nbsp;tags&#x27;)))))
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[ot&nbsp;(::tags&nbsp;object)]
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(set?&nbsp;ot)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?&nbsp;ot&nbsp;tags&#x27;)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
027&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
028&nbsp;&nbsp;(defn&nbsp;tag
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;an&nbsp;object&nbsp;like&nbsp;this&nbsp;`object`&nbsp;but&nbsp;with&nbsp;these&nbsp;`tags`&nbsp;added&nbsp;to&nbsp;its&nbsp;tags,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;they&nbsp;are&nbsp;not&nbsp;already&nbsp;present.&nbsp;It&nbsp;is&nbsp;an&nbsp;error&nbsp;(and&nbsp;an&nbsp;exception&nbsp;will&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;thrown)&nbsp;if
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
032&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;`object`&nbsp;is&nbsp;not&nbsp;a&nbsp;map;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;any&nbsp;of&nbsp;`tags`&nbsp;is&nbsp;not&nbsp;a&nbsp;keyword&nbsp;or&nbsp;sequence&nbsp;of&nbsp;keywords.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
035&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;It&#x27;s&nbsp;legal&nbsp;to&nbsp;include&nbsp;sequences&nbsp;of&nbsp;keywords&nbsp;in&nbsp;`tags`,&nbsp;so&nbsp;that&nbsp;users&nbsp;can&nbsp;do
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;useful&nbsp;things&nbsp;like&nbsp;`(tag&nbsp;obj&nbsp;(map&nbsp;keyword&nbsp;some-strings))`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;[object&nbsp;&amp;&nbsp;tags]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;debug&nbsp;&quot;Tagging&quot;&nbsp;(kind-type&nbsp;object)&nbsp;&quot;with&quot;&nbsp;tags)
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;(when-not&nbsp;(map?&nbsp;object)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Must&nbsp;be&nbsp;a&nbsp;map:&nbsp;&quot;&nbsp;(kind-type&nbsp;object)))))
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[tags&#x27;&nbsp;(flatten&nbsp;tags)]
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when-not&nbsp;(every?&nbsp;keyword?&nbsp;tags&#x27;)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Must&nbsp;be&nbsp;keywords:&nbsp;&quot;&nbsp;(map&nbsp;kind-type&nbsp;tags&#x27;)))))
</span><br/>
<span class="covered" title="12 out of 12 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;object&nbsp;::tags&nbsp;(union&nbsp;(set&nbsp;tags&#x27;)&nbsp;(::tags&nbsp;object)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
048&nbsp;&nbsp;
</span><br/>
<span class="covered" title="15 out of 15 forms covered">
049&nbsp;&nbsp;(defmacro&nbsp;tags
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;the&nbsp;tags&nbsp;of&nbsp;this&nbsp;object,&nbsp;if&nbsp;any.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;[object]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;`(::tags&nbsp;~object))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
053&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
054&nbsp;&nbsp;(defn&nbsp;untag
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;an&nbsp;object&nbsp;like&nbsp;this&nbsp;`object`&nbsp;but&nbsp;with&nbsp;these&nbsp;`tags`&nbsp;removed&nbsp;from&nbsp;its
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;tags,&nbsp;if&nbsp;present.&nbsp;It&nbsp;is&nbsp;an&nbsp;error&nbsp;(and&nbsp;an&nbsp;exception&nbsp;will&nbsp;be&nbsp;thrown)&nbsp;if
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
057&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;`object`&nbsp;is&nbsp;not&nbsp;a&nbsp;map;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;any&nbsp;of&nbsp;`tags`&nbsp;is&nbsp;not&nbsp;a&nbsp;keyword&nbsp;or&nbsp;sequence&nbsp;of&nbsp;keywords.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;[object&nbsp;&amp;&nbsp;tags]
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;(when-not&nbsp;(map?&nbsp;object)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Must&nbsp;be&nbsp;a&nbsp;map:&nbsp;&quot;&nbsp;(kind-type&nbsp;object)))))
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[tags&#x27;&nbsp;(flatten&nbsp;tags)]
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when-not&nbsp;(every?&nbsp;keyword?&nbsp;tags&#x27;)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Must&nbsp;be&nbsp;keywords:&nbsp;&quot;&nbsp;(map&nbsp;kind-type&nbsp;tags&#x27;)))))
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(update-in&nbsp;object&nbsp;[:walkmap.tag&#x2F;tags]&nbsp;difference&nbsp;(set&nbsp;tags&#x27;))))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,365 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> walkmap/utils.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;walkmap.utils
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Miscellaneous&nbsp;utility&nbsp;functions.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.edn&nbsp;:as&nbsp;edn&nbsp;:only&nbsp;[read]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.java.io&nbsp;:as&nbsp;io]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.math.numeric-tower&nbsp;:as&nbsp;m]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.string&nbsp;:as&nbsp;s]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
007&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
008&nbsp;&nbsp;(defn&nbsp;deep-merge
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&quot;Recursively&nbsp;merges&nbsp;maps.&nbsp;If&nbsp;vals&nbsp;are&nbsp;not&nbsp;maps,&nbsp;the&nbsp;last&nbsp;value&nbsp;wins.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;TODO:&nbsp;not&nbsp;my&nbsp;implementation,&nbsp;not&nbsp;sure&nbsp;I&nbsp;entirely&nbsp;trust&nbsp;it.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;TODO&nbsp;TODO:&nbsp;if&nbsp;we&nbsp;are&nbsp;to&nbsp;successfully&nbsp;merge&nbsp;walkmap&nbsp;objects,&nbsp;we&nbsp;must
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;return,&nbsp;on&nbsp;each&nbsp;object,&nbsp;the&nbsp;union&nbsp;of&nbsp;its&nbsp;tags&nbsp;if&nbsp;any.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;[&amp;&nbsp;vals]
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(every?&nbsp;map?&nbsp;vals)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;merge-with&nbsp;deep-merge&nbsp;vals)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(last&nbsp;vals)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
017&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
018&nbsp;&nbsp;(defn&nbsp;truncate
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;string&nbsp;`s`&nbsp;is&nbsp;more&nbsp;than&nbsp;`n`&nbsp;characters&nbsp;long,&nbsp;return&nbsp;the&nbsp;first&nbsp;`n`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;characters;&nbsp;otherwise,&nbsp;return&nbsp;`s`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;[s&nbsp;n]
</span><br/>
<span class="partial" title="20 out of 21 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(and&nbsp;(string?&nbsp;s)&nbsp;(number?&nbsp;n)&nbsp;(&gt;&nbsp;(count&nbsp;s)&nbsp;n))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(subs&nbsp;s&nbsp;0&nbsp;n)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
025&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
026&nbsp;&nbsp;(defn&nbsp;kind-type
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&quot;Identify&nbsp;the&nbsp;type&nbsp;of&nbsp;an&nbsp;`object`,&nbsp;e.g.&nbsp;for&nbsp;logging.&nbsp;If&nbsp;it&nbsp;has&nbsp;a&nbsp;`:kind`&nbsp;key,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;it&#x27;s&nbsp;one&nbsp;of&nbsp;ours,&nbsp;and&nbsp;that&#x27;s&nbsp;what&nbsp;we&nbsp;want.&nbsp;Otherwise,&nbsp;we&nbsp;want&nbsp;its&nbsp;type;&nbsp;but
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;type&nbsp;of&nbsp;`nil`&nbsp;is&nbsp;`nil`,&nbsp;which&nbsp;doesn&#x27;t&nbsp;get&nbsp;printed&nbsp;when&nbsp;assembling&nbsp;error
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;,essages,&nbsp;so&nbsp;return&nbsp;\&quot;nil\&quot;.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;[object]
</span><br/>
<span class="covered" title="15 out of 15 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(:kind&nbsp;object)&nbsp;(type&nbsp;object)&nbsp;&quot;nil&quot;))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
033&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
034&nbsp;&nbsp;(defn&nbsp;=ish
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;numbers&nbsp;`n1`,&nbsp;`n2`&nbsp;are&nbsp;roughly&nbsp;equal;&nbsp;that&nbsp;is&nbsp;to&nbsp;say,&nbsp;equal&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;within&nbsp;`tolerance`&nbsp;(defaults&nbsp;to&nbsp;one&nbsp;part&nbsp;in&nbsp;one&nbsp;hundred&nbsp;thousand).&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;([n1&nbsp;n2]
</span><br/>
<span class="covered" title="11 out of 11 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(and&nbsp;(number?&nbsp;n1)&nbsp;(number?&nbsp;n2))
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[m&nbsp;(m&#x2F;abs&nbsp;(min&nbsp;n1&nbsp;n2))
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t&nbsp;(if&nbsp;(zero?&nbsp;m)&nbsp;0.00001&nbsp;(*&nbsp;0.00001&nbsp;m))]
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=ish&nbsp;n1&nbsp;n2&nbsp;t))
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;n1&nbsp;n2)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;([n1&nbsp;n2&nbsp;tolerance]
</span><br/>
<span class="covered" title="11 out of 11 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(and&nbsp;(number?&nbsp;n1)&nbsp;(number?&nbsp;n2))
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(m&#x2F;abs&nbsp;(-&nbsp;n1&nbsp;n2))&nbsp;tolerance)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;n1&nbsp;n2))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
047&nbsp;&nbsp;
</span><br/>
<span class="covered" title="198 out of 198 forms covered">
048&nbsp;&nbsp;(defmacro&nbsp;check-kind-type
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`object`&nbsp;is&nbsp;not&nbsp;of&nbsp;kind-type&nbsp;`expected`,&nbsp;throws&nbsp;an
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;IllegalArgumentException&nbsp;with&nbsp;an&nbsp;appropriate&nbsp;message;&nbsp;otherwise,&nbsp;returns
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;`object`.&nbsp;If&nbsp;`checkfn`&nbsp;is&nbsp;supplied,&nbsp;it&nbsp;should&nbsp;be&nbsp;a&nbsp;function&nbsp;which&nbsp;tests
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;whether&nbsp;the&nbsp;object&nbsp;is&nbsp;of&nbsp;the&nbsp;expected&nbsp;kind-type.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
053&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;Macro,&nbsp;so&nbsp;that&nbsp;the&nbsp;exception&nbsp;is&nbsp;thrown&nbsp;from&nbsp;the&nbsp;calling&nbsp;function.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;([object&nbsp;expected]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`(if-not&nbsp;(=&nbsp;(kind-type&nbsp;~object)&nbsp;~expected)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;join
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;&nbsp;&quot;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[&quot;Expected&quot;&nbsp;~expected&nbsp;&quot;but&nbsp;found&quot;&nbsp;(kind-type&nbsp;~object)])))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~object))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;([object&nbsp;checkfn&nbsp;expected]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`(if-not&nbsp;(~checkfn&nbsp;~object)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;join
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;&nbsp;&quot;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[&quot;Expected&quot;&nbsp;~expected&nbsp;&quot;but&nbsp;found&quot;&nbsp;(kind-type&nbsp;~object)])))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~object)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
071&nbsp;&nbsp;
</span><br/>
<span class="covered" title="416 out of 416 forms covered">
072&nbsp;&nbsp;(defmacro&nbsp;check-kind-type-seq
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;some&nbsp;item&nbsp;on&nbsp;sequence&nbsp;`s`&nbsp;is&nbsp;not&nbsp;of&nbsp;the&nbsp;`expected`&nbsp;kind-type,&nbsp;throws&nbsp;an
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;IllegalArgumentException&nbsp;with&nbsp;an&nbsp;appropriate&nbsp;message;&nbsp;otherwise,&nbsp;returns
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;`object`.&nbsp;If&nbsp;`checkfn`&nbsp;is&nbsp;supplied,&nbsp;it&nbsp;should&nbsp;be&nbsp;a&nbsp;function&nbsp;which&nbsp;tests
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;whether&nbsp;the&nbsp;object&nbsp;is&nbsp;of&nbsp;the&nbsp;expected&nbsp;kind-type.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
077&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;Macro,&nbsp;so&nbsp;that&nbsp;the&nbsp;exception&nbsp;is&nbsp;thrown&nbsp;from&nbsp;the&nbsp;calling&nbsp;function.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;([s&nbsp;expected]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;`(if-not&nbsp;(every?&nbsp;#(=&nbsp;(kind-type&nbsp;%)&nbsp;~expected)&nbsp;~s)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;join
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;&nbsp;&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[&quot;Expected&nbsp;sequence&nbsp;of&quot;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~expected
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;but&nbsp;found&nbsp;(&quot;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;join&nbsp;&quot;,&nbsp;&quot;&nbsp;(remove&nbsp;#(=&nbsp;~expected&nbsp;%)&nbsp;(map&nbsp;kind-type&nbsp;~s)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;)&quot;])))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~s))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;([s&nbsp;checkfn&nbsp;expected]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;`(if-not&nbsp;(every?&nbsp;#(~checkfn&nbsp;%)&nbsp;~s)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;join
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;&nbsp;&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[&quot;Expected&nbsp;sequence&nbsp;of&quot;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~expected
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;but&nbsp;found&nbsp;(&quot;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;join&nbsp;&quot;,&nbsp;&quot;&nbsp;(remove&nbsp;#(=&nbsp;~expected&nbsp;%)&nbsp;(map&nbsp;kind-type&nbsp;~s)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;)&quot;])))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;~s)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
103&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
104&nbsp;&nbsp;(defn&nbsp;load-edn
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&quot;Load&nbsp;edn&nbsp;from&nbsp;an&nbsp;io&#x2F;reader&nbsp;source&nbsp;(filename&nbsp;or&nbsp;io&#x2F;resource).&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;[source]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(with-open&nbsp;[r&nbsp;(io&#x2F;reader&nbsp;source)]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(edn&#x2F;read&nbsp;(java.io.PushbackReader.&nbsp;r)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;java.io.IOException&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(printf&nbsp;&quot;Couldn&#x27;t&nbsp;open&nbsp;&#x27;%s&#x27;:&nbsp;%s\n&quot;&nbsp;source&nbsp;(.getMessage&nbsp;e)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;RuntimeException&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(printf&nbsp;&quot;Error&nbsp;parsing&nbsp;edn&nbsp;file&nbsp;&#x27;%s&#x27;:&nbsp;%s\n&quot;&nbsp;source&nbsp;(.getMessage&nbsp;e)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
114&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
115&nbsp;&nbsp;(defn&nbsp;not-yet-implemented
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;[message]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;(throw
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(UnsupportedOperationException.
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Not&nbsp;yet&nbsp;implemented:&nbsp;&quot;&nbsp;message))))
</span><br/>
</body>
</html>

View file

@ -8,130 +8,454 @@
001&nbsp;&nbsp;(ns&nbsp;walkmap.vertex
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Essentially&nbsp;the&nbsp;specification&nbsp;for&nbsp;things&nbsp;we&nbsp;shall&nbsp;consider&nbsp;to&nbsp;be&nbsp;vertices.&quot;)
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Essentially&nbsp;the&nbsp;specification&nbsp;for&nbsp;things&nbsp;we&nbsp;shall&nbsp;consider&nbsp;to&nbsp;be&nbsp;vertices.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
003&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
004&nbsp;&nbsp;(defn&nbsp;vertex?
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;Note&nbsp;that&nbsp;there&#x27;s&nbsp;no&nbsp;`distance`&nbsp;function&nbsp;here;&nbsp;to&nbsp;find&nbsp;the&nbsp;distance&nbsp;between
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;satisfies&nbsp;the&nbsp;conditions&nbsp;for&nbsp;a&nbsp;vertex.&nbsp;That&nbsp;is,&nbsp;essentially,
005&nbsp;&nbsp;&nbsp;&nbsp;two&nbsp;vertices,&nbsp;create&nbsp;an&nbsp;edge&nbsp;from&nbsp;them&nbsp;and&nbsp;use&nbsp;`walkmap.edge&#x2F;length`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;that&nbsp;it&nbsp;must&nbsp;rerpresent&nbsp;a&nbsp;two-&nbsp;or&nbsp;three-&nbsp;dimensional&nbsp;vector.&nbsp;A&nbsp;vertex&nbsp;is
006&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.math.numeric-tower&nbsp;:as&nbsp;m]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;shall&nbsp;be&nbsp;a&nbsp;map&nbsp;having&nbsp;at&nbsp;least&nbsp;the&nbsp;keys&nbsp;`:x`&nbsp;and&nbsp;`:y`,&nbsp;where&nbsp;the&nbsp;value&nbsp;of
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clojure.string&nbsp;:as&nbsp;s]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;those&nbsp;keys&nbsp;is&nbsp;a&nbsp;number.&nbsp;If&nbsp;the&nbsp;key&nbsp;`:z`&nbsp;is&nbsp;also&nbsp;present,&nbsp;its&nbsp;value&nbsp;must&nbsp;also
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;be&nbsp;a&nbsp;number.
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[walkmap.utils&nbsp;:refer&nbsp;[=ish&nbsp;check-kind-type&nbsp;check-kind-type-seq&nbsp;kind-type&nbsp;truncate]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
010&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;The&nbsp;name&nbsp;&nbsp;`vector?`&nbsp;was&nbsp;not&nbsp;used&nbsp;as&nbsp;that&nbsp;would&nbsp;clash&nbsp;with&nbsp;a&nbsp;function&nbsp;of&nbsp;that
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;in&nbsp;`clojure.core`&nbsp;whose&nbsp;semantics&nbsp;are&nbsp;entirely&nbsp;different.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="partial" title="15 out of 17 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;o)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(number?&nbsp;(:x&nbsp;o))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(number?&nbsp;(:y&nbsp;o))
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(nil?&nbsp;(:z&nbsp;o))&nbsp;(number?&nbsp;(:z&nbsp;o)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
019&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
020&nbsp;&nbsp;(def&nbsp;ensure3d
011&nbsp;&nbsp;(defn&nbsp;vertex-key
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&quot;Given&nbsp;a&nbsp;vertex&nbsp;`o`,&nbsp;if&nbsp;`o`&nbsp;has&nbsp;a&nbsp;`:z`&nbsp;value,&nbsp;just&nbsp;return&nbsp;`o`;&nbsp;otherwise
012&nbsp;&nbsp;&nbsp;&nbsp;&quot;Making&nbsp;sure&nbsp;we&nbsp;get&nbsp;the&nbsp;same&nbsp;key&nbsp;everytime&nbsp;we&nbsp;key&nbsp;a&nbsp;vertex&nbsp;with&nbsp;the&nbsp;same
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;a&nbsp;vertex&nbsp;like&nbsp;`o`&nbsp;but&nbsp;having&nbsp;thie&nbsp;`dflt`&nbsp;value&nbsp;as&nbsp;the&nbsp;value&nbsp;of&nbsp;its
013&nbsp;&nbsp;&nbsp;&nbsp;coordinates.&nbsp;`o`&nbsp;must&nbsp;have&nbsp;numeric&nbsp;values&nbsp;for&nbsp;`:x`,&nbsp;`:y`,&nbsp;and&nbsp;optionally
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;`:z`&nbsp;key,&nbsp;or&nbsp;zero&nbsp;as&nbsp;the&nbsp;value&nbsp;of&nbsp;its&nbsp;`:z`&nbsp;key&nbsp;if&nbsp;`dflt`&nbsp;is&nbsp;not&nbsp;specified.
014&nbsp;&nbsp;&nbsp;&nbsp;`:z`;&nbsp;it&nbsp;is&nbsp;an&nbsp;error&nbsp;and&nbsp;an&nbsp;exception&nbsp;will&nbsp;be&nbsp;thrown&nbsp;if&nbsp;`o`&nbsp;does&nbsp;not
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;&nbsp;&nbsp;conform&nbsp;to&nbsp;this&nbsp;specification.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
024&nbsp;&nbsp;
016&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;vertex,&nbsp;throws&nbsp;an&nbsp;exception.&quot;
017&nbsp;&nbsp;&nbsp;&nbsp;**Note:**&nbsp;these&nbsp;keys&nbsp;can&nbsp;be&nbsp;quite&nbsp;long.&nbsp;No&nbsp;apology&nbsp;is&nbsp;made:&nbsp;it&nbsp;is&nbsp;required
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;that&nbsp;the&nbsp;same&nbsp;key&nbsp;can&nbsp;*never*&nbsp;refer&nbsp;to&nbsp;two&nbsp;different&nbsp;locations&nbsp;in&nbsp;space.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;(memoize
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;([o]
020&nbsp;&nbsp;&nbsp;&nbsp;(keyword
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ensure3d&nbsp;o&nbsp;0.0))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;([o&nbsp;dflt]
021&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s&#x2F;replace
</span><br/>
<span class="partial" title="2 out of 3 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
022&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="partial" title="5 out of 8 forms covered">
032&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(not&nbsp;(vertex?&nbsp;o))&nbsp;(throw&nbsp;(Exception.&nbsp;&quot;Not&nbsp;a&nbsp;vertex!&quot;))
<span class="partial" title="15 out of 17 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(:x&nbsp;o)&nbsp;(:y&nbsp;o)&nbsp;(:z&nbsp;o))
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:z&nbsp;o)&nbsp;o
<span class="covered" title="14 out of 14 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;vert_&quot;&nbsp;(:x&nbsp;o)&nbsp;&quot;_&quot;&nbsp;(:y&nbsp;o)&nbsp;&quot;_&quot;&nbsp;(:z&nbsp;o))
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else&nbsp;(assoc&nbsp;o&nbsp;:z&nbsp;dflt))))))
<span class="partial" title="9 out of 10 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(:x&nbsp;o)&nbsp;(:y&nbsp;o))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
035&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
036&nbsp;&nbsp;(def&nbsp;ensure2d
<span class="covered" title="10 out of 10 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;vert_&quot;&nbsp;(:x&nbsp;o)&nbsp;&quot;_&quot;&nbsp;(:y&nbsp;o))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;a&nbsp;vertex,&nbsp;set&nbsp;its&nbsp;`:z`&nbsp;value&nbsp;to&nbsp;zero;&nbsp;else&nbsp;throw&nbsp;an&nbsp;exception.&quot;
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;(memoize
<span class="not-covered" title="0 out of 2 forms covered">
028&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(IllegalArgumentException.
</span><br/>
<span class="not-covered" title="0 out of 12 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(truncate&nbsp;(str&nbsp;&quot;Not&nbsp;a&nbsp;vertex:&nbsp;&quot;&nbsp;(or&nbsp;o&nbsp;&quot;nil&quot;))&nbsp;80))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;-&quot;)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
032&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[o]
033&nbsp;&nbsp;(defn&nbsp;vertex?
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if
<span class="not-tracked" title="0 out of 0 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`o`&nbsp;satisfies&nbsp;the&nbsp;conditions&nbsp;for&nbsp;a&nbsp;vertex.&nbsp;That&nbsp;is,&nbsp;essentially,
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vertex?&nbsp;o)
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;that&nbsp;it&nbsp;must&nbsp;rerpresent&nbsp;a&nbsp;two-&nbsp;or&nbsp;three-&nbsp;dimensional&nbsp;vector.&nbsp;A&nbsp;vertex&nbsp;is
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;o&nbsp;:z&nbsp;0.0)
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;shall&nbsp;be&nbsp;a&nbsp;map&nbsp;having&nbsp;at&nbsp;least&nbsp;the&nbsp;keys&nbsp;`:x`&nbsp;and&nbsp;`:y`,&nbsp;where&nbsp;the&nbsp;value&nbsp;of
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(Exception.&nbsp;&quot;Not&nbsp;a&nbsp;vertex!&quot;))))))
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;those&nbsp;keys&nbsp;is&nbsp;a&nbsp;number.&nbsp;If&nbsp;the&nbsp;key&nbsp;`:z`&nbsp;is&nbsp;also&nbsp;present,&nbsp;its&nbsp;value&nbsp;must&nbsp;also
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;be&nbsp;a&nbsp;number.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
039&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;The&nbsp;name&nbsp;&nbsp;`vector?`&nbsp;was&nbsp;not&nbsp;used&nbsp;as&nbsp;that&nbsp;would&nbsp;clash&nbsp;with&nbsp;a&nbsp;function&nbsp;of&nbsp;that
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;in&nbsp;`clojure.core`&nbsp;whose&nbsp;semantics&nbsp;are&nbsp;entirely&nbsp;different.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="partial" title="24 out of 26 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;o)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:walkmap.id&#x2F;id&nbsp;o)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(number?&nbsp;(:x&nbsp;o))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(number?&nbsp;(:y&nbsp;o))
</span><br/>
<span class="partial" title="20 out of 26 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(nil?&nbsp;(:z&nbsp;o))&nbsp;(number?&nbsp;(:z&nbsp;o)))
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(nil?&nbsp;(:kind&nbsp;o))&nbsp;(=&nbsp;(:kind&nbsp;o)&nbsp;:vertex))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
050&nbsp;&nbsp;
</span><br/>
<span class="covered" title="27 out of 27 forms covered">
051&nbsp;&nbsp;(defmacro&nbsp;check-vertex
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;vertex,&nbsp;throw&nbsp;an&nbsp;`IllegalArgumentException`&nbsp;with&nbsp;an
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;appropriate&nbsp;message;&nbsp;otherwise,&nbsp;returns&nbsp;`o`.&nbsp;Macro,&nbsp;so&nbsp;exception&nbsp;is&nbsp;thrown
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;the&nbsp;calling&nbsp;function.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;`(check-kind-type&nbsp;~o&nbsp;vertex?&nbsp;:vertex))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
057&nbsp;&nbsp;
</span><br/>
<span class="covered" title="22 out of 22 forms covered">
058&nbsp;&nbsp;(defmacro&nbsp;check-vertices
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;sequence&nbsp;of&nbsp;vertices,&nbsp;throw&nbsp;an&nbsp;`IllegalArgumentException`&nbsp;with&nbsp;an
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;appropriate&nbsp;message;&nbsp;otherwise,&nbsp;returns&nbsp;`o`.&nbsp;Macro,&nbsp;so&nbsp;exception&nbsp;is&nbsp;thrown
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;the&nbsp;calling&nbsp;function.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;`(check-kind-type-seq&nbsp;~o&nbsp;vertex?&nbsp;:vertex))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
064&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
065&nbsp;&nbsp;(defn&nbsp;vertex=
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;vertices&nbsp;`v1`,&nbsp;`v2`&nbsp;represent&nbsp;the&nbsp;same&nbsp;vertex.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;[v1&nbsp;v2]
</span><br/>
<span class="partial" title="6 out of 16 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;(check-vertex&nbsp;v1)
</span><br/>
<span class="covered" title="16 out of 16 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;(check-vertex&nbsp;v2)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;(every?
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(=ish&nbsp;(%&nbsp;v1)&nbsp;(%&nbsp;v2))
</span><br/>
<span class="covered" title="13 out of 13 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:x&nbsp;:y&nbsp;:z]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
073&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
074&nbsp;&nbsp;(defn&nbsp;vertex*
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;vertex&nbsp;like&nbsp;`v1`,&nbsp;but&nbsp;with&nbsp;each&nbsp;of&nbsp;its&nbsp;coordinates&nbsp;multiplied
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;by&nbsp;the&nbsp;equivalent&nbsp;vertex&nbsp;in&nbsp;`v2`.&nbsp;It&nbsp;is&nbsp;an&nbsp;error,&nbsp;and&nbsp;an&nbsp;exception&nbsp;will
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;be&nbsp;thrown,&nbsp;if&nbsp;either&nbsp;`v1`&nbsp;or&nbsp;`v2`&nbsp;is&nbsp;not&nbsp;a&nbsp;vertex.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;[v1&nbsp;v2]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[f&nbsp;(fn&nbsp;[v1&nbsp;v2&nbsp;coord]
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*&nbsp;(or&nbsp;(coord&nbsp;v1)&nbsp;0)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;one&nbsp;here&nbsp;is&nbsp;deliberate!
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(coord&nbsp;v2)&nbsp;1)))]
</span><br/>
<span class="covered" title="41 out of 41 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;v1&nbsp;:x&nbsp;(f&nbsp;(check-vertex&nbsp;v1)&nbsp;(check-vertex&nbsp;v2)&nbsp;:x)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:y&nbsp;(f&nbsp;v1&nbsp;v2&nbsp;:y)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:z&nbsp;(f&nbsp;v1&nbsp;v2&nbsp;:z))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
086&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
087&nbsp;&nbsp;(defn&nbsp;vertex
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&quot;Make&nbsp;a&nbsp;vertex&nbsp;with&nbsp;this&nbsp;`x`,&nbsp;`y`&nbsp;and&nbsp;(if&nbsp;provided)&nbsp;`z`&nbsp;values.&nbsp;Returns&nbsp;a&nbsp;map
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;with&nbsp;those&nbsp;values,&nbsp;plus&nbsp;a&nbsp;unique&nbsp;`:walkmap.id&#x2F;id`&nbsp;value,&nbsp;and&nbsp;`:kind`&nbsp;set&nbsp;to&nbsp;`:vertex`.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;It&#x27;s&nbsp;not&nbsp;necessary&nbsp;to&nbsp;use&nbsp;this&nbsp;function&nbsp;to&nbsp;create&nbsp;a&nbsp;vertex,&nbsp;but&nbsp;the&nbsp;`:walkmap.id&#x2F;id`
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;must&nbsp;be&nbsp;present&nbsp;and&nbsp;must&nbsp;be&nbsp;unique.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;([x&nbsp;y]
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[v&nbsp;{:x&nbsp;x&nbsp;:y&nbsp;y&nbsp;:kind&nbsp;:vertex}]
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;v&nbsp;:walkmap.id&#x2F;id&nbsp;(vertex-key&nbsp;v))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;([x&nbsp;y&nbsp;z]
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[v&nbsp;{:x&nbsp;x&nbsp;:y&nbsp;y&nbsp;:z&nbsp;z&nbsp;:kind&nbsp;:vertex}]
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;v&nbsp;:walkmap.id&#x2F;id&nbsp;(vertex-key&nbsp;v)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
098&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
099&nbsp;&nbsp;(defn&nbsp;canonicalise
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;a&nbsp;map&nbsp;with&nbsp;numeric&nbsp;values&nbsp;for&nbsp;`:x`,&nbsp;`:y`&nbsp;and&nbsp;optionally&nbsp;`:z`,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;upgrade&nbsp;it&nbsp;to&nbsp;something&nbsp;we&nbsp;will&nbsp;recognise&nbsp;as&nbsp;a&nbsp;vertex.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;[o]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;(if
</span><br/>
<span class="partial" title="16 out of 17 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map?&nbsp;o)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(number?&nbsp;(:x&nbsp;o))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(number?&nbsp;(:y&nbsp;o))
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(nil?&nbsp;(:z&nbsp;o))&nbsp;(number?&nbsp;(:z&nbsp;o))))
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;o&nbsp;:kind&nbsp;:vertex&nbsp;:walkmap.id&#x2F;id&nbsp;(vertex-key&nbsp;o))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(IllegalArgumentException.
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(truncate
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Not&nbsp;a&nbsp;proto-vertex:&nbsp;must&nbsp;have&nbsp;numeric&nbsp;`:x`&nbsp;and&nbsp;`:y`:&nbsp;&quot;
</span><br/>
<span class="partial" title="5 out of 6 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;o&nbsp;&quot;nil&quot;))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;80)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
116&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
117&nbsp;&nbsp;(def&nbsp;ensure3d
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;&quot;Given&nbsp;a&nbsp;vertex&nbsp;`o`,&nbsp;if&nbsp;`o`&nbsp;has&nbsp;a&nbsp;`:z`&nbsp;value,&nbsp;just&nbsp;return&nbsp;`o`;&nbsp;otherwise
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;a&nbsp;vertex&nbsp;like&nbsp;`o`&nbsp;but&nbsp;having&nbsp;this&nbsp;`dflt`&nbsp;value&nbsp;as&nbsp;the&nbsp;value&nbsp;of&nbsp;its
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
120&nbsp;&nbsp;&nbsp;&nbsp;`:z`&nbsp;key,&nbsp;or&nbsp;zero&nbsp;as&nbsp;the&nbsp;value&nbsp;of&nbsp;its&nbsp;`:z`&nbsp;key&nbsp;if&nbsp;`dflt`&nbsp;is&nbsp;not&nbsp;specified.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
121&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
122&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;`o`&nbsp;is&nbsp;not&nbsp;a&nbsp;vertex,&nbsp;throws&nbsp;an&nbsp;exception.&quot;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;(memoize
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
124&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;([o]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ensure3d&nbsp;o&nbsp;0.0))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
127&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;([o&nbsp;dflt]
</span><br/>
<span class="partial" title="9 out of 19 forms covered">
128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(:z&nbsp;(check-vertex&nbsp;o))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;o
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
130&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;o&nbsp;:z&nbsp;dflt))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
131&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
132&nbsp;&nbsp;(def&nbsp;ensure2d
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
133&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;`o`&nbsp;is&nbsp;a&nbsp;vertex,&nbsp;set&nbsp;its&nbsp;`:z`&nbsp;value&nbsp;to&nbsp;zero;&nbsp;else&nbsp;throw&nbsp;an&nbsp;exception.&quot;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;(memoize
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
135&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[o]
</span><br/>
<span class="partial" title="10 out of 20 forms covered">
136&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;(check-vertex&nbsp;o)&nbsp;:z&nbsp;0.0))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
137&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
138&nbsp;&nbsp;(defn&nbsp;within-box?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
139&nbsp;&nbsp;&nbsp;&nbsp;&quot;True&nbsp;if&nbsp;`target`&nbsp;is&nbsp;within&nbsp;the&nbsp;box&nbsp;defined&nbsp;by&nbsp;`minv`&nbsp;and&nbsp;`maxv`.&nbsp;All
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
140&nbsp;&nbsp;&nbsp;&nbsp;arguments&nbsp;must&nbsp;be&nbsp;vertices;&nbsp;additionally,&nbsp;both&nbsp;`minv`&nbsp;and&nbsp;`maxv`&nbsp;must
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
141&nbsp;&nbsp;&nbsp;&nbsp;have&nbsp;`:z`&nbsp;coordinates.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
142&nbsp;&nbsp;&nbsp;&nbsp;[target&nbsp;minv&nbsp;maxv]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
143&nbsp;&nbsp;&nbsp;&nbsp;(do
</span><br/>
<span class="covered" title="34 out of 34 forms covered">
144&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(check-vertices&nbsp;[target&nbsp;minv&nbsp;maxv])
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
146&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;true?
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
147&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
148&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(if&nbsp;(%&nbsp;target)
</span><br/>
<span class="covered" title="11 out of 11 forms covered">
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;=&nbsp;(%&nbsp;minv)&nbsp;(%&nbsp;target)&nbsp;(%&nbsp;maxv))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;true)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
151&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:x&nbsp;:y&nbsp;:z]))))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,171 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>Dali performance</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Walkmap</span> <span class="project-version">0.1.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 current"><a href="dali-performance.html"><div class="inner"><span>Dali performance</span></div></a></li><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to walkmap</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>walkmap</span></div></div></li><li class="depth-2 branch"><a href="walkmap.edge.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>edge</span></div></a></li><li class="depth-2 branch"><a href="walkmap.id.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>id</span></div></a></li><li class="depth-2 branch"><a href="walkmap.microworld.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>microworld</span></div></a></li><li class="depth-2 branch"><a href="walkmap.ocean.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>ocean</span></div></a></li><li class="depth-2 branch"><a href="walkmap.path.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>path</span></div></a></li><li class="depth-2 branch"><a href="walkmap.polygon.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>polygon</span></div></a></li><li class="depth-2 branch"><a href="walkmap.read-svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>read-svg</span></div></a></li><li class="depth-2 branch"><a href="walkmap.routing.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>routing</span></div></a></li><li class="depth-2 branch"><a href="walkmap.stl.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>stl</span></div></a></li><li class="depth-2 branch"><a href="walkmap.superstructure.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>superstructure</span></div></a></li><li class="depth-2 branch"><a href="walkmap.svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>svg</span></div></a></li><li class="depth-2 branch"><a href="walkmap.tag.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>tag</span></div></a></li><li class="depth-2 branch"><a href="walkmap.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="walkmap.vertex.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>vertex</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#dali-performance" name="dali-performance"></a>Dali performance</h1>
<p>Notes written while trying to characterise the performance problem in Dali.</p>
<h2><a href="#hypothesis-one-its-the-way-i-format-the-polygons-thats-the-issue" name="hypothesis-one-its-the-way-i-format-the-polygons-thats-the-issue"></a>Hypothesis one: its the way I format the polygons thats the issue</h2>
<p>Firstly, with both versions of <code>stl-&gt;svg</code> using the same version of <code>facet-&gt;svg-poly</code>, i.e. this one:</p>
<pre><code>(defn- facet-&gt;svg-poly
[facet]
[:polygon
{:points (s/join " " (map #(str (:x %) "," (:y %)) (:vertices facet)))}])
</code></pre>
<p>we get this performance using the smaller <code>isle_of_man</code> map:</p>
<pre><code>walkmap.svg=&gt; (def ^:dynamic *preferred-svg-render* :hiccup)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=&gt; (time (def hiccup (binary-stl-file-&gt;svg "resources/isle_of_man.stl" "resources/isle_of_man.svg")))
20-05-25 09:21:43 mason INFO [walkmap.svg:82] - Generating SVG for :hiccup renderer
20-05-25 09:21:43 mason INFO [walkmap.svg:96] - Emitting SVG with :hiccup renderer
"Elapsed time: 86.904891 msecs"
#'walkmap.svg/hiccup
walkmap.svg=&gt; (def ^:dynamic *preferred-svg-render* :dali)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=&gt; (time (def dali (binary-stl-file-&gt;svg "resources/isle_of_man.stl" "resources/isle_of_man.svg")))
20-05-25 09:22:17 mason INFO [walkmap.svg:82] - Generating SVG for :dali renderer
20-05-25 09:22:17 mason INFO [walkmap.svg:96] - Emitting SVG with :dali renderer
"Elapsed time: 890.863814 msecs"
#'walkmap.svg/dali
</code></pre>
<p>If we switch the Dali render to use my original version of <code>facet-&gt;svg-poly</code>, i.e. this one:</p>
<pre><code>(defn- dali-facet-&gt;svg-poly
[facet]
(vec
(cons
:polygon
(map #(vec (list (:x %) (:y %))) (:vertices facet)))))
</code></pre>
<p>we get this performance:</p>
<pre><code>walkmap.svg=&gt; (def ^:dynamic *preferred-svg-render* :hiccup)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=&gt; (time (def hiccup (binary-stl-file-&gt;svg "resources/isle_of_man.stl" "resources/isle_of_man.svg")))
20-05-25 09:35:33 mason INFO [walkmap.svg:82] - Generating SVG for :hiccup renderer
20-05-25 09:35:33 mason INFO [walkmap.svg:96] - Emitting SVG with :hiccup renderer
"Elapsed time: 84.09972 msecs"
#'walkmap.svg/hiccup
walkmap.svg=&gt; (def ^:dynamic *preferred-svg-render* :dali)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=&gt; (time (def dali (binary-stl-file-&gt;svg "resources/isle_of_man.stl" "resources/isle_of_man.svg")))
20-05-25 09:35:41 mason INFO [walkmap.svg:82] - Generating SVG for :dali renderer
20-05-25 09:35:41 mason INFO [walkmap.svg:96] - Emitting SVG with :dali renderer
"Elapsed time: 874.292007 msecs"
#'walkmap.svg/dali
</code></pre>
<p>No significant difference in performance.</p>
<p>If we generate but dont render, we get this:</p>
<pre><code>walkmap.svg=&gt; (def ^:dynamic *preferred-svg-render* :hiccup)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=&gt; (time (def hiccup (binary-stl-file-&gt;svg "resources/isle_of_man.stl")))
20-05-25 09:37:44 mason INFO [walkmap.svg:82] - Generating SVG for :hiccup renderer
"Elapsed time: 52.614707 msecs"
#'walkmap.svg/hiccup
walkmap.svg=&gt; (def ^:dynamic *preferred-svg-render* :dali)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=&gt; (time (def dali (binary-stl-file-&gt;svg "resources/isle_of_man.stl")))
20-05-25 09:38:07 mason INFO [walkmap.svg:82] - Generating SVG for :dali renderer
"Elapsed time: 49.891043 msecs"
#'walkmap.svg/dali
</code></pre>
<p>This implies that the problem is not in the way polygons are formatted.</p>
<p>The difference between the two versions of <code>facet-&gt;svg-poly</code> is as follows:</p>
<h3><a href="#new-version-works-with-both-hiccup-and-dali-" name="new-version-works-with-both-hiccup-and-dali-"></a>New version, works with both Hiccup and Dali:</h3>
<pre><code>walkmap.svg=&gt; (def stl (decode-binary-stl "resources/isle_of_man.stl"))
#'walkmap.svg/stl
walkmap.svg=&gt; (def facet (first (:facets stl)))
#'walkmap.svg/facet
walkmap.svg=&gt; (pprint facet)
{:normal {:x -0.0, :y 0.0, :z 1.0},
:vertices
[{:x 3.0, :y 1.0, :z 1.0}
{:x 2.0, :y 3.0, :z 1.0}
{:x 0.0, :y 0.0, :z 1.0}],
:abc 0}
nil
walkmap.svg=&gt; (pprint (facet-&gt;svg-poly facet))
[:polygon {:points "3.0,1.0 2.0,3.0 0.0,0.0"}]
nil
</code></pre>
<p>In other words, the new version constructs the <code>:points</code> attribute of the <code>:polygon</code> tag by string concatenation, and the renderer just needs to output it.</p>
<h3><a href="#older-version-works-with-dali-only-" name="older-version-works-with-dali-only-"></a>Older version, works with Dali only:</h3>
<pre><code>walkmap.svg=&gt; (pprint (dali-facet-&gt;svg-poly facet))
[:polygon [3.0 1.0] [2.0 3.0] [0.0 0.0]]
nil
</code></pre>
<p>This means that the renderer is actually doing more work, since it has to compose the <code>:points</code> attribute itself; nevertheless there doesnt seem to be an increased time penalty.</p>
<h3><a href="#conclusion" name="conclusion"></a>Conclusion</h3>
<p>It doesnt seem that formatting the polygons is the issue.</p>
<h2><a href="#hypothesis-two-dali-renderer-scales-non-linearly-with-number-of-objects-drawn" name="hypothesis-two-dali-renderer-scales-non-linearly-with-number-of-objects-drawn"></a>Hypothesis two: Dali renderer scales non-linearly with number of objects drawn</h2>
<p>To test this, we need some otherwise-similar test files with different numbers of objects:</p>
<pre><code>walkmap.svg=&gt; (count (:facets stl))
4416
walkmap.svg=&gt; (def small-stl (assoc stl :facets (take 400 (:facets stl))))
#'walkmap.svg/small-stl
walkmap.svg=&gt; (count (:facets small-stl))
400
walkmap.svg=&gt; (def large-stl (decode-binary-stl "../the-great-game/resources/maps/heightmap.stl"))
#'walkmap.svg/large-stl
walkmap.svg=&gt; (count (:facets large-stl))
746585
walkmap.svg=&gt; (def ^:dynamic *preferred-svg-render* :dali)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=&gt; (time (dali.io/render-svg (stl-&gt;svg small-stl) "dali-small.svg"))
20-05-25 10:12:25 mason INFO [walkmap.svg:92] - Generating SVG for :dali renderer
"Elapsed time: 32.55506 msecs"
nil
walkmap.svg=&gt; (def ^:dynamic *preferred-svg-render* :hiccup)
#'walkmap.svg/*preferred-svg-render*
walkmap.svg=&gt; (time (spit "hiccup-small.svg" (hiccup.core/html (stl-&gt;svg small-stl))))
20-05-25 10:14:07 mason INFO [walkmap.svg:92] - Generating SVG for :hiccup renderer
"Elapsed time: 10.026369 msecs"
</code></pre>
<p>So we have</p>
<table>
<thead>
<tr>
<th> </th>
<th>Dali </th>
<th> </th>
<th>Hiccup </th>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td># of facets </td>
<td>time (msecs) </td>
<td>objets/msec </td>
<td>time (msecs) </td>
<td>objets/msec </td>
<td>ratio (Dali/Hiccup) </td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<td>400 </td>
<td>32.55506 </td>
<td>12.29 </td>
<td>10.026369 </td>
<td>39.89 </td>
<td>3.35 </td>
</tr>
<tr>
<td>4416 </td>
<td>874.292007 </td>
<td>5.05 </td>
<td>84.09972 </td>
<td>52.51 </td>
<td>10.40 </td>
</tr>
<tr>
<td>746585 </td>
<td>29,695,695.61 </td>
<td>0.03 </td>
<td>16724.848222 </td>
<td>44.64 </td>
<td>1775.54 </td>
</tr>
</tbody>
</table>
<h3><a href="#conclusion" name="conclusion"></a>Conclusion</h3>
<p>What were seeing is that Hiccup renders more or less linearly by the number of objects (bear in mind that all of these objects are triangles, so essentially equally complex to render), whereas trhe performance of Dali degrades significantly as the number of objects increases.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>Introduction to walkmap</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Walkmap</span> <span class="project-version">0.1.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 current"><a href="intro.html"><div class="inner"><span>Introduction to walkmap</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>walkmap</span></div></div></li><li class="depth-2 branch"><a href="walkmap.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="walkmap.edge.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>edge</span></div></a></li><li class="depth-2 branch"><a href="walkmap.geometry.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>geometry</span></div></a></li><li class="depth-2 branch"><a href="walkmap.path.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>path</span></div></a></li><li class="depth-2 branch"><a href="walkmap.polygon.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>polygon</span></div></a></li><li class="depth-2 branch"><a href="walkmap.stl.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>stl</span></div></a></li><li class="depth-2 branch"><a href="walkmap.svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>svg</span></div></a></li><li class="depth-2"><a href="walkmap.vertex.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>vertex</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#introduction-to-walkmap" name="introduction-to-walkmap"></a>Introduction to walkmap</h1>
<html><head><meta charset="UTF-8" /><title>Introduction to walkmap</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Walkmap</span> <span class="project-version">0.1.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="dali-performance.html"><div class="inner"><span>Dali performance</span></div></a></li><li class="depth-1 current"><a href="intro.html"><div class="inner"><span>Introduction to walkmap</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>walkmap</span></div></div></li><li class="depth-2 branch"><a href="walkmap.edge.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>edge</span></div></a></li><li class="depth-2 branch"><a href="walkmap.id.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>id</span></div></a></li><li class="depth-2 branch"><a href="walkmap.microworld.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>microworld</span></div></a></li><li class="depth-2 branch"><a href="walkmap.ocean.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>ocean</span></div></a></li><li class="depth-2 branch"><a href="walkmap.path.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>path</span></div></a></li><li class="depth-2 branch"><a href="walkmap.polygon.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>polygon</span></div></a></li><li class="depth-2 branch"><a href="walkmap.read-svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>read-svg</span></div></a></li><li class="depth-2 branch"><a href="walkmap.routing.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>routing</span></div></a></li><li class="depth-2 branch"><a href="walkmap.stl.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>stl</span></div></a></li><li class="depth-2 branch"><a href="walkmap.superstructure.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>superstructure</span></div></a></li><li class="depth-2 branch"><a href="walkmap.svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>svg</span></div></a></li><li class="depth-2 branch"><a href="walkmap.tag.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>tag</span></div></a></li><li class="depth-2 branch"><a href="walkmap.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="walkmap.vertex.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>vertex</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#introduction-to-walkmap" name="introduction-to-walkmap"></a>Introduction to walkmap</h1>
<p>This library is written in support of work on <a href="https://simon-brooke.github.io/the-great-game/codox/Pathmaking.html">The Great Game</a>, but is separate because it may be of some use in other settings.</p>
<h2><a href="#usage" name="usage"></a>Usage</h2>
<p>What works:</p>
@ -10,6 +10,10 @@
<p>Lein dependency:</p>
<pre><code>[walkmap "0.1.0-SNAPSHOT"]
</code></pre>
<ul>
<li><a href="https://simon-brooke.github.io/walkmap/codox/index.html">API documentation</a></li>
<li><a href="https://simon-brooke.github.io/walkmap/cloverage/index.html">Test coverage</a></li>
</ul>
<h3><a href="#converting-heightmaps-to-stl" name="converting-heightmaps-to-stl"></a>Converting heightmaps to STL</h3>
<p>Doesnt work yet, and is not a priority. Use <a href="https://github.com/fogleman/hmm">hmm</a> instead.</p>
<h3><a href="#reading-binary-stl-files" name="reading-binary-stl-files"></a>Reading binary STL files</h3>
@ -36,10 +40,19 @@
<pre><code>(require '[walkmap.core :refer [binary-stl-file-&gt;svg]])
(binary-stl-file-&gt;svg "path/to/input-file.stl" "path-to-output-file.svg")
</code></pre>
<p>As above, but, as a side effect, writes the SVG to the specified output file. Works for smaller test files, as above.</p>
<p>As above, but, as a side effect, writes the SVG to the specified output file.</p>
<h3><a href="#merging-exclusion-maps-and-reserved-area-maps" name="merging-exclusion-maps-and-reserved-area-maps"></a>Merging exclusion maps and reserved area maps</h3>
<p>It is intended that it should be possible to merge exclusion maps (maps of areas which should be excluded from the traversable area) with maps derived from height maps. These exclusion maps will probably be represented as SVG.</p>
<p>This is not yet implemented.</p>
<p>Culling facets in ocean areas is implemented and works:</p>
<pre><code>(require '[walkmap.core :refer [cull-ocean-facets *sea-level*]])
(cull-ocean-facets stl)
</code></pre>
<p>If sea level in your heightmaps is not zero, e.g. is 5, set it thus:</p>
<pre><code>(def ^:dynamic *sea-level* 5.0)
(cull-ocean-facets stl)
</code></pre>
<p>It is <strong>strongly recomended</strong> that you set <code>*sea-level*</code> to a floating point number, not an integer, because numbers are specified in the STL file as floating point, and in Clojure, <code>(= 5 5.0)</code> returns <code>false</code>.</p>
<h3><a href="#merging-road-maps-and-river-system-maps" name="merging-road-maps-and-river-system-maps"></a>Merging road maps and river system maps</h3>
<p>It is intended that it should be possible to merge road maps (maps of already computed routes) with maps derived from height maps. These exclusion maps will probably be represented as SVG. This is not yet implemented.</p>
<p>River system maps are conceptually similar to road maps; this too is not yet implemented.</p>

View file

@ -1,4 +1,3 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>walkmap.core documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Walkmap</span> <span class="project-version">0.1.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to walkmap</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>walkmap</span></div></div></li><li class="depth-2 branch current"><a href="walkmap.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="walkmap.edge.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>edge</span></div></a></li><li class="depth-2 branch"><a href="walkmap.geometry.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>geometry</span></div></a></li><li class="depth-2 branch"><a href="walkmap.path.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>path</span></div></a></li><li class="depth-2 branch"><a href="walkmap.polygon.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>polygon</span></div></a></li><li class="depth-2 branch"><a href="walkmap.stl.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>stl</span></div></a></li><li class="depth-2 branch"><a href="walkmap.svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>svg</span></div></a></li><li class="depth-2"><a href="walkmap.vertex.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>vertex</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="walkmap.core.html#var-*sea-level*"><div class="inner"><span>*sea-level*</span></div></a></li><li class="depth-1"><a href="walkmap.core.html#var-binary-stl-file-.3Esvg"><div class="inner"><span>binary-stl-file-&gt;svg</span></div></a></li><li class="depth-1"><a href="walkmap.core.html#var-cull-ocean-facets"><div class="inner"><span>cull-ocean-facets</span></div></a></li><li class="depth-1"><a href="walkmap.core.html#var-ocean.3F"><div class="inner"><span>ocean?</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">walkmap.core</h1><div class="doc"><div class="markdown"><p>At this stage, primarily utility functions dealing with stereolithography (STL) files. Not a stable API yet!</p></div></div><div class="public anchor" id="var-*sea-level*"><h3>*sea-level*</h3><h4 class="dynamic">dynamic</h4><div class="usage"></div><div class="doc"><div class="markdown"><p>The sea level on heightmaps were 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.</p>
<p><strong>Note</strong> must be a floating point number. <code>(= 0 0.0)</code> returns <code>false</code>!</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/core.clj#L12">view source</a></div></div><div class="public anchor" id="var-binary-stl-file-.3Esvg"><h3>binary-stl-file-&gt;svg</h3><div class="usage"><code>(binary-stl-file-&gt;svg in-filename)</code><code>(binary-stl-file-&gt;svg in-filename out-filename)</code></div><div class="doc"><div class="markdown"><p>Given only an <code>in-filename</code>, parse the indicated file, expected to be binary STL, and return an equivalent SVG structure. Given both <code>in-filename</code> and <code>out-filename</code>, as side-effect write the SVG to the indicated output file.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/core.clj#L34">view source</a></div></div><div class="public anchor" id="var-cull-ocean-facets"><h3>cull-ocean-facets</h3><div class="usage"><code>(cull-ocean-facets stl)</code></div><div class="doc"><div class="markdown"><p>Ye cannae walk on water. Remove all facets from this <code>stl</code> structure which are at sea level.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/core.clj#L28">view source</a></div></div><div class="public anchor" id="var-ocean.3F"><h3>ocean?</h3><div class="usage"><code>(ocean? facet)</code></div><div class="doc"><div class="markdown"><p>Of a <code>facet</code>, is the altitude of every vertice equal to <code>*sea-level*</code>?</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/core.clj#L21">view source</a></div></div></div></body></html>
<html><head><meta charset="UTF-8" /><title>walkmap.core documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Walkmap</span> <span class="project-version">0.1.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="dali-performance.html"><div class="inner"><span>Dali performance</span></div></a></li><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to walkmap</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>walkmap</span></div></div></li><li class="depth-2 branch current"><a href="walkmap.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="walkmap.edge.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>edge</span></div></a></li><li class="depth-2 branch"><a href="walkmap.geometry.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>geometry</span></div></a></li><li class="depth-2 branch"><a href="walkmap.ocean.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>ocean</span></div></a></li><li class="depth-2 branch"><a href="walkmap.path.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>path</span></div></a></li><li class="depth-2 branch"><a href="walkmap.polygon.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>polygon</span></div></a></li><li class="depth-2 branch"><a href="walkmap.stl.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>stl</span></div></a></li><li class="depth-2 branch"><a href="walkmap.superstructure.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>superstructure</span></div></a></li><li class="depth-2 branch"><a href="walkmap.svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>svg</span></div></a></li><li class="depth-2 branch"><a href="walkmap.tag.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>tag</span></div></a></li><li class="depth-2 branch"><a href="walkmap.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="walkmap.vertex.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>vertex</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">walkmap.core</h1><div class="doc"><div class="markdown"><p>This namespace mostly gets used as a scratchpad for ideas which havent yet solidified.</p></div></div></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,3 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>walkmap.geometry documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Walkmap</span> <span class="project-version">0.1.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to walkmap</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>walkmap</span></div></div></li><li class="depth-2 branch"><a href="walkmap.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="walkmap.edge.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>edge</span></div></a></li><li class="depth-2 branch current"><a href="walkmap.geometry.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>geometry</span></div></a></li><li class="depth-2 branch"><a href="walkmap.path.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>path</span></div></a></li><li class="depth-2 branch"><a href="walkmap.polygon.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>polygon</span></div></a></li><li class="depth-2 branch"><a href="walkmap.stl.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>stl</span></div></a></li><li class="depth-2 branch"><a href="walkmap.svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>svg</span></div></a></li><li class="depth-2"><a href="walkmap.vertex.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>vertex</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="walkmap.geometry.html#var-collinear.3F"><div class="inner"><span>collinear?</span></div></a></li><li class="depth-1"><a href="walkmap.geometry.html#var-on.3F"><div class="inner"><span>on?</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">walkmap.geometry</h1><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p></div></div><div class="public anchor" id="var-collinear.3F"><h3>collinear?</h3><div class="usage"><code>(collinear? v1 v2 v3)</code></div><div class="doc"><div class="markdown"><p>True if these vertices <code>v1</code>, <code>v2</code>, <code>v3</code> are colinear; false otherwise.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/geometry.clj#L9">view source</a></div></div><div class="public anchor" id="var-on.3F"><h3>on?</h3><div class="usage"><code>(on? e v)</code></div><div class="doc"><div class="markdown"><p>True if the vertex <code>v</code> is on the edge <code>e</code>.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/geometry.clj#L42">view source</a></div></div></div></body></html>
<html><head><meta charset="UTF-8" /><title>walkmap.geometry documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Walkmap</span> <span class="project-version">0.1.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="dali-performance.html"><div class="inner"><span>Dali performance</span></div></a></li><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to walkmap</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>walkmap</span></div></div></li><li class="depth-2 branch"><a href="walkmap.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="walkmap.edge.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>edge</span></div></a></li><li class="depth-2 branch current"><a href="walkmap.geometry.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>geometry</span></div></a></li><li class="depth-2 branch"><a href="walkmap.ocean.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>ocean</span></div></a></li><li class="depth-2 branch"><a href="walkmap.path.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>path</span></div></a></li><li class="depth-2 branch"><a href="walkmap.polygon.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>polygon</span></div></a></li><li class="depth-2 branch"><a href="walkmap.stl.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>stl</span></div></a></li><li class="depth-2 branch"><a href="walkmap.superstructure.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>superstructure</span></div></a></li><li class="depth-2 branch"><a href="walkmap.svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>svg</span></div></a></li><li class="depth-2 branch"><a href="walkmap.tag.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>tag</span></div></a></li><li class="depth-2 branch"><a href="walkmap.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="walkmap.vertex.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>vertex</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">walkmap.geometry</h1><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p></div></div></div></body></html>

View file

@ -0,0 +1,3 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>walkmap.id documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Walkmap</span> <span class="project-version">0.1.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="dali-performance.html"><div class="inner"><span>Dali performance</span></div></a></li><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to walkmap</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>walkmap</span></div></div></li><li class="depth-2 branch"><a href="walkmap.edge.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>edge</span></div></a></li><li class="depth-2 branch current"><a href="walkmap.id.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>id</span></div></a></li><li class="depth-2 branch"><a href="walkmap.microworld.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>microworld</span></div></a></li><li class="depth-2 branch"><a href="walkmap.ocean.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>ocean</span></div></a></li><li class="depth-2 branch"><a href="walkmap.path.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>path</span></div></a></li><li class="depth-2 branch"><a href="walkmap.polygon.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>polygon</span></div></a></li><li class="depth-2 branch"><a href="walkmap.read-svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>read-svg</span></div></a></li><li class="depth-2 branch"><a href="walkmap.routing.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>routing</span></div></a></li><li class="depth-2 branch"><a href="walkmap.stl.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>stl</span></div></a></li><li class="depth-2 branch"><a href="walkmap.superstructure.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>superstructure</span></div></a></li><li class="depth-2 branch"><a href="walkmap.svg.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>svg</span></div></a></li><li class="depth-2 branch"><a href="walkmap.tag.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>tag</span></div></a></li><li class="depth-2 branch"><a href="walkmap.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="walkmap.vertex.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>vertex</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="walkmap.id.html#var-id"><div class="inner"><span>id</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">walkmap.id</h1><div class="doc"><div class="markdown"><p>The namespace within which the privileged keyword <code>:walkmap.id/id</code> is defined.</p></div></div><div class="public anchor" id="var-id"><h3>id</h3><div class="usage"></div><div class="doc"><div class="markdown"><p>The magic id key walkmap uses, to distinguish it from all other uses of the unprotected keyword.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/id.clj#L4">view source</a></div></div></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -4,13 +4,20 @@
:doc/format :markdown}
:output-path "docs/codox"
:source-uri "https://github.com/simon-brooke/walkmap/blob/master/{filepath}#L{line}"}
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/math.numeric-tower "0.0.4"]
[org.clojure/math.combinatorics "0.1.6"]
[com.taoensso/timbre "4.10.0"]
[dali "0.7.4"] ;; not currently used because performance issues.
:dependencies [[org.clojure/algo.generic "1.0.0"]
[org.clojure/core.memoize "1.1.266"]
[org.clojure/clojure "1.11.2"]
[org.clojure/data.zip "1.1.0"]
[org.clojure/math.numeric-tower "0.1.0"]
[org.clojure/math.combinatorics "0.3.0"]
[com.taoensso/timbre "6.5.0"]
;; [dali "1.0.2"] ;; not currently used because performance issues.
[hiccup "1.0.5"]
[macroz/search "0.3.0"]
[me.raynes/fs "1.4.6"]
[mw-engine "0.3.0-SNAPSHOT"]
[net.mikera/core.matrix "0.63.0"]
[net.mikera/vectorz-clj "0.48.0"]
[smee/binary "0.5.5"]]
:deploy-repositories [["releases" :clojars]
["snapshots" :clojars]]
@ -18,7 +25,9 @@
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url "https://www.eclipse.org/legal/epl-2.0/"}
:plugins [[lein-cloverage "1.1.1"]
[lein-codox "0.10.7"]]
[lein-codox "0.10.7"]
[org.clojars.benfb/lein-gorilla "0.7.0"]
]
:release-tasks [["vcs" "assert-committed"]
["change" "version" "leiningen.release/bump-version" "release"]
["vcs" "commit"]
@ -29,5 +38,5 @@
["uberjar"]
["change" "version" "leiningen.release/bump-version"]
["vcs" "commit"]]
:repl-options {:init-ns walkmap.core}
:repl-options {:init-ns cc.journeyman.walkmap.superstructure}
:url "https://simon-brooke.github.io/walkmap/")

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

Before

(image error) Size: 6.1 KiB

After

(image error) Size: 6.1 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -0,0 +1,155 @@
# Human settlement
;; This rule set attempts to model human settlement in a landscape. It models
;; western European pre-history moderately well. Settlement first occurs as
;; nomadic camps on coastal promentaries (cells with four or more neighbours
;; that are water). This represents 'kitchen-midden' mesolithic settlement.
;;
;; As grassland becomes available near camps, pastoralists appear, and will
;; follow their herds inland. When pastoralists have available fertile land,
;; they will till the soil and plant crops, and in doing so will establish
;; permanent settlements; this is approximately a neolithic stage.
;;
;; Where soil is fertile, settlements will cluster, and markets will appear.
;; where there is sufficient settlement, the markets become permanent, and you
;; have the appearance of towns. This takes us roughly into the bronze age.
;;
;; This is quite a complex ruleset, and runs quite slowly. However, it does
;; model some significant things. Soil gains in fertility under woodland; deep
;; loams and podzols build up over substantial time. Agriculture depletes
;; fertility. So if forest has become well established before human settlement
;; begins, a higher population (more crops) will eventually be sustainable,
;; whereas if human population starts early the deep fertile soils will not
;; establish and you will have more pastoralism, supporting fewer permanent
;; settlements.
;; hack to speed up processing on the 'great britain and ireland' map
if state is water then state should be water
;; nomads make their first significant camp near water because of fish and
;; shellfish (kitchen-midden people)
if state is in grassland or heath and more than 3 neighbours are water and generation is more than 20 then state should be camp
;; sooner or later nomads learn to keep flocks
if state is in grassland or heath and some neighbours are camp then 1 chance in 2 state should be pasture
;; and more herds support more people
if state is in grassland or heath and more than 2 neighbours are pasture then 1 chance in 3 state should be camp
if state is pasture and more than 3 neighbours are pasture and fewer than 1 neighbours are camp and fewer than 1 neighbours within 2 are house then state should be camp
;; the idea of agriculture spreads
if state is in grassland or heath and some neighbours within 2 are house then state should be pasture
;; nomads don't move on while the have crops growing. That would be silly!
if state is camp and some neighbours are ploughland then state should be camp
;; Impoverished pasture can't be grazed permanently
if state is pasture and fertility is less than 2 then 1 chance in 3 state should be heath
;; nomads move on
if state is camp then 1 chance in 5 state should be waste
;; pasture that's too far from a house or camp will be abandoned
if state is pasture and fewer than 1 neighbours within 3 are house and fewer than 1 neighbours within 2 are camp then state should be heath
;; markets spring up near settlements
if state is in grassland or pasture and more than 1 neighbours are house then 1 chance in 10 state should be market
;; good fertile pasture close to settlement will be ploughed for crops
if state is pasture and fertility is more than 10 and altitude is less than 100 and some neighbours are camp or some neighbours are house then state should be ploughland
if state is ploughland then state should be crop
;; after the crop is harvested, the land is allowed to lie fallow. But cropping
;; depletes fertility.
if state is crop then state should be grassland and fertility should be fertility - 1
;; if there's reliable food available, nomads build permanent settlements
if state is in camp or abandoned and some neighbours are crop then state should be house
if state is abandoned and some neighbours are pasture then state should be house
;; people camp near to markets
if state is in waste or grassland and some neighbours are market then state should be camp
;; a market in a settlement survives
if state is market and some neighbours are inn then state should be market
if state is market then state should be grassland
;; a house near a market in a settlement will become an inn
if state is house and some neighbours are market and more than 1 neighbours are house then 1 chance in 5 state should be inn
;; but it will need some local custom to survive
if state is inn and fewer than 3 neighbours are house then state should be house
;; if there aren't enough resources houses should be abandoned
;; resources from fishing
if state is house and more than 2 neighbours are water then state should be house
;; from farming
if state is house and some neighbours are pasture then state should be house
if state is house and some neighbours are ploughland then state should be house
if state is house and some neighbours are crop then state should be house
;; from the market
if state is house and some neighbours are market then state should be house
if state is house then 1 chance in 2 state should be abandoned
if state is abandoned then 1 chance in 5 state should be waste
## Vegetation rules
;; rules which populate the world with plants
;; Occasionally, passing birds plant tree seeds into grassland
if state is grassland then 1 chance in 10 state should be heath
;; heath below the treeline grows gradually into forest
if state is heath and altitude is less than 120 then state should be scrub
if state is scrub then 1 chance in 5 state should be forest
;; Forest on fertile land grows to climax
if state is forest and fertility is more than 5 and altitude is less than 70 then state should be climax
;; Climax forest occasionally catches fire (e.g. lightning strikes)
if state is climax then 1 chance in 500 state should be fire
;; Forest neighbouring fires is likely to catch fire. So are buildings.
if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire
;; Climax forest near to settlement may be cleared for timber
if state is in climax and more than 3 neighbours within 2 are house then state should be scrub
;; After fire we get waste
if state is fire then state should be waste
;; waste near settlement that is fertile becomes ploughland
if state is waste and fertility is more than 10 and some neighbours are house or some neighbours are camp then state should be ploughland
;; And after waste we get pioneer species; if there's a woodland seed
;; source, it's going to be heath, otherwise grassland.
if state is waste and some neighbours are scrub then state should be heath
if state is waste and some neighbours are forest then state should be heath
if state is waste and some neighbours are climax then state should be heath
if state is waste then state should be grassland
## Potential blockers
;; Forest increases soil fertility.
if state is in forest or climax then fertility should be fertility + 1
## Initialisation rules
;; Rules which deal with state 'new' will waste less time if they're near the
;; end of the file
;; below the waterline we have water.
if state is new and altitude is less than 10 then state should be water
;; above the snowline we have snow.
if state is new and altitude is more than 200 then state should be snow
;; otherwise, we have grassland.
if state is new then state should be grassland

View file

@ -0,0 +1,185 @@
(ns cc.journeyman.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."
(:require [clojure.math.numeric-tower :as m]
[cc.journeyman.walkmap.vertex :refer [canonicalise check-vertex ensure2d ensure3d vertex vertex= vertex?]]))
(defn edge
"Return an edge between vertices `v1` and `v2`."
[v1 v2]
{:kind :edge
:walkmap.id/id (keyword (gensym "edge"))
:start (check-vertex v1)
:end (check-vertex v2)})
(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
keys shall be a vertex."
[o]
(and
(map? o)
(vertex? (:start o))
(vertex? (:end o))))
(defn length
"Return the length of the edge `e`."
[e]
(let [start (ensure3d (:start e))
end (ensure3d (:end e))]
(m/sqrt
(reduce
+
(map
#(m/expt (- (% end) (% start)) 2)
[:x :y :z])))))
(defn centre
"Return the vertex that represents the centre of this `edge`."
[edge]
(let [s (ensure3d (:start edge))
e (ensure3d (:end edge))]
(vertex
(+ (:x s) (/ (- (:x e) (:x s)) 2))
(+ (:y s) (/ (- (:y e) (:y s)) 2))
(+ (:z s) (/ (- (:z e) (:z s)) 2)))))
(defn unit-vector
"Return an vertex parallel to `e` starting from the coordinate origin. Two
edges which are parallel will have the same unit vector."
[e]
(let [e' {:start (ensure3d (:start e)) :end (ensure3d (:end e))}
l (length e')]
(canonicalise
(reduce
merge
{}
(map
(fn [k]
{k (/ (- (k (:end e')) (k (:start e'))) l)})
[:x :y :z])))))
(defn parallel?
"True if all `edges` passed are parallel with one another."
[& edges]
(let [uvs (map unit-vector edges)]
(every?
#(vertex= % (first uvs))
(rest uvs))))
(defn collinear?
"True if edges `e1` and `e2` are collinear with one another."
[e1 e2]
(parallel?
e1
e2
(if (vertex= (:start e1) (:start e2))
{:start (:start e1) :end (:end e2)}
{:start (:start e1) :end (:start e2)})))
(defn collinear2d?
"True if the projections of edges `e1`, `e2` onto the x, y plane are
collinear."
[e1 e2]
(collinear? {:start (ensure2d (:start e1)) :end (ensure2d (:end e1))}
{:start (ensure2d (:start e2)) :end (ensure2d (:end e2))}))
(defn minimaxd
"Apply function `f` to `coord` of the vertices at start and end of `edge`
and return the result. Intended use case is `f` = `min` or `max`, `coord`
is `:x`, `:y` or `:z`. No checks are made for sane arguments."
[edge coord f]
(apply f (list (coord (:start edge)) (coord (:end edge)))))
(defn on?
"True if the vertex `v` is on the edge `e`."
[e v]
(let [p (ensure3d (:start e))
q (ensure3d v)
r (ensure3d (:end e))]
(and
(collinear? (edge p q) (edge q r))
(<= (:x q) (max (:x p) (:x r)))
(>= (:x q) (min (:x p) (:x r)))
(<= (:y q) (max (:y p) (:y r)))
(>= (:y q) (min (:y p) (:y r)))
(<= (:z q) (max (:z p) (:z r)))
(>= (:z q) (min (:z p) (:z r))))))
(defn on2d?
"True if vertex `v` is on edge `e` when projected onto the x, y plane."
[e v]
(on? (edge (ensure2d (:start e)) (ensure2d (:end e))) v))
(defn overlaps2d?
"True if the recangle in the x,y plane bisected by edge `e1` overlaps that
bisected by edge `e2`. It is an error if either `e1` or `e2` is not an edge.
If `c1` is passed it should be the first coordinate of the plane of
projection on which the overlap is sought (default: `:x`); similarly `c2`
should be the second such coordinate (default: `:y`)."
([e1 e2]
(overlaps2d? e1 e2 :x :y))
([e1 e2 c1 c2]
(when (and (edge? e1) (edge? e2))
(and
(> (minimaxd e1 c1 max) (minimaxd e2 c1 min))
(< (minimaxd e1 c1 min) (minimaxd e2 c1 max))
(> (minimaxd e1 c2 max) (minimaxd e2 c2 min))
(< (minimaxd e1 c2 min) (minimaxd e2 c2 max))))))
(defn intersection2d
"The probability of two lines intersecting in 3d space is low, and actually
that is mostly not something we're interested in. We're interested in
intersection in the `x,y` plane. This function returns a vertex representing
a point vertically over the intersection of edges `e1`, `e2` in the `x,y`
plane, whose `z` coordinate is
* 0 if both edges are 2d (i.e. have missing or zero `z` coordinates);
* if one edge is 2d, then the point on the other edge over the intersection;
* otherwise, the average of the z coordinates of the points on the two
edges over the intersection.
If no such intersection exists, `nil` is returned.
It is an error, and an exception will be thrown, if either `e1` or `e2` is
not an edge."
([e1 e2]
(intersection2d e1 e2 :x :y :z))
([e1 e2 c1 c2 _c3]
(if (and (edge? e1) (edge? e2))
(when
(overlaps2d? e1 e2) ;; relatively cheap check
(if
(collinear2d? e1 e2)
;; any point within the overlap will do, but we'll pick the end of e1
;; which is on e2
(if (on2d? e2 (:start e1)) (:start e1) (:end e1))
;; blatantly stolen from
;; https://gist.github.com/cassiel/3e725b49670356a9b936
(let [x1 (c1 (:start e1))
x2 (c1 (:end e1))
x3 (c1 (:start e2))
x4 (c1 (:end e2))
y1 (c2 (:start e1))
y2 (c2 (:end e1))
y3 (c2 (:start e2))
y4 (c2 (:end e2))
denom (- (* (- x1 x2) (- y3 y4))
(* (- y1 y2) (- x3 x4)))
x1y2-y1x2 (- (* x1 y2) (* y1 x2))
x3y4-y3x4 (- (* x3 y4) (* y3 x4))
px-num (- (* x1y2-y1x2 (- x3 x4))
(* (- x1 x2) x3y4-y3x4))
py-num (- (* x1y2-y1x2 (- y3 y4))
(* (- y1 y2) x3y4-y3x4))
result (when-not (zero? denom)
(vertex (/ px-num denom) (/ py-num denom)))]
(when (and result (on2d? e1 result) (on2d? e2 result)) result))))
(throw (IllegalArgumentException.
(str
"Both `e1` and `e2` must be edges."
(map #(or (:kind %) (type %)) [e1 e2])))))))

View file

@ -0,0 +1,8 @@
(ns cc.journeyman.walkmap.id
"The namespace within which the privileged keyword `:walkmap.id/id` is defined.")
(def ^:const id
"The magic id key walkmap uses, to distinguish it from all other uses of
the unprotected keyword."
::id)

View file

@ -0,0 +1,75 @@
(ns cc.journeyman.walkmap.microworld
"An interface between walkmap and microworld, to allow use of microworld
functionality to model things like rainfall, soil fertility, settlement
and so on."
(:require [cc.journeyman.walkmap.polygon :refer [rectangle]]
[cc.journeyman.walkmap.superstructure :refer [store]]
[cc.journeyman.walkmap.tag :refer [tag]]
[cc.journeyman.walkmap.vertex :refer [check-vertex vertex]]
[cc.journeyman.walkmap.utils :refer [truncate]]
[clojure.edn :as edn :only [read]]
[clojure.java.io :refer [reader]]
[taoensso.timbre :refer [error]])
(:import [clojure.lang Keyword IPersistentMap]
[java.io PushbackReader]))
(defn cell->polygon
"From this MicroWorld `cell`, construct a walkmap polygon (specifically,
a rectangle). If `scale-vector` passed and is a vertex, scale all the vertices
in the cell by that vector."
([cell]
(cell->polygon cell (vertex 1 1 1)))
([cell scale-vector]
(tag
(assoc
(merge
cell
(let [w (* (:x cell) (:x (check-vertex scale-vector)))
s (* (:y cell) (:y scale-vector))
e (+ w (:x scale-vector))
n (+ s (:y scale-vector))
z (* (:altitude cell) (:z scale-vector))]
(rectangle
(vertex s w z)
(vertex n e z))))
:walkmap.id/id
(keyword (gensym "mw-cell")))
(:state cell))))
(defn load-microworld-edn
"While it would be possible to call MicroWorld functions directly from
Walkmap, the fact is that running MicroWorld is so phenomenally
compute-heavy that it's much more sensible to do it in batch mode. So the
better plan is to be able to pull the output from MicroWorld - as an EDN
structure - into a walkmap superstructure."
([^String filename]
(load-microworld-edn filename :mw))
([^String filename ^Keyword map-kind]
(load-microworld-edn filename map-kind nil))
([^String filename ^Keyword mapkind ^IPersistentMap superstucture]
(load-microworld-edn filename mapkind superstucture (vertex 1 1 1)))
([^String filename ^Keyword map-kind ^IPersistentMap superstructure ^IPersistentMap _scale-vertex]
(when-not
(keyword? map-kind)
(throw (IllegalArgumentException.
(truncate
(format "Must be a keyword: %s." (or map-kind "nil")) 80))))
(let [mw (try
(with-open [r (reader filename)]
(edn/read (PushbackReader. r)))
(catch RuntimeException e
(error "Error parsing edn file '%s': %s\n"
filename (.getMessage e))))
polys (reduce
concat
(map (fn [row] (map cell->polygon row)) mw))]
(if (map? superstructure)
(reduce
#(store %2 %1)
superstructure
polys)
polys))))

View file

@ -0,0 +1,50 @@
(ns cc.journeyman.walkmap.mw-stl
"Convert from Microworld to STL format"
(:require [cc.journeyman.walkmap.ocean :refer [cull-ocean-facets]]
[cc.journeyman.walkmap.polygon :refer [polygon]]
[cc.journeyman.walkmap.vertex :refer [vertex]]
[mw-engine.utils :refer [get-cell map-world]]))
(defn mean-altitude
[cells]
(let [c (remove nil? cells)]
(if (= (count c) 1)
(:altitude (first c))
(/ (reduce + (map :altitude c)) (count c)))))
(defn cell->facets
"Convert a cell into facets.
All facets in an STL file must be triangles, so each MicroWorld cell needs
to be split into two. I am not at present seeing a rational rule for
splitting cells, so at this stage I'm going to do it randomly to prevent
parallel ridge artifacts appearing in the output.
This function is designed to be used with `mw-engint.utils/map-world`, q.v."
[world cell]
(let [;; bounds
n (:y cell)
e (:x cell)
s (inc n)
w (inc e)
;; corner altitudes
nea (mean-altitude [cell (get-cell world (dec n) (dec e))])
nwa (mean-altitude [cell (get-cell world (dec n) (inc e))])
swa (mean-altitude [cell (get-cell world (inc n) (inc e))])
sea (mean-altitude [cell (get-cell world (inc n) (dec e))])]
(if (rand-nth [true false])
[(polygon (vertex n e nea) (vertex n w nwa) (vertex s e sea))
(polygon (vertex n w nwa) (vertex s e sea) (vertex s w swa))]
[(polygon (vertex n e nea) (vertex n w nwa) (vertex s w sea))
(polygon (vertex n e nwa) (vertex s e sea) (vertex s w swa))])))
(defn mw->stl
"Return an STL structure representing the topology of this MicroWorld world
`mw`. If `title` is supplied use that as the title of the STL structure."
([mw]
(mw->stl mw nil))
([mw title]
(let [facets (cull-ocean-facets (flatten (map-world mw cell->facets)))
stl {:facets facets
:count (count facets)}]
(if title (assoc stl :title title) stl))))

View file

@ -0,0 +1,33 @@
(ns cc.journeyman.walkmap.ocean
"Deal with (specifically, at this stage, cull) ocean areas"
(:require [cc.journeyman.walkmap.polygon :refer [triangle?]]
[cc.journeyman.walkmap.stl :refer [stl?]]
[cc.journeyman.walkmap.utils :refer [=ish]]))
(def ^:dynamic *sea-level*
"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`!"
0.0)
(defn ocean?
"Of a `facet`, is the altitude of every vertice equal to `*sea-level*`?"
[facet]
(every?
#(=ish % *sea-level*)
(map :z (:vertices facet))))
(defn cull-ocean-facets
"Ye cannae walk on water. Remove all facets from this `stl` structure which
are at sea level."
[stl-or-seq]
(cond
(and (seq? stl-or-seq)
(every? triangle? stl-or-seq)) (remove ocean? stl-or-seq)
(stl? stl-or-seq)(assoc stl-or-seq :facets
(cull-ocean-facets (:facets stl-or-seq)))
:else (throw (IllegalArgumentException.
"Expected STL structure, or sequence of triangles."))))

View file

@ -0,0 +1,91 @@
(ns cc.journeyman.walkmap.path
"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 [cc.journeyman.walkmap.edge :as e]
[cc.journeyman.walkmap.polygon :refer [polygon?]]
[cc.journeyman.walkmap.utils :refer [check-kind-type check-kind-type-seq]]
[cc.journeyman.walkmap.vertex :refer [check-vertices vertex?]]))
(defn path?
"True if `o` satisfies the conditions for a path. A path shall be a map
having the key `:vertices`, whose value shall be a sequence of vertices as
defined in `walkmap.vertex`."
[o]
(let
[v (:vertices o)]
(and
(seq? v)
(> (count v) 1)
(every? vertex? v)
(:walkmap.id/id o)
(or (nil? (:kind o)) (= (:kind o) :path)))))
(defn path
"Return a path constructed from these `vertices`."
[& vertices]
(if
(> (count (check-vertices vertices)) 1)
{:vertices vertices :walkmap.id/id (keyword (gensym "path")) :kind :path}
(throw (IllegalArgumentException. "Path must have more than one vertex."))))
(defmacro check-path
"If `o` is not a path, throw an `IllegalArgumentException` with an
appropriate message; otherwise, returns `o`. Macro, so exception is thrown
from the calling function."
[o]
`(check-kind-type ~o path? :path))
(defmacro check-paths
"If `o` is not a sequence of paths, throw an `IllegalArgumentException` with an
appropriate message; otherwise, returns `o`. Macro, so exception is thrown
from the calling function."
[o]
`(check-kind-type-seq ~o path? :path))
(defn polygon->path
"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."
[o]
;; this is breaking, but I have NO IDEA why!
;; (check-polygon o polygon? :polygon)
(assoc (dissoc o :vertices)
:kind :path
;; `concat` rather than `conj` because order matters.
:vertices (concat (:vertices o) (list (first (:vertices 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
;; 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) (first (rest o)))
(path->edges (rest o))))
(path? o) (path->edges (:vertices o))
(polygon? o) (path->edges (polygon->path 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]
(reduce + (map e/length (path->edges (check-path path)))))

View file

@ -0,0 +1,178 @@
(ns cc.journeyman.walkmap.polygon
"Essentially the specification for things we shall consider to be polygons."
(:require [clojure.string :as s]
[cc.journeyman.walkmap.edge :as e]
[cc.journeyman.walkmap.tag :as t]
[cc.journeyman.walkmap.utils :refer [check-kind-type
check-kind-type-seq
kind-type
not-yet-implemented]]
[cc.journeyman.walkmap.vertex :refer [check-vertex check-vertices vertex vertex?]]))
(defn polygon?
"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."
[o]
(let
[v (:vertices o)]
(and
(coll? v)
(> (count v) 2)
(every? vertex? v)
(:walkmap.id/id o)
(or (nil? (:kind o)) (= (:kind o) :polygon)))))
(defmacro check-polygon
"If `o` is not a polygon, throw an `IllegalArgumentException` with an
appropriate message; otherwise, returns `o`. Macro, so exception is thrown
from the calling function."
[o]
`(check-kind-type ~o polygon? :polygon))
(defmacro check-polygons
"If `o` is not a sequence of polygons, throw an `IllegalArgumentException` with an
appropriate message; otherwise, returns `o`. Macro, so exception is thrown
from the calling function."
[o]
`(check-kind-type-seq ~o polygon? :polygon))
(defn triangle?
"True if `o` satisfies the conditions for a triangle. A triangle shall be a
polygon with exactly three vertices."
[o]
(and
(coll? o)
(#{:polygon :triangle} (kind-type o))
(= (count (:vertices o)) 3)))
(defmacro check-triangle
"If `o` is not a triangle, throw an `IllegalArgumentException` with an
appropriate message; otherwise, returns `o`. Macro, so exception is thrown
from the calling function."
[o]
`(check-kind-type ~o triangle? :triangle))
(def recognised-polygon-types #{:triangle
:quadrilateral
:pentagon
:hexagon
:heptagon
:octogon
:polygon})
(defn- poly-kind
"Return a keyword representing the kind of polygon which has this many
`vertices`."
[vertices]
(case (count vertices)
3 :triangle
4 :quadrilateral
5 :pentagon
6 :hexagon
7 :heptagon
8 :octogon
;;else
:polygon))
(defn polygon
"Return a polygon constructed from these `vertices`."
[& vertices]
(if
(> (count vertices) 2)
{:vertices (check-vertices vertices)
:walkmap.id/id (keyword (gensym "poly"))
:kind (poly-kind vertices)}
(throw (IllegalArgumentException.
"A polygon must have at least 3 vertices."))))
(defn rectangle
"Return a rectangle, with edges aligned east-west and north-south, whose
south-west corner is the vertex `vsw` and whose north-east corner is the
vertex `vne`."
[vsw vne]
;; we can actually create any rectangle in the xy plane based on two opposite
;; corners, but the maths are a bit to advanced for me today. TODO: do it!
(let [vnw (vertex (:x (check-vertex vsw))
(:y (check-vertex vne))
(/ (reduce + (map #(or (:z %) 0) [vsw vne])) 2))
vse (vertex (:x vne)
(:y vsw)
(/ (reduce + (map #(or (:z %) 0) [vsw vne])) 2))
height-order (sort-by :z [vsw vne])]
(t/tag
(assoc
(polygon vsw vnw vne vse)
:gradient
(e/unit-vector (e/edge (first height-order) (last height-order)))
:centre
(vertex (+ (:x vsw) (/ (- (:x vne) (:x vsw)) 2))
(+ (:y vsw) (/ (- (:y vne) (:y vsw)) 2))
(:z vse)))
:rectangle)))
;; (rectangle (vertex 1 2 3) (vertex 7 9 4))
(defn gradient
"Return a polygon like `triangle` but with a key `:gradient` whose value is a
unit vector representing the gradient across `triangle`."
[triangle]
(let [order (sort #(max (:z %1) (:z %2))
(:vertices (check-triangle triangle)))
highest (first order)
lowest (last order)]
(assoc triangle :gradient (e/unit-vector (e/edge lowest highest)))))
(defn triangle-centre
"Return a canonicalised `facet` (i.e. a triangular polygon) with an added
key `:centre` whose value represents the centre of this facet in 3
dimensions. This only works for triangles, so is here not in
`walkmap.polygon`. It is an error (although no exception is currently
thrown) if the object past is not a triangular polygon."
[facet]
(let [vs (:vertices (check-triangle facet))
v1 (first vs)
opposite (e/edge (nth vs 1) (nth vs 2))
oc (e/centre opposite)]
(assoc
facet
:centre
(vertex
(+ (:x v1) (* (- (:x oc) (:x v1)) 2/3))
(+ (:y v1) (* (- (:y oc) (:y v1)) 2/3))
(+ (:z v1) (* (- (:z oc) (:z v1)) 2/3))))))
(defn centre
[poly]
(case (count (:vertices (check-polygon poly)))
3 (triangle-centre poly)
;; else
(throw
(UnsupportedOperationException.
"The general case of centre for polygons is not yet implemented."))))
(defmacro on2dtriangle?
"Is the projection of this `vertex` on the x, y plane within the
projection of this triangle on that plane?"
[vertex poly]
`(not-yet-implemented "on2d? for triangles."))
(defn on2drectangle?
"Is the projection of this `vertex` on the x, y plane within the
projection of this rectangle on that plane?"
[vertex rectangle]
(let [xo (sort-by :x (:vertices rectangle))
yo (sort-by :y (:vertices rectangle))]
(and
(< (:x (first xo)) (:x vertex) (:x (last xo)))
(< (:y (first yo)) (:y vertex) (:y (last yo))))))
(defmacro on2d?
"Is the projection of this `vertex` on the x, y plane within the
projection of this polygon `poly` on that plane?"
[vertex poly]
`(cond
(rectangle? ~poly) (on2drectangle? ~vertex ~poly)
(triangle? ~poly) (on2dtriangle? ~vertex ~poly)
:else
(not-yet-implemented "general case of on2d? for polygons.")))

View file

@ -0,0 +1,95 @@
(ns cc.journeyman.walkmap.read-svg
"Utility functions for scalable vector graphics (SVG) into walkmap
structures."
(:require [clojure.java.io :as io]
[clojure.string :as s]
[clojure.xml :as x]
[cc.journeyman.walkmap.path :refer [path]]
[cc.journeyman.walkmap.tag :refer [tag]]
[cc.journeyman.walkmap.vertex :refer [vertex vertex?]]))
(defn upper-case?
[s]
(every? #(Character/isUpperCase %) s))
(defn match->vertex
[match-vector x y]
(when-not (empty? match-vector)
(let [command (nth match-vector 1)
xcoord (read-string (nth match-vector 2))
ycoord (read-string (nth match-vector 3))
;; upper case command letters mean the coordinates that follow are
;; absolute; lower case, relative.
x' (if (upper-case? command) xcoord (+ x xcoord))
y' (if (upper-case? command) ycoord (+ y ycoord))]
(case (s/lower-case command)
("m" "l") {:vertex (vertex x' y') :x x' :y y'}
nil))))
(defn command-string->vertices
"Return the destination of each successive line (`l`, `L`) and move (`m`, `M`)
command in this string `s`, expected to be an SVG path command string."
[s]
(let [cmd-matcher ;; matches a 'command' in the string: a letter followed by
;;spaces and numbers
(re-matcher #"[a-zA-Z][^a-zA-Z]*" s)
seg-pattern ;; matches a command which initiates a move of the current
;; position.
#"([a-zA-Z]) +([-+]?[0-9]*\.?[0-9]+) +([-+]?[0-9]*\.?[0-9]+) +"]
(loop [match (re-find cmd-matcher)
result []
x 0
y 0]
(if-not match
(filter vertex? result)
(let [m (match->vertex (re-find seg-pattern match) x y)]
(recur (re-find cmd-matcher) ;loop with 2 new arguments
(conj result (:vertex m))
(or (:x m) x)
(or (:y m) y)))))))
(defn path-elt->path
"Given the SVG path element `elt`, return a walkmap path structure
representing the line (`l`, `L`) and move (`m`, `M`) commands in
that path."
[elt]
(if (= (:tag elt) :path)
(let [vs (command-string->vertices (-> elt :attrs :d))
p (when-not (empty? vs) (apply path vs))]
(if (and p (-> elt :attrs :class))
(tag p (map keyword (s/split (-> elt :attrs :class) #" ")))
p))
(throw (IllegalArgumentException.
(str "Must be an SVG `path` element: " elt)))))
(defn progeny
"Return all the nodes in the XML structure below this `elt` which match
this `predicate`."
;; the name `descendants` is bound in `clojure.core` for something quite
;; different, and I chose not to rebind it.
[elt predicate]
(if
(apply predicate (list elt))
(list elt)
(reduce
concat
(remove
empty?
(map
#(progeny % predicate)
(:content elt))))))
(defn read-svg
;; I tried to get this working with all the clever zip stuff in
;; `clojure.zip`, `clojure.data.zip`, and so on. It would probably have
;; been more elegant, but it kept crashing out of heap space on even
;; quite small XML files. So I've implemented my own solution.
([file-name]
(read-svg file-name nil))
([file-name _map-kind]
(let [xml (x/parse (io/file file-name))
paths (progeny xml #(= (:tag %) :path))]
(remove nil? (map path-elt->path paths)))))
;; (read-svg "resources/iom/manual_roads.svg")

View file

@ -0,0 +1,210 @@
(ns cc.journeyman.walkmap.routing
"Finding optimal routes to traverse a map."
(:require [clojure.math.numeric-tower :refer [expt]]
[clojure.set :refer [intersection]]
[cc.journeyman.walkmap.edge :as e]
[cc.journeyman.walkmap.path :as p]
[cc.journeyman.walkmap.polygon :as q]
[cc.journeyman.walkmap.superstructure :as s]
[cc.journeyman.walkmap.tag :refer [tags]]
[cc.journeyman.walkmap.vertex :as v]
[search.core :refer [a*]]
[taoensso.timbre :refer [debug]]))
;; Breadth first search is a good algorithm for terrain in which all steps have
;; equal, but in our world (like the real world), they don't.
;; Reading list:
;;
;; https://en.wikipedia.org/wiki/A*_search_algorithm
;; https://www.redblobgames.com/pathfinding/a-star/introduction.html
;; https://faculty.nps.edu/ncrowe/opmpaper2.htm
;;
;; See https://simon-brooke.github.io/the-great-game/codox/Pathmaking.html
(def ^:dynamic *gradient-exponent*
"The exponent to be applied to `(inc (:z (unit-vector from to)))`
of a path segment to calculate the gradient-related part of the
cost of traversal. Dynamic, because we will want to tune this."
2)
(def ^:dynamic *traversals-exponent*
"The (expected to be negative) exponent to be applied to the number
of traversals of a path to compute the road bonus. Paths more travelled by
should have larger bonuses, but not dramatically so - so the increase in
bonus needs to scale significantly less than linearly with the number
of traversals. Dynamic, because we will want to tune this."
-2)
(def ^:dynamic *untraversable*
"The set of all tags which may indicate that a polygon should not be
traversed."
#{:no-traversal})
(defn traversable?
"True if this `object` is a polygon which can be considered as part of
the walkmap."
[object]
(and
(q/polygon? object)
(:centre object)
(empty? (intersection (tags object) *untraversable*))))
(declare traversal-cost)
(defn vertices-traversal-cost
[vertices s]
(reduce
+
(map
#(traversal-cost %1 %2 s)
(v/check-vertices vertices)
(rest vertices))))
(defn path-traversal-cost
[path s]
(vertices-traversal-cost (:vertices (p/check-path path)) s))
(defn barriers-crossed
"Search superstructure `s` and return a sequence of barriers, if any, which
obstruct traversal from vertex `from` to vertex `to`."
[from to _s]
(debug (format "barriers-crossed called with vertices\n\tfrom: %s\n\tto: %s" from to))
;; TODO: implement
'())
(defn crossing-penalty
"TODO: should return the cost of crossing this `barrier`, initially mainly
a watercourse, on the axis from vertex `from` to vertex `to`. in the context
of superstructure `s`. If there's a bridge, ferry or other crossing mechanism
in `s` at the intersection of the vertex and the barrier, then the penalty
should be substantially less than it would otherwise be."
[barrier from to _s]
(debug (format "crossing-penalty called with arguments\n\tbarrier: %s\n\tfrom: %s\n\tto: %s" barrier from to))
;; TODO: implement
0)
(defn gradient-cost
"Compute the per-unit-distance cost of traversing this `edge`."
[edge]
(let [g (:z (e/unit-vector edge))]
(if (pos? g)
(expt (inc g) *gradient-exponent*)
1)))
;; (gradient-cost (e/edge (v/vertex 0 0 0) (v/vertex 0 1 0)))
;; (gradient-cost (e/edge (v/vertex 0 0 0) (v/vertex 0 2 0)))
;; (gradient-cost (e/edge (v/vertex 0 0 0) (v/vertex 0 1 1)))
;; (gradient-cost (e/edge (v/vertex 0 0 0) (v/vertex 0 2 1)))
;; (gradient-cost (e/edge (v/vertex 0 0 0) (v/vertex 0 1 0.0001)))
(defn best-road
"Find the best traversable path which links the vertices `from` and `to`
in this superstructure `s`, or nil if there are none."
[from to s]
(let [f (fn [v] (set (s/touching v p/path? s)))]
(first
(sort-by
;;; I... chose the path more travelled by.
#(or (:traversals %) 0)
(filter traversable? (intersection (f from) (f to)))))))
(defn road-bonus
"Calculate the road bonus of the edge represented by the vertices `from`,
`to`, in the context of the superstructure `s`. Obviously there only is
such a bonus if there actually is an existing thoroughfare to use. Road
bonuses scale with some fractional exponent of the number of traversals
which have been made of the road segment in question."
[from to s]
(let [best (best-road from to s)]
(when (:traversals best)
(expt (:traversals best) *traversals-exponent*))))
(defn traversal-cost
"Return the traversal cost of the edge represented by the vertices `from`,
`to`, in the context of the superstructure `s`. It is legitimate to pass
`nil` as the `to` argument, in which case the result will be zero, in order
to allow `reduce` to be used to compute total path costs."
[from to s]
(if (nil? to)
0
(let [edge (e/edge from to)
distance (e/length edge)]
(/
(+
(* distance
(gradient-cost edge))
(reduce +
(map
#(crossing-penalty % from to s)
(barriers-crossed from to s))))
(or (road-bonus from to s) 1)))))
;; (def p '({:x 1.40625, :y 0, :kind :vertex, :walkmap.id/id :vert_1-40625_0}
;; {:x 1.40625, :y -10.703125, :kind :vertex, :walkmap.id/id :vert_1-40625_-10-703125}
;; {:x 7.578125, :y -10.703125, :kind :vertex, :walkmap.id/id :vert_7-578125_-10-703125}
;; {:x 7.578125, :y 0, :kind :vertex, :walkmap.id/id :vert_7-578125_0}
;; {:x 2.171875, :y -0.765625, :kind :vertex, :walkmap.id/id :vert_2-171875_-0-765625}
;; {:x 6.8125, :y -0.765625, :kind :vertex, :walkmap.id/id :vert_6-8125_-0-765625}))
;; (v/check-vertices p)
;; (def p' (p/path p))
;; (traversal-cost (first p) (nth p 1) {})
;; (vertices-traversal-cost p {})
;; (path-traversal-cost (p/path p))
(defn extend-frontier
"Return a sequence like `frontier` with all of these `candidates` which are
not already members either of `frontier` or of `rejects` appended. Assumes
candidates are traversable."
([frontier candidates]
(extend-frontier frontier candidates nil))
([frontier candidates rejects]
(if
(empty? frontier)
candidates
(let [fs (set (concat frontier rejects))]
(concat frontier (remove fs candidates))))))
;; (extend-frontier '(1 2 3 4 5) '(7 3 6 2 9 8) '(6 8))
;; (extend-frontier '(1 2 3 4 5) '(7 3 6 2 9 8))
;; (extend-frontier '(1 2 3 4 5) '())
;; (extend-frontier '(1 2 3 4 5) nil)
;; (extend-frontier nil '(1 2 3 4 5))
(def ^:dynamic *route-goal*
"The goal of the route currently sought."
nil)
(defn find-traversable-facet
"Return the nearest traversable walkmap facet within `search-radius` of
`target`, or throw an exception if none is found."
[target search-radius s]
(let [r (s/nearest s target traversable? search-radius)]
(when-not r (throw
(Exception.
(format "Unable to find walkable facet within %s of %s"
search-radius
target))))
r))
(defn route
;; architectural problem: needs to return not the route, but a modified
;; superstructure with the new route stored in it.
([from to s]
(route from to s traversal-cost 5))
([from to s cost-fn search-radius]
(let [from' (find-traversable-facet from search-radius s)
to' (find-traversable-facet to search-radius s)]
(a* from'
#(v/vertex= % (:centre to')) ;; goal?-fn - 'have we got there yet?'
#(cost-fn %1 %2 s) ;; distance-fn - what is the distance/cost
;; between these vertices?
#(e/length (e/edge (:centre %) to))
;; heuristic: how far to the end goal
#(s/neighbours % traversable? s)
;; neighbours-fn - return the traversable
;; neighbours of the current facet
(int (* search-radius (e/length (e/edge from to))))
;; how long a path we'll accept
))))

View file

@ -0,0 +1,253 @@
(ns cc.journeyman.walkmap.stl
"Utility functions dealing with stereolithography (STL) files. Not a stable API yet!"
(:require [cc.journeyman.walkmap.ocean :refer [ocean?]]
[cc.journeyman.walkmap.polygon :refer [centre gradient triangle?]]
[cc.journeyman.walkmap.superstructure :refer [store]]
[cc.journeyman.walkmap.tag :refer [tag]]
[cc.journeyman.walkmap.utils :refer [kind-type truncate]]
[cc.journeyman.walkmap.vertex :as v :refer [vertex]]
[clojure.core.matrix :refer [set-current-implementation sub]]
[clojure.java.io :refer [input-stream]]
[clojure.string :as s]
[me.raynes.fs :refer [base-name split-ext]]
[org.clojars.smee.binary.core :as b]
[taoensso.timbre :refer [debug]])
(:import [clojure.lang Keyword]))
;; We want to use the `[vectorz](https://github.com/mikera/vectorz-clj)`
;; implementation of core.matrix.
(set-current-implementation :vectorz)
(defn stl?
"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."
([o]
(stl? o false))
([o verify-count?]
(and
(map? o)
(:facets o)
(every? triangle? (:facets o))
(if (:header o) (string? (:header o)) true)
(if (:count o) (integer? (:count o)) true)
(or (nil? (:kind o)) (= (:kind o) :stl))
(if verify-count? (= (:count o) (count (:facets o))) true))))
(def vect
"A codec for vectors within a binary STL file."
(b/ordered-map
:x :float-le
:y :float-le
:z :float-le))
(def facet
"A codec for a facet (triangle) within a binary STL file."
(b/ordered-map
:normal vect
:vertices [vect vect vect]
:abc :ushort-le))
(def binary-stl
"A codec for binary STL files"
(b/ordered-map
:header (b/string "ISO-8859-1" :length 80) ;; for the time being we neither know nor care what's in this.
:count :uint-le
:facets (b/repeated facet)))
(defn vertex->array
[v]
[(:x v) (:y v) (or (:z v) 0)])
(defn surface-normal
"From https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal
```
Begin Function CalculateSurfaceNormal (Input Triangle) Returns Vector
Set Vector U to (Triangle.p2 minus Triangle.p1)
Set Vector V to (Triangle.p3 minus Triangle.p1)
Set Normal.x to (multiply U.y by V.z) minus (multiply U.z by V.y)
Set Normal.y to (multiply U.z by V.x) minus (multiply U.x by V.z)
Set Normal.z to (multiply U.x by V.y) minus (multiply U.y by V.x)
Returning Normal
End Function
```"
[triangle]
(if (triangle? triangle)
(let
[vertices (:vertices triangle)
v1 (vertex->array (nth vertices 0))
u (sub (vertex->array (nth vertices 1)) v1)
v (sub (vertex->array (nth vertices 2)) v1)
x (- (* (nth u 1)(nth v 2)) (* (nth u 2) (nth v 1)))
y (- (* (nth u 2) (nth v 0)) (* (nth u 0) (nth v 2)))
z (- (* (nth u 0) (nth v 1)) (* (nth u 1 (nth v 0))))]
(debug (format "Calculating normal for triangle %s" triangle))
(vertex x y z))
(throw (IllegalArgumentException.
(format "Expected :triangle, found %s" (kind-type triangle))))))
(defn ensure-normal
"Ensure this `triangle` has a normal vector/"
[triangle]
(if (triangle? triangle)
(if (:normal triangle) triangle
(assoc triangle :normal (surface-normal triangle)))
(throw (IllegalArgumentException.
(format "Expected :triangle, found %s" (kind-type triangle))))))
(defn canonicalise
"Objects read in from STL won't have all the keys/values we need them to have.
`o` may be a map (representing a facet or a vertex), or a sequence of such maps;
if it isn't recognised it is at present just returned unchanged. `map-kind`, if
passed, must be a keyword indicating the value represented by the `z` axis
(defaults to `:height`). It is an error, and an exception will be thrown, if
`map-kind` is not a keyword."
([o] (canonicalise o :height))
([o ^Keyword map-kind]
(canonicalise o map-kind (v/vertex 1 1 1)))
([o ^Keyword map-kind scale-vertex]
(when-not
(keyword? map-kind)
(throw (IllegalArgumentException.
(truncate (str "Must be a keyword: " (or map-kind "nil")) 80))))
(cond
(and (coll? o) (not (map? o))) (map #(canonicalise % map-kind) o)
;; if it has :facets it's an STL structure, but it doesn't yet conform to `stl?`
(:facets o) (assoc o
:kind :stl
:walkmap.id/id (or (:walkmap.id/id o)
(keyword (gensym "stl")))
:facets (canonicalise (:facets o) map-kind))
;; if it's a triangle it's almost a facet. All it needs now is a normal
;; vector
(triangle? o) (ensure-normal o)
;; if it has :vertices it's a polygon, but it may not yet conform to
;; `polygon?`
(:vertices o) (let [f (gradient
(centre
(tag
(assoc o
:walkmap.id/id (or
(:walkmap.id/id o)
(keyword (gensym "poly")))
:kind :polygon
:vertices (canonicalise
(:vertices o)
map-kind))
:facet map-kind)))]
(if (ocean? f)
(tag f :ocean :no-traversal)
f))
;; if it has a value for :x it's a vertex, but it may not yet conform
;; to `vertex?`; it should also be scaled using the scale-vertex, if any.
(:x o) (let [c (v/canonicalise o)]
(if (v/vertex? scale-vertex)
(v/vertex* c scale-vertex)
c))
;; shouldn't happen
:else o)))
(defn decode-binary-stl
"Parse a binary STL file from this `filename` and return an STL structure
representing its contents. `map-kind`, if passed, must be a keyword
or sequence of keywords indicating the semantic value represented by the `z`
axis (defaults to `:height`).
If `superstructure` is supplied and is a map, the generated STL structure
will be stored in that superstructure, which will be returned.
If `scale-vertex` is supplied, it must be a three dimensional vertex (i.e.
the `:z` key must have a numeric value) representing the amount by which
each of the vertices read from the STL will be scaled.
It is an error, and an exception will be thrown, if `map-kind` is not a
keyword or sequence of keywords.
**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."
([^String filename]
(decode-binary-stl filename :height))
([^String filename ^Keyword map-kind]
(decode-binary-stl filename map-kind nil))
([^String filename ^Keyword mapkind superstucture]
(decode-binary-stl filename mapkind superstucture (v/vertex 1 1 1)))
([^String filename ^Keyword map-kind superstructure scale-vertex]
(let [in (input-stream filename)
stl (canonicalise (b/decode binary-stl in) map-kind scale-vertex)]
(if
(map? superstructure)
(store stl superstructure)
stl))))
(defn- vect->str [prefix v]
(str prefix " " (:x v) " " (:y v) " " (:z v) "\n"))
(defn- facet2str [tri]
(str
(vect->str "facet normal" (:normal tri))
"outer loop\n"
(s/join
(map
#(vect->str "vertex" %)
(:vertices tri)))
"endloop\nendfacet\n"))
(defn stl->ascii
"Return as a string an ASCII rendering of the `stl` structure."
([stl]
(stl->ascii stl "unknown"))
([stl solidname]
(str
"solid "
(or solidname
(when (:header stl)(s/trim (:header stl))))
"\n"
(s/join
(map
facet2str
(:facets stl)))
"endsolid "
solidname
"\n")))
(defn write-ascii-stl
"Write an `stl` structure as read by `decode-binary-stl` to this
`filename` as ASCII encoded STL."
([filename stl]
(let [b (base-name filename true)]
(write-ascii-stl
filename stl
(subs b 0 (or (s/index-of b ".") (count b))))))
([filename stl solidname]
(debug (format "Writing STL to '%s'; solid name is %s" filename solidname))
(spit
filename
(stl->ascii stl solidname))))
(defn binary-stl-to-ascii
"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`."
([in-filename]
(let [[_ ext] (split-ext in-filename)]
(binary-stl-to-ascii
in-filename
(str
(subs
in-filename
0
(or
(s/last-index-of in-filename ".")
(count in-filename)))
".ascii"
ext))))
([in-filename out-filename]
(write-ascii-stl out-filename (decode-binary-stl in-filename))))

View file

@ -0,0 +1,277 @@
(ns cc.journeyman.walkmap.superstructure
"single indexing structure for walkmap objects"
(:require [clojure.walk :refer [postwalk]]
[taoensso.timbre :as l]
[cc.journeyman.walkmap.edge :refer [edge length]]
;; [cc.journeyman.walkmap.path :as p]
;; [cc.journeyman.walkmap.polygon :as q]
[cc.journeyman.walkmap.utils :as u]
[cc.journeyman.walkmap.vertex :as v])
(:import [clojure.lang IFn IPersistentMap]))
;; TODO: Think about reification/dereification. How can we cull a polygon, if
;; some vertices still index it? I *think* that what's needed is that when
;; we store something in the superstructure, we replace all its vertices (and
;; other dependent structures, if any) with their ids - as well as, obviously,
;; adding/merging those vertices/dependent structures into the superstructure
;; as first class objects in themselves. That means, for each identified thing,
;; the superstructure only contains one copy of it.
;;
;; The question then is, when we want to do things with those objects, do we
;; exteract a copy with its dependent structures fixed back up (reification),
;; or do we indirect through the superstructure every time we want to access
;; them? In a sense, the copy in the superstructure is the 'one true copy',
;; but it may become very difficult then to have one true copy of the
;; superstructure - unless we replace the superstructure altogether with a
;; database, which may be the Right Thing To Do.
(def vertex-index ::vertex-index)
(defn vertices
"If `o` is an object with vertices, return those vertices, else nil."
[o]
(when (map? o)
(reduce
concat
(remove
nil?
(map
#(cond
(v/vertex? %) (list %)
(and (coll? %) (every? v/vertex? %)) %)
(vals o))))))
;; (cond
;; (v/vertex? o) (list o)
;; (q/polygon? o) (:vertices o)
;; (p/path? o) (:vertices o))
;; )
(defn index-vertex
"Return a superstructure like `s` in which object `o` is indexed by vertex
`v`. It is an error (and an exception may be thrown) if
1. `s` is not a map;
2. `o` is not a map;
3. `o` does not have a value for the key `:walkmap.id/id`;
4. `v` is not a vertex."
[^IPersistentMap s ^IPersistentMap o ^IPersistentMap v]
(if-not (v/vertex? o)
(if (:walkmap.id/id o)
(if (v/vertex? v)
(let [vi (or (::vertex-index s) {})
current (or (vi (:walkmap.id/id v)) {})]
;; deep-merge doesn't merge sets, only maps; so at this
;; stage we need to build a map.
(assoc vi (:walkmap.id/id v) (assoc current (:walkmap.id/id o) (:walkmap.id/id v))))
(throw (IllegalArgumentException. "Not a vertex: " v)))
(throw (IllegalArgumentException. (u/truncate (str "No `:walkmap.id/id` value: " o) 80))))
;; it shouldn't actually be an error to try to index a vertex, but it
;; also isn't useful to do so, so I'd be inclined to ignore it.
(::vertex-index s)))
(defn index-vertices
"Return a superstructure like `s` in which object `o` is indexed by its
vertices. It is an error (and an exception may be thrown) if
1. `s` is not a map;
2. `o` is not a map;
3. `o` does not have a value for the key `:walkmap.id/id`."
[s o]
(u/deep-merge
s
{::vertex-index
(reduce
u/deep-merge
{}
(map
#(index-vertex s o %)
(:vertices o)))}))
(defn in-retrieve
"Internal guts of `retrieve`, q.v. `x` can be anything; `s` must be a
walkmap superstructure. TODO: recursive, quite likely to blow the fragile
Clojure stack. Probably better to do this with `walk`, but I don't yet
understand that."
[x s]
(cond
;; if it's a keyword identifying something in s, retrieve that something.
(keyword? x) (if (s x)
(in-retrieve (s x) s)
x)
;; if it's a map, for every key which is not `:walkmap.id/id`, recurse.
(map? x) (let [v (reduce
(fn [m k]
(assoc m k (in-retrieve (x k) s)))
{}
(keys (dissoc x :walkmap.id/id)))
id (:walkmap.id/id x)]
;; if it has an id, bind it to that id in the returned value.
(if id
(assoc
v
:walkmap.id/id
(:walkmap.id/id x))
v))
(set? x) x ;; TODO: should I search in sets for objects when storing?
(coll? x) (map #(in-retrieve % s) x)
:else x))
(defn retrieve
"Retrieve the canonical representation of the object with this `id` from the
superstructure `s`."
[id s]
(in-retrieve (id s) s))
(defn in-store-find-objects
"Return an id -> object map of every object within `o`. Internal to
`in-store`, q.v. Use at your own peril."
([o]
(in-store-find-objects o {}))
([o s]
(when (map? o) (l/debug "Finding objects in:" o))
(cond
(set? o) s ;; TODO: should I search in sets for objects when storing?
(map? o) (if (:walkmap.id/id o)
(assoc
(in-store-find-objects (vals o) s)
(:walkmap.id/id o)
o)
(in-store-find-objects (vals o) s))
(coll? o) (reduce merge s (map #(in-store-find-objects % s) o))
:else s)))
(defn in-store-replace-with-keys
"Return a copy of `o` in which each reified walkmap object within `o` has
been replaced with the `:walkmap.id/id` of that object. Internal to
`in-store`, q.v. Use at your own peril."
[o]
(assoc
(postwalk #(or (:walkmap.id/id %) %) (dissoc o :walkmap.id/id))
:walkmap.id/id
(:walkmap.id/id o)))
;; (in-store-replace-with-keys (p/path (v/vertex 0 0 0) (v/vertex 0 1 2) (v/vertex 3 3 3)))
;; (in-store-find-objects (p/path (v/vertex 0 0 0) (v/vertex 0 1 2) (v/vertex 3 3 3)))
(defn store
"Return a superstructure like `s` with object `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. `o` is not a recognisable walkmap object"
([^IPersistentMap o]
(store o {}))
([^IPersistentMap o ^IPersistentMap s]
(when-not (:walkmap.id/id o)
(throw
(IllegalArgumentException.
(str "Not a walkmap object: no value for `:walkmap.id/id`: "
(u/kind-type o)))))
(when-not (map? s)
(throw
(IllegalArgumentException.
(str "Superstructure must be a map: " (u/kind-type s)))))
(assoc
(u/deep-merge s (in-store-find-objects o) (index-vertices s o))
(:walkmap.id/id o)
(in-store-replace-with-keys o))))
(defn search-vertices
"Search superstructure `s` for vertices within the box defined by vertices
`minv` and `maxv`. Every coordinate in `minv` must have a lower value than
the equivalent coordinate in `maxv`. If `d2?` is supplied and not false,
search only in the x,y projection.
**NOTE THAT** this depends on the fact that vertices do not currently
have properties which will be denormalised by `store`, and therefore do not
have to restored with `retrieve`. If properties are added to vertices
whose values are objects, then this will have to be rewritten."
([^IPersistentMap s ^IPersistentMap minv ^IPersistentMap maxv]
(search-vertices s minv maxv false))
([s minv maxv d2?]
(let [minv' (if d2? (assoc minv :z Double/NEGATIVE_INFINITY) minv)
maxv' (if d2? (assoc maxv :z Double/POSITIVE_INFINITY) maxv)]
(filter
#(v/within-box? % minv' maxv')
(filter #(= (:kind %) :vertex) (vals s))))))
(defn nearest
"Search superstructure `s` for the nearest object matching `filter-fn` to
the `target` vertex. Searches only with `radius` (slight misnomer, area
actually searched is a cube). Returns one object, or `nil` if no matching
object found.
WARNING: currently only returns objects which have a defined `:centre`
(but most of the significant objects we have do)."
([^IPersistentMap s ^IPersistentMap target ^Number radius]
(nearest s target :centre radius))
([^IPersistentMap s ^IPersistentMap target ^IFn filter-fn ^Number radius]
(let [minv (v/vertex
(- (:x (v/check-vertex target)) radius)
(- (:y target) radius) (- (or (:z target) 0) radius))
maxv (v/vertex
(+ (:x target) 0.5) (+ (:y target) 0.5)
(+ (or (:z target) 0) 0.5))]
;; filter those objects with the filter function, then sort that list
;; by the edge distance from the target to the `:centre` of the object
;; and take the first
(first
(sort-by
#(length (edge target (:centre %)))
(filter
filter-fn
(filter
:centre
(pmap #(retrieve % s)
;; for each vertex id in vids, get the objects associated with that id
;; in the vertex index as a single flat list
(reduce
concat
(remove
nil?
(map
#(-> s ::vertex-index % keys)
;; get all the vertex ids within radius of the target
(set
(map
:walkmap.id/id
(search-vertices s minv maxv))))))))))))))
(defn touching
"Return a sequence of all objects in superstructure `s` which are
indexed as touching the vertex `v`."
([^IPersistentMap vertex ^IPersistentMap s]
(map
#(retrieve % s)
(set (-> s :vertex-index (:walkmap.id/id (v/check-vertex vertex)) keys))))
([^IPersistentMap vertex ^IFn filter-fn ^IPersistentMap s]
(filter
filter-fn
(touching vertex s))))
(defn neighbours
"Return a sequence of all those objects in superstructure `s` which share
at least one vertex with `target`, and which are matched by `filter-fn`
if supplied."
([^IPersistentMap target ^IPersistentMap s]
(neighbours target identity s))
([^IPersistentMap target ^IFn filter-fn ^IPersistentMap s]
(remove
#(= target %)
(reduce
concat
(remove
nil?
(map #(touching % filter-fn s) (vertices target)))))))
(defn neighbour-ids
"Return a sequence of the ids all those objects in superstructure `s` which
share at least one vertex with `target`, and which are matched by
`filter-fn` if supplied."
([^IPersistentMap target ^IPersistentMap s]
(neighbour-ids target identity s))
([^IPersistentMap target ^IFn filter-fn ^IPersistentMap s]
(pmap :walkmap.id/id (neighbours target filter-fn s))))

View file

@ -0,0 +1,106 @@
(ns cc.journeyman.walkmap.svg
"Utility functions for writing stereolithography (STL) files (and possibly,
later, other geometry files of interest to us) as scalable vector graphics
(SVG)."
(:require [clojure.string :as s]
[dali.io :as neatly-folded-clock]
[hiccup.core :refer [html]]
[taoensso.timbre :refer [info]]
[cc.journeyman.walkmap.ocean :refer [cull-ocean-facets]]
[cc.journeyman.walkmap.stl :refer [decode-binary-stl]]))
(def ^:dynamic *preferred-svg-render*
"Mainly for debugging dali; switch SVG renderer to use. Expected values:
`:dali`, `:hiccup`."
:dali)
(defn- facet->svg-poly
[facet]
[:polygon
{:points (s/join " " (map #(str (:x %) "," (:y %)) (:vertices facet)))}])
(defn- dali-facet->svg-poly
[facet]
(vec
(cons
:polygon
(map #(vec (list (:x %) (:y %))) (:vertices facet)))))
(defn dali-stl->svg
"Format this `stl` as SVG for the `dali` renderer on a page with these
bounds."
[stl minx maxx miny maxy]
[:dali/page
{:xmlns "http://www.w3.org/2000/svg"
:version "1.2"
:width (- maxx minx)
:height (- maxy miny)
:viewBox (s/join " " (map str [minx miny maxx maxy]))}
(vec
(cons
:g
(map
dali-facet->svg-poly
(:facets stl))))])
(defn hiccup-stl->svg
"Format this `stl` as SVG for the `hiccup` renderer on a page with these
bounds."
[stl minx maxx miny maxy]
[:svg
{:xmlns "http://www.w3.org/2000/svg"
:version "1.2"
:width (- maxx minx)
:height (- maxy miny)
:viewBox (s/join " " (map str [minx miny maxx maxy]))}
(vec
(cons
:g
(map
facet->svg-poly
(:facets stl))))])
(defn stl->svg
"Convert this in-memory `stl` structure, as read by `decode-binary-stl`, into
an in-memory hiccup representation of SVG structure, and return it."
[stl]
(let [minx (reduce
min
(map
#(reduce min (map :x (:vertices %)))
(:facets stl)))
maxx (reduce
max
(map
#(reduce max (map :x (:vertices %)))
(:facets stl)))
miny (reduce
min
(map
#(reduce min (map :y (:vertices %)))
(:facets stl)))
maxy (reduce
max
(map
#(reduce max (map :y (:vertices %)))
(:facets stl)))]
(info "Generating SVG for " *preferred-svg-render* " renderer")
(case *preferred-svg-render*
:hiccup (hiccup-stl->svg stl minx maxx miny maxy)
:dali (dali-stl->svg stl minx maxx miny maxy)
(throw (Exception. "Unexpected renderer value: " *preferred-svg-render*)))))
(defn binary-stl-file->svg
"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."
([in-filename]
(stl->svg (cull-ocean-facets (decode-binary-stl in-filename))))
([in-filename out-filename]
(let [s (binary-stl-file->svg in-filename)]
(info "Emitting SVG with " *preferred-svg-render* " renderer")
(case *preferred-svg-render*
:dali (neatly-folded-clock/render-svg s out-filename)
:hiccup (spit out-filename (html s))
(throw (Exception. "Unexpected renderer value: " *preferred-svg-render*)))
s)))

View file

@ -0,0 +1,60 @@
(ns cc.journeyman.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."
(:require [clojure.set :refer [difference union]]
[taoensso.timbre :as l]
[cc.journeyman.walkmap.utils :refer [kind-type]])
(:import [clojure.lang IPersistentMap]))
(defn tagged?
"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."
[^IPersistentMap object & tags]
(let [tags' (flatten tags)]
(when-not (every? keyword? tags')
(throw (IllegalArgumentException.
(str "Must be keywords: " (map kind-type tags')))))
(let [ot (::tags object)]
(and
(set? ot)
(every? ot tags')))))
(defn tag
"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. any of `tags` is not a keyword or sequence of keywords.
It's legal to include sequences of keywords in `tags`, so that users can do
useful things like `(tag obj (map keyword some-strings))`."
[^IPersistentMap object & tags]
(l/debug "Tagging" (kind-type object) "with" tags)
(let [tags' (flatten tags)]
(when-not (every? keyword? tags')
(throw (IllegalArgumentException.
(str "Must be keywords: " (map kind-type tags')))))
(assoc object ::tags (union (set tags') (::tags 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. 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 or sequence of keywords."
[^IPersistentMap object & tags]
(let [tags' (flatten tags)]
(when-not (every? keyword? tags')
(throw (IllegalArgumentException.
(str "Must be keywords: " (map kind-type tags')))))
(update-in object [:walkmap.tag/tags] difference (set tags'))))

View file

@ -0,0 +1,19 @@
(ns cc.journeyman.walkmap.test-all
(:require [cc.journeyman.walkmap.mw-stl :refer [mw->stl]]
[cc.journeyman.walkmap.stl :refer [write-ascii-stl]]
[mw-engine.world :refer [world?]]))
(defn run-test
([^String name]
(run-test (str name ".edn") (str name ".stl") name))
([^String mw-name ^String stl-name ^String title]
(let [mw (read-string (slurp mw-name))]
(if (world? mw)
(write-ascii-stl
stl-name
(mw->stl mw)
title)
(throw (IllegalArgumentException.
(format
"Content of file '%s' was not recognised as a valid world"
mw-name)))))))

View file

@ -0,0 +1,119 @@
(ns cc.journeyman.walkmap.utils
"Miscellaneous utility functions."
(:require [clojure.edn :as edn :only [read]]
[clojure.java.io :as io]
[clojure.math.numeric-tower :as m]
[clojure.set :refer [union]]
[clojure.string :as s]))
(defn deep-merge
"Recursively merges maps. If vals are not maps, the last value wins."
;; TODO: not my implementation, not sure I entirely trust it.
[& vals]
(if (every? map? vals)
(let [tags (apply union (map :cc.journeyman.walkmap.tag/tags vals))]
(assoc (apply merge-with deep-merge vals) :cc.journeyman.walkmap.tag/tags tags))
(last vals)))
(defn truncate
"If string `s` is more than `n` characters long, return the first `n`
characters; otherwise, return `s`."
[s n]
(if (and (string? s) (number? n) (> (count s) n))
(subs s 0 n)
s))
(defn kind-type
"Identify the type of an `object`, e.g. for logging. If it has a `:kind` key,
it's one of ours, and that's what we want. Otherwise, we want its type; but
the type of `nil` is `nil`, which doesn't get printed when assembling error
messages, so return \"nil\"."
[object]
(or (:kind object) (type object) "nil"))
(defn =ish
"True if numbers `n1`, `n2` are roughly equal; that is to say, equal to
within `tolerance` (defaults to one part in one hundred thousand)."
([^Number n1 ^Number n2]
(if (and (number? n1) (number? n2))
(let [m (m/abs (min n1 n2))
t (if (zero? m) 0.00001 (* 0.00001 m))]
(=ish n1 n2 t))
(= n1 n2)))
([^Number n1 ^Number n2 ^Number tolerance]
(if (and (number? n1) (number? n2))
(< (m/abs (- n1 n2)) tolerance)
(= n1 n2))))
(defmacro check-kind-type
"If `object` is not of kind-type `expected`, throws an
IllegalArgumentException with an appropriate message; otherwise, returns
`object`. If `checkfn` is supplied, it should be a function which tests
whether the object is of the expected kind-type.
Macro, so that the exception is thrown from the calling function."
([object expected]
`(if-not (= (kind-type ~object) ~expected)
(throw
(IllegalArgumentException.
(s/join
" "
["Expected" ~expected "but found" (kind-type ~object)])))
~object))
([object checkfn expected]
`(if-not (~checkfn ~object)
(throw
(IllegalArgumentException.
(s/join
" "
["Expected" ~expected "but found" (kind-type ~object)])))
~object)))
(defmacro check-kind-type-seq
"If some item on sequence `s` is not of the `expected` kind-type, throws an
IllegalArgumentException with an appropriate message; otherwise, returns
`object`. If `checkfn` is supplied, it should be a function which tests
whether the object is of the expected kind-type.
Macro, so that the exception is thrown from the calling function."
([s expected]
`(if-not (every? #(= (kind-type %) ~expected) ~s)
(throw
(IllegalArgumentException.
(s/join
" "
["Expected sequence of"
~expected
"but found ("
(s/join ", " (remove #(= ~expected %) (map kind-type ~s)))
")"])))
~s))
([s checkfn expected]
`(if-not (every? #(~checkfn %) ~s)
(throw
(IllegalArgumentException.
(s/join
" "
["Expected sequence of"
~expected
"but found ("
(s/join ", " (remove #(= ~expected %) (map kind-type ~s)))
")"])))
~s)))
(defn load-edn
"Load edn from an io/reader source (filename or io/resource)."
[source]
(try
(with-open [r (io/reader source)]
(edn/read (java.io.PushbackReader. r)))
(catch java.io.IOException e
(printf "Couldn't open '%s': %s\n" source (.getMessage e)))
(catch RuntimeException e
(printf "Error parsing edn file '%s': %s\n" source (.getMessage e)))))
(defn not-yet-implemented
[message]
(throw
(UnsupportedOperationException.
(str "Not yet implemented: " message))))

View file

@ -0,0 +1,152 @@
(ns cc.journeyman.walkmap.vertex
"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`."
(:require [clojure.math.numeric-tower :as m]
[clojure.string :as s]
[taoensso.timbre :as l]
[cc.journeyman.walkmap.utils :refer
[=ish check-kind-type check-kind-type-seq kind-type truncate]]))
(defn vertex-key
"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`; it is an error and an exception will be thrown if `o` does not
conform to this specification.
**Note:** these keys can be quite long. No apology is made: it is required
that the same key can *never* refer to two different locations in space."
[o]
(keyword
(s/replace
(cond
(and (:x o) (:y o) (:z o))
(str "vert_" (:x o) "_" (:y o) "_" (:z o))
(and (:x o) (:y o))
(str "vert_" (:x o) "_" (:y o))
:else
(throw (IllegalArgumentException.
(truncate (str "Not a vertex: " (or o "nil")) 80))))
#"\p{Punct}"
"_")))
(defn vertex?
"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."
[o]
(and
(map? o)
(:walkmap.id/id o)
(number? (:x o))
(number? (:y o))
(or (nil? (:z o)) (number? (:z o)))
(or (nil? (:kind o)) (= (:kind o) :vertex))))
(defmacro check-vertex
"If `o` is not a vertex, throw an `IllegalArgumentException` with an
appropriate message; otherwise, returns `o`. Macro, so exception is thrown
from the calling function."
[o]
`(check-kind-type ~o vertex? :vertex))
(defmacro check-vertices
"If `o` is not a sequence of vertices, throw an `IllegalArgumentException` with an
appropriate message; otherwise, returns `o`. Macro, so exception is thrown
from the calling function."
[o]
`(check-kind-type-seq ~o vertex? :vertex))
(defn vertex=
"True if vertices `v1`, `v2` represent the same vertex."
[v1 v2]
(check-vertex v1)
(check-vertex v2)
(every?
#(=ish (% v1) (% v2))
[:x :y :z]))
(defn vertex*
"Return a vertex like `v1`, but with each of its coordinates multiplied
by the equivalent vertex in `v2`. It is an error, and an exception will
be thrown, if either `v1` or `v2` is not a vertex."
[v1 v2]
(let [f (fn [v1 v2 coord]
(* (or (coord v1) 0)
;; one here is deliberate!
(or (coord v2) 1)))]
(assoc v1 :x (f (check-vertex v1) (check-vertex v2) :x)
:y (f v1 v2 :y)
:z (f v1 v2 :z))))
(defn vertex
"Make a vertex with this `x`, `y` and (if provided) `z` values. Returns a map
with those values, plus a unique `:walkmap.id/id` value, and `:kind` set to `:vertex`.
It's not necessary to use this function to create a vertex, but the `:walkmap.id/id`
must be present and must be unique."
([x y]
(let [v {:x x :y y :kind :vertex}]
(assoc v :walkmap.id/id (vertex-key v))))
([x y z]
(let [v {:x x :y y :z z :kind :vertex}]
(assoc v :walkmap.id/id (vertex-key v)))))
(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]
(if
(and
(map? o)
(number? (:x o))
(number? (:y o))
(or (nil? (:z o)) (number? (:z o))))
(assoc o :kind :vertex :walkmap.id/id (vertex-key o))
(throw
(IllegalArgumentException.
(truncate
(str "Not a proto-vertex: must have numeric `:x` and `:y`: "
(or o "nil"))
80)))))
(def ensure3d
"Given a vertex `o`, if `o` has a `:z` value, just return `o`; otherwise
return a vertex like `o` but having this `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."
(memoize
(fn
([o]
(ensure3d o 0.0))
([o dflt]
(if (:z (check-vertex o))
o
(assoc o :z dflt))))))
(def ensure2d
"If `o` is a vertex, set its `:z` value to zero; else throw an exception."
(memoize
(fn [o]
(assoc (check-vertex o) :z 0.0))))
(defn within-box?
"True if `target` is within the box defined by `minv` and `maxv`. All
arguments must be vertices; additionally, both `minv` and `maxv` must
have `:z` coordinates."
[target minv maxv]
(do
(check-vertices [target minv maxv])
(every?
true?
(map
#(if (% target)
(<= (% minv) (% target) (% maxv))
true)
[:x :y :z]))))

View file

@ -1,52 +0,0 @@
# -*- encoding: utf-8 -*-
# From https://github.com/IsseiMori/binary-stl-toASCII/blob/master/BinaryToASCII.py
# Included here to sanity check.
import struct
infile = open('../the-great-game/resources/maps/heightmap.stl') #import file
out = open('ASCII.stl', 'w') #export file
data = infile.read()
out.write("solid ")
for x in xrange(0,80):
if not ord(data[x]) == 0:
out.write(struct.unpack('c', data[x])[0])
else:
pass
out.write("\n")
number = data[80] + data[81] + data[82] + data[83]
faces = struct.unpack('I',number)[0]
for x in range(0,faces):
out.write("facet normal ")
xc = data[84+x*50] + data[85+x*50] + data[86+x*50] + data[87+x*50]
yc = data[88+x*50] + data[89+x*50] + data[90+x*50] + data[91+x*50]
zc = data[92+x*50] + data[93+x*50] + data[94+x*50] + data[95+x*50]
out.write(str(struct.unpack('f',xc)[0]) + " ")
out.write(str(struct.unpack('f',yc)[0]) + " ")
out.write(str(struct.unpack('f',zc)[0]) + "\n")
out.write("outer loop\n")
for y in range(1,4):
out.write("vertex ")
xc = data[84+y*12+x*50] + data[85+y*12+x*50] + data[86+y*12+x*50] + data[87+y*12+x*50]
yc = data[88+y*12+x*50] + data[89+y*12+x*50] + data[90+y*12+x*50] + data[91+y*12+x*50]
zc = data[92+y*12+x*50] + data[93+y*12+x*50] + data[94+y*12+x*50] + data[95+y*12+x*50]
out.write(str(struct.unpack('f',xc)[0]) + " ")
out.write(str(struct.unpack('f',yc)[0]) + " ")
out.write(str(struct.unpack('f',zc)[0]) + "\n")
out.write("endloop\n")
out.write("endfacet\n")
out.close()
print "end"

View file

@ -1,44 +0,0 @@
(ns walkmap.core
"At this stage, primarily utility functions dealing with stereolithography
(STL) files. Not a stable API yet!"
(:require [clojure.java.io :as io :refer [file output-stream input-stream]]
[clojure.string :as s]
[hiccup.core :refer [html]]
[me.raynes.fs :as fs]
[taoensso.timbre :as l :refer [info error spy]]
[walkmap.stl :refer [decode-binary-stl]]
[walkmap.svg :refer [stl->svg]]))
(def ^:dynamic *sea-level*
"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`!"
0.0)
(defn ocean?
"Of a `facet`, is the altitude of every vertice equal to `*sea-level*`?"
[facet]
(every?
#(= % *sea-level*)
(map :z (:vertices facet))))
(defn cull-ocean-facets
"Ye cannae walk on water. Remove all facets from this `stl` structure which
are at sea level."
[stl]
(assoc stl :facets (remove ocean? (:facets stl))))
(defn binary-stl-file->svg
"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."
([in-filename]
(stl->svg (cull-ocean-facets (decode-binary-stl in-filename))))
([in-filename out-filename]
(let [s (binary-stl-file->svg in-filename)]
(spit out-filename (html s))
s)))

View file

@ -1,82 +0,0 @@
(ns 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."
(:require [clojure.math.numeric-tower :as m]
[walkmap.path :refer [path? polygon->path]]
[walkmap.polygon :refer [polygon?]]
[walkmap.vertex :refer [ensure3d vertex?]]))
(defn edge?
"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."
[o]
(and
(map? o)
(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."
[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))))
(defn length
"Return the length of the edge `e`."
[e]
(let [start (ensure3d (:start e))
end (ensure3d (:end e))]
(m/sqrt
(reduce
+
(map
#(m/expt (- (% end) (% start)) 2)
[:x :y :z])))))
(defn unit-vector
"Return an vertex parallel to `e` starting from the coordinate origin. Two
edges which are parallel will have the same unit vector."
[e]
(let [e' {:start (ensure3d (:start e)) :end (ensure3d (:end e))}
l (length e')]
(reduce
merge
{}
(map
(fn [k]
{k (/ (- (k (:end e')) (k (:start e'))) l)})
[:x :y :z]))))
(defn parallel?
"True if all `edges` passed are parallel with one another."
;; TODO: this bears being wary about, dealing with floating point arithmetic.
;; Keep an eye out for spurious errors.
[& edges]
(let [uvs (map unit-vector edges)]
(every?
#(= % (first uvs))
(rest uvs))))
(defn collinear?
"True if edges `e1` and `e2` are collinear with one another."
[e1 e2]
(parallel?
e1
e2
{:start (:start e1) :end (:start e2)}))

View file

@ -1,24 +0,0 @@
(ns walkmap.geometry
(:require [clojure.math.combinatorics :as combo]
[clojure.math.numeric-tower :as m]
[walkmap.edge :as e]
[walkmap.path :refer [path? polygon->path]]
[walkmap.polygon :refer [polygon?]]
[walkmap.vertex :as v]))
(defn on?
"True if the vertex `v` is on the edge `e`."
[e v]
(let [p (v/ensure3d (:start e))
q (v/ensure3d v)
r (v/ensure3d (:end e))]
(and
(e/collinear? p q r)
(<= (:x q) (max (:x p) (:x r)))
(>= (:x q) (min (:x p) (:x r)))
(<= (:y q) (max (:y p) (:y r)))
(>= (:y q) (min (:y p) (:y r)))
(<= (:z q) (max (:z p) (:z r)))
(>= (:z q) (min (:z p) (:z r))))))

View file

@ -1,30 +0,0 @@
(ns walkmap.path
"Essentially the specification for things we shall consider to be path."
(:require [walkmap.polygon :refer [polygon?]]
[walkmap.vertex :refer [vertex?]]))
(defn path?
"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`."
[o]
(let
[v (:nodes o)]
(and
(seq? v)
(> (count v) 2)
(every? vertex? v))))
(defn polygon->path
"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."
[o]
(if
(polygon? o)
(assoc (dissoc o :vertices) :nodes (concat (:vertices o) (list (first (:vertices o)))))
(throw (Exception. "Not a polygon!"))))

View file

@ -1,17 +0,0 @@
(ns walkmap.polygon
"Essentially the specification for things we shall consider to be polygons."
(:require [walkmap.vertex :refer [vertex?]]))
(defn polygon?
"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."
[o]
(let
[v (:vertices o)]
(and
(seq? v)
(> (count v) 2)
(every? vertex? v))))

View file

@ -1,126 +0,0 @@
(ns walkmap.stl
"Utility functions dealing with stereolithography (STL) files. Not a stable API yet!"
(:require [clojure.java.io :as io :refer [file output-stream input-stream]]
[clojure.string :as s]
[me.raynes.fs :as fs]
[org.clojars.smee.binary.core :as b]
[taoensso.timbre :as l :refer [info error spy]]
[walkmap.polygon :refer [polygon?]])
(:import org.clojars.smee.binary.core.BinaryIO
java.io.DataInput))
(defn stl?
"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."
([o]
(stl? o false))
([o verify-count?]
(and
(map? o)
(:facets o)
(every? polygon? (:facets o))
(if (:header o) (string? (:header o)) true)
(if (:count o) (integer? (:count o)) true)
(if verify-count? (= (:count o) (count (:facets o))) true))))
(def vect
"A codec for vectors within a binary STL file."
(b/ordered-map
:x :float-le
:y :float-le
:z :float-le))
(def facet
"A codec for a facet (triangle) within a binary STL file."
(b/ordered-map
:normal vect
:vertices [vect vect vect]
:abc :ushort-le))
(def binary-stl
"A codec for binary STL files"
(b/ordered-map
:header (b/string "ISO-8859-1" :length 80) ;; for the time being we neither know nor care what's in this.
:count :uint-le
:facets (b/repeated facet)))
(defn decode-binary-stl
"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."
[filename]
(let [in (io/input-stream filename)]
(b/decode binary-stl in)))
(defn- vect->str [prefix v]
(str prefix " " (:x v) " " (:y v) " " (:z v) "\n"))
(defn- facet2str [tri]
(str
(vect->str "facet normal" (:normal tri))
"outer loop\n"
(apply str
(map
#(vect->str "vertex" %)
(:vertices tri)))
"endloop\nendfacet\n"))
(defn stl->ascii
"Return as a string an ASCII rendering of the `stl` structure."
([stl]
(stl->ascii stl "unknown"))
([stl solidname]
(str
"solid "
solidname
(s/trim (:header stl))
"\n"
(apply
str
(map
facet2str
(:facets stl)))
"endsolid "
solidname
"\n")))
(defn write-ascii-stl
"Write an `stl` structure as read by `decode-binary-stl` to this
`filename` as ASCII encoded STL."
([filename stl]
(let [b (fs/base-name filename true)]
(write-ascii-stl
filename stl
(subs b 0 (or (s/index-of b ".") (count b))))))
([filename stl solidname]
(l/debug "Solid name is " solidname)
(spit
filename
(stl->ascii stl solidname))))
(defn binary-stl-to-ascii
"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`."
([in-filename]
(let [[_ ext] (fs/split-ext in-filename)]
(binary-stl-to-ascii
in-filename
(str
(subs
in-filename
0
(or
(s/last-index-of in-filename ".")
(count in-filename)))
".ascii"
ext))))
([in-filename out-filename]
(write-ascii-stl out-filename (decode-binary-stl in-filename))))

View file

@ -1,50 +0,0 @@
(ns walkmap.svg
"Utility functions for writing stereolithography (STL) files (and possibly,
later, other geometry files of interest to us) as scalable vector graphics
(SVG)."
(:require [clojure.string :as s]
[taoensso.timbre :as l :refer [info error spy]]
[walkmap.polygon :refer [polygon?]]
[walkmap.vertex :refer [vertex?]]))
(defn- facet->svg-poly
[facet]
[:polygon
{:points (s/join " " (map #(str (:x %) "," (:y %)) (:vertices facet)))}])
(defn stl->svg
"Convert this in-memory `stl` structure, as read by `decode-binary-stl`, into
an in-memory hiccup representation of SVG structure, and return it."
[stl]
(let [minx (reduce
min
(map
#(reduce min (map :x (:vertices %)))
(:facets stl)))
maxx (reduce
max
(map
#(reduce max (map :x (:vertices %)))
(:facets stl)))
miny (reduce
min
(map
#(reduce min (map :y (:vertices %)))
(:facets stl)))
maxy (reduce
max
(map
#(reduce max (map :y (:vertices %)))
(:facets stl)))]
[:svg
{:xmlns "http://www.w3.org/2000/svg"
:version "1.2"
:width (- maxx minx)
:height (- maxy miny)
:viewBox (s/join " " (map str [minx miny maxx maxy]))}
(vec
(cons
:g
(map
facet->svg-poly
(:facets stl))))]))

View file

@ -1,43 +0,0 @@
(ns walkmap.vertex
"Essentially the specification for things we shall consider to be vertices.")
(defn vertex?
"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."
[o]
(and
(map? o)
(number? (:x o))
(number? (:y o))
(or (nil? (:z o)) (number? (:z o)))))
(def 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."
(memoize
(fn
([o]
(ensure3d o 0.0))
([o dflt]
(cond
(not (vertex? o)) (throw (Exception. "Not a vertex!"))
(:z o) o
:else (assoc o :z dflt))))))
(def ensure2d
"If `o` is a vertex, set its `:z` value to zero; else throw an exception."
(memoize
(fn [o]
(if
(vertex? o)
(assoc o :z 0.0)
(throw (Exception. "Not a vertex!"))))))

View file

@ -0,0 +1,124 @@
(ns cc.journeyman.walkmap.edge-test
(:require [clojure.math.numeric-tower :as m]
[clojure.test :refer :all]
[cc.journeyman.walkmap.edge :refer [collinear? collinear2d? edge
edge? intersection2d length
minimaxd parallel? overlaps2d?
unit-vector]]
[cc.journeyman.walkmap.vertex :refer [vertex vertex=]]))
(deftest edge-test
(testing "identification of edges."
(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 :walkmap.id/id 'foo}
:end {:x 3 :y 4 :z 0.0 :walkmap.id/id 'bar}})) "Start lacks :x key")
(is (not (edge? {:start {:x nil :y 0.0 :z 0.0 :walkmap.id/id 'foo}
:end {:x 3 :y 4 :z 0.0 :walkmap.id/id 'bar}})) "Start lacks :x value")
(is (not (edge? {:begin {:x nil :y 0.0 :z 0.0 :walkmap.id/id 'foo}
:end {:x 3 :y 4 :z 0.0 :walkmap.id/id 'bar}})) "Lacks start key")
(is (not (edge? {:start {:x nil :y 0.0 :z 0.0 :walkmap.id/id 'foo}
:finish {:x 3 :y 4 :z 0.0 :walkmap.id/id 'bar}})) "Lacks end key")
(is (not (edge? {:start {:x "zero" :y 0.0 :z 0.0 :walkmap.id/id 'foo}
:end {:x 3 :y 4 :z 0.0 :walkmap.id/id 'bar}})) "Value of x in start is not a number")
(is (false? (edge? "I am not an edge")) "Edge mustbe a map.")))
(deftest collinear-test
(testing "collinearity"
(is (collinear? {:start {:x 0.0 :y 0.0 :z 0.0 :walkmap.id/id 'foo} :end {:x 3.0 :y 4.0 :z 0.0 :walkmap.id/id 'bar}}
{:start {:x 3.0 :y 4.0 :z 0.0 :walkmap.id/id 'foo} :end {:x 9.0 :y 12.0 :z 0.0 :walkmap.id/id 'bar}})
"Should be")
(is (not
(collinear? {:start {:x 0.0 :y 0.0 :z 0.0 :walkmap.id/id 'foo} :end {:x 3 :y 4 :z 0.0 :walkmap.id/id 'bar}}
{:start {:x 1.0 :y 2.0 :z 3.5 :walkmap.id/id 'foo} :end {:x 4.0 :y 6.0 :z 3.5 :walkmap.id/id 'bar}}))
"Should not be!")
(is (collinear? {:start {:x 0.0 :y 0.0 :z 0.0 :walkmap.id/id 'foo} :end {:x 3.0 :y 4.0 :z 0.0 :walkmap.id/id 'bar}}
{:start {:x 0.0 :y 0.0 :z 0.0 :walkmap.id/id 'foo} :end {:x 9.0 :y 12.0 :z 0.0 :walkmap.id/id 'bar}})
"Edge case: same start location")
(is (collinear? {:start {:x 0.0 :y 0.0 :z 0.0 :walkmap.id/id 'foo} :end {:x 9.0 :y 12.0 :z 0.0 :walkmap.id/id 'bar}}
{:start {:x 3.0 :y 4.0 :z 0.0 :walkmap.id/id 'foo} :end {:x 9.0 :y 12.0 :z 0.0 :walkmap.id/id 'bar}})
"Edge case: same end location")
))
(deftest collinear2d-test
(testing "Collinearity when projected onto the x,y plane."
(is (collinear2d? (edge (vertex 1.0 1.0) (vertex 5.0 5.0))
(edge (vertex 4.0 4.0) (vertex 6.0 6.0)))
"Collinear, overlapping.")
(is (collinear2d? (edge (vertex 1.0 1.0 0.0) (vertex 5.0 5.0 5.0))
(edge (vertex 4.0 4.0 79.3) (vertex 6.0 6.0 0.2)))
"Separated in the z axis, but collinear in x, y.")))
(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 intersection2d-test
(testing "intersection of two edges projected onto the x,y plane."
(is (thrown? IllegalArgumentException
(intersection2d
(edge (vertex 1.0 1.0) (vertex 5.0 5.0))
"This is not an edge"))
"Not an edge (second arg) -> exception.")
(is (thrown? IllegalArgumentException
(intersection2d
"This is not an edge"
(edge (vertex 1.0 1.0) (vertex 5.0 5.0))))
"Not an edge (first arg) -> exception.")
(is (nil? (intersection2d (edge (vertex 1.0 1.0) (vertex 5.0 5.0))
(edge (vertex 1.0 2.0) (vertex 5.0 6.0))))
"Parallel but not intersecting.")
(is (:x (intersection2d (edge (vertex 1.0 1.0) (vertex 5.0 5.0))
(edge (vertex 4.0 4.0) (vertex 6.0 6.0)))
5.0)
"Collinear, overlapping, should choose the overlapping end of the first edge.")
(is (= (:x (intersection2d (edge (vertex 1.0 1.0) (vertex 5.0 5.0))
(edge (vertex 1.0 5.0) (vertex 5.0 1.0))))
3.0)
"Crossing, should intersect at 3.0, 3.0: x coord.")
(is (= (:y (intersection2d (edge (vertex 1.0 1.0) (vertex 5.0 5.0))
(edge (vertex 1.0 5.0) (vertex 5.0 1.0))))
3.0)
"Crossing, should intersect at 3.0, 3.0: y coord.")
(is (= (:y (intersection2d (edge (vertex 1.0 1.0 0.0) (vertex 5.0 5.0 0.0))
(edge (vertex 1.0 5.0 999) (vertex 5.0 1.0 379))))
3.0)
"Crossing, presence of z coordinate should make no difference")))
(deftest length-test
(testing "length of an edge"
(is (= (length {:start {:x 0.0 :y 0.0 :z 0.0 :walkmap.id/id 'foo} :end {:x 3.0 :y 4.0 :z 0.0 :walkmap.id/id 'bar}}) 5.0))))
(deftest minimaxd-test
(testing "finding minimum and maximum coordinates of edges."
(is (= (minimaxd (edge (vertex 1.0 2.0 3.0) (vertex 4.0 8.0 12.0)) :x min) 1.0))
(is (= (minimaxd (edge (vertex 1.0 2.0 3.0) (vertex 4.0 8.0 12.0)) :y max) 8.0))))
(deftest parallel-test
(testing "parallelism"
(is (parallel? (edge (vertex 0.0 0.0 0.0) (vertex 3 4 0.0))
(edge (vertex 1.0 2.0 3.5) (vertex 4.0 6.0 3.5)))
"Should be")
(is (not
(parallel? (edge (vertex 0.0 0.0 0.0) (vertex 3 4 0.0))
(edge (vertex 1.0 2.0 3.5) (vertex 4.0 6.0 3.49))))
"Should not be!")))
(deftest overlaps2d-test
(testing "whether two edges are in the same area of the x,y plane."
(is (false? (overlaps2d? (edge (vertex 1 1) (vertex 4 4)) (edge (vertex 5 5) (vertex 8 8)))))
(is (overlaps2d? (edge (vertex 1 1) (vertex 4 4)) (edge (vertex 4 4) (vertex 1 1))))))
(deftest unit-vector-test
(testing "deriving the unit vector"
(is (vertex=
(unit-vector (edge (vertex 0.0 0.0 0.0) (vertex 3 4 0.0)))
(vertex 0.6 0.8 0.0)))
(is (vertex=
(unit-vector (edge (vertex 1.0 2.0 3.5) (vertex 4.0 6.0 3.5)))
(vertex 0.6 0.8 0.0)))))

View file

@ -0,0 +1,53 @@
(ns cc.journeyman.walkmap.ocean-test
(:require [clojure.test :refer :all]
[cc.journeyman.walkmap.ocean :refer [*sea-level* cull-ocean-facets ocean?]]
[cc.journeyman.walkmap.polygon :refer [polygon]]
[cc.journeyman.walkmap.vertex :refer [vertex vertex=]]))
(deftest ocean-tests
(testing "Identification of polygons at sea level"
(is (ocean? (polygon (vertex 0 0 0) (vertex 0 1 0) (vertex 1 0 0)))
"All `:z` coordinates are zero, and default binding for `*sea-level*`
=> ocean.")
(is (false? (ocean? (polygon (vertex 0 0 1) (vertex 0 1 0) (vertex 1 0 0))))
"Not all `:z` coordinates are zero, and default binding for `*sea-level*`
=> not ocean.")
(is (false? (ocean? (polygon (vertex 0 0 5) (vertex 0 1 5) (vertex 1 0 5))))
"Not all `:z` coordinates are five, and default binding for `*sea-level*`
=> not ocean.")
(binding [*sea-level* 5]
(is (false? (ocean? (polygon (vertex 0 0 0) (vertex 0 1 0) (vertex 1 0 0))))
"All `:z` coordinates are zero, and `*sea-level*` rebound to five
=> not ocean.")
(is (false? (ocean? (polygon (vertex 0 0 1) (vertex 0 1 0) (vertex 1 0 0))))
"Not all `:z` coordinates are zero, and `*sea-level*` rebound to five
=> not ocean.")
(is (ocean? (polygon (vertex 0 0 5) (vertex 0 1 5) (vertex 1 0 5)))
"Not all `:z` coordinates are five, and `*sea-level*` rebound to five
=> ocean."))))
(deftest cull-ocean-facets-tests
(testing "Culling of ocean facets (not currently used)."
(let [stl {:facets [(polygon (vertex 0 0 0) (vertex 0 1 0) (vertex 1 0 0))
(polygon (vertex 0 0 1) (vertex 0 1 0) (vertex 1 0 0))
(polygon (vertex 0 0 5) (vertex 0 1 5) (vertex 1 0 5))]}
expected {:facets
[(polygon (vertex 0 0 1) (vertex 0 1 0) (vertex 1 0 0))
(polygon (vertex 0 0 5) (vertex 0 1 5) (vertex 1 0 5))]}
actual (cull-ocean-facets stl)]
(map
#(is (vertex= (nth (:facets expected) %) (nth (:facets actual) %))
(str "Facet " % " did not match."))
(range (max (count (:facets expected)) (count (:facets actual))))))
(binding [*sea-level* 5]
(let [stl {:facets [(polygon (vertex 0 0 0) (vertex 0 1 0) (vertex 1 0 0))
(polygon (vertex 0 0 1) (vertex 0 1 0) (vertex 1 0 0))
(polygon (vertex 0 0 5) (vertex 0 1 5) (vertex 1 0 5))]}
expected {:facets
[(polygon (vertex 0 0 0) (vertex 0 1 0) (vertex 1 0 0))
(polygon (vertex 0 0 1) (vertex 0 1 0) (vertex 1 0 0))]}
actual (cull-ocean-facets stl)]
(map
#(is (vertex= (nth (:facets expected) %) (nth (:facets actual) %))
(str "Facet " % " did not match."))
(range (max (count (:facets expected)) (count (:facets actual)))))))))

View file

@ -0,0 +1,113 @@
(ns cc.journeyman.walkmap.path-test
(:require [clojure.test :refer :all]
[cc.journeyman.walkmap.edge :refer [edge?]]
[cc.journeyman.walkmap.path :refer [check-path check-paths
length path path? path->edges
polygon->path]]
[cc.journeyman.walkmap.polygon :refer [polygon]]
[cc.journeyman.walkmap.utils :refer [kind-type]]
[cc.journeyman.walkmap.vertex :refer [vertex vertex=]]))
(deftest path-tests
(testing "Path instantiation"
(is (= (kind-type (path (vertex 0 0 0) (vertex 1 1 1))) :path)
"Paths should be identified as paths.")
(is (path? (path (vertex 0 0 0) (vertex 1 1 1)))
"Paths should test as paths.")
(is (check-path (path (vertex 0 0 0) (vertex 1 1 1)))
"No exception should be thrown when checking a valid path.")
(is (thrown?
IllegalArgumentException
(check-path
(update-in
(path (vertex 0 0 0) (vertex 1 1 1))
[:vertices]
conj
"Not a vertex")))
"Checking an invalid path should throw an exception.")
(is (thrown?
IllegalArgumentException
(path (vertex 0 0 0)))
"Too short.")
(is (thrown?
IllegalArgumentException
(path (vertex 0 0 0) (vertex 1 1 1) "Not a vertex"))
"Non-vertex included.")
(is (thrown?
IllegalArgumentException
(path (vertex 0 0 0) (vertex 1 1 1) "Not a vertex."))
"Passing something which is not a vertex when constructing a path whould
cause an exception to be thrown.")))
(deftest conversion-tests
(testing "Converting polygons to paths"
(let [poly (polygon (vertex 0 0 0) (vertex 1 0 0) (vertex 1 1 0) (vertex 0 1 0))
p (polygon->path poly)]
(is (path? p) "Should be a path.")
(is (vertex= (first (:vertices p)) (last (:vertices p)))
"First and last vertices of the generated path should be equal to
one another.")
(is (= (count (:vertices p)) (inc (count (:vertices poly))))
"The generated path should have one more vertex than the polygon.")
(map
#(is (vertex= (nth (:vertices poly) %) (nth (:vertices p) %))
(str "Vertex " % " from each set of vertices should be the same."))
(range (count (:vertices poly))))))
(testing "Converting polygons and paths to edges."
(let [poly (polygon (vertex 0 0 0) (vertex 1 0 0) (vertex 1 1 0) (vertex 0 1 0))
edges (path->edges poly)]
(is (every? edge? edges)
"Every returned edge should be an edge.")
(is (= (count (:vertices poly)) (count edges))
"There should be the same number of edges as the vertices of the polygon")
(doall
(map
#(is
(vertex= (nth (:vertices poly) %) (:start (nth edges %)))
(str
"Each edge should start from the same place as the corresponding
vertex: " %))
(range (count (:vertices poly)))))
(doall
(map
#(is
(vertex= (nth (:vertices poly) (mod (inc %) (count (:vertices poly))))
(:end (nth edges %)))
(str
"Each edge should end at the same place as the subsequent
vertex: " %))
(range (count (:vertices poly))))))
(is (thrown? IllegalArgumentException
(path->edges "Not a legal argument.")))))
(deftest check-paths-tests
(testing "Checking multiple paths."
(is (thrown? IllegalArgumentException
(check-paths [(path (vertex 0 0 0)
(vertex 1 0 0)
(vertex 1 1 0)
(vertex 0 1 0)
(vertex 0 0 0))
(path (vertex 0 0 1)
(vertex 1 0 1)
(vertex 1 1 1)
(vertex 0 1 1)
(vertex 0 0 1))
(vertex 0 0 0)]))
"Not all elements are paths")
(is (check-paths [(path (vertex 0 0 0)
(vertex 1 0 0)
(vertex 1 1 0)
(vertex 0 1 0)
(vertex 0 0 0))
(path (vertex 0 0 1)
(vertex 1 0 1)
(vertex 1 1 1)
(vertex 0 1 1)
(vertex 0 0 1))])
"All elements are paths")))
(deftest length-tests
(testing "length of paths"
(let [p (path (vertex 0 0 0) (vertex 1 0 0) (vertex 1 1 0) (vertex 0 1 0) (vertex 0 0 0))]
(is (= (length p) 4) "By inspection."))))

View file

@ -0,0 +1,85 @@
(ns cc.journeyman.walkmap.polygon-test
(:require [clojure.test :refer :all]
;; [clojure.algo.generic.math-functions :as m]
;; [cc.journeyman.walkmap.edge :refer [edge?]]
;; [cc.journeyman.walkmap.path :refer :all]
[cc.journeyman.walkmap.polygon :refer [centre check-polygon
check-polygons
check-triangle gradient
polygon polygon?
triangle?]]
[cc.journeyman.walkmap.utils :refer [kind-type]]
[cc.journeyman.walkmap.vertex :refer [vertex vertex? vertex=]])
)
(deftest polygon-tests
(testing "Constructing polygons"
(let [square (polygon (vertex 0 0 0) (vertex 1 0 0)
(vertex 1 1 0) (vertex 0 1 0))
triangle (polygon (vertex 0 0 0) (vertex 0 3 0)
(vertex 4 0 0))]
(is (= (kind-type square) :polygon)
"Square should have `:kind` = `:polygon`.")
(is (= (kind-type triangle) :polygon)
"Triangle should have `:kind` = `:polygon`.")
(is (polygon? square) "Square should be a polygon.")
(is (polygon? triangle) "Triangle should be a polygon.")
(is (false? (triangle? square)) "Square is not a triangle.")
(is (triangle? triangle) "Triangle is a triangle.")
(is (check-polygon square) "No exception should be thrown.")
(is (check-polygon triangle) "No exception should be thrown.")
(is (check-triangle triangle) "No exception should be thrown.")
(is (check-polygons [square triangle])
"No exception should be thrown.")
(is (thrown?
IllegalArgumentException
(check-polygon "Not a polygon")) "Not a polygon")
(is (thrown?
IllegalArgumentException
(check-polygons [square triangle "Not a polygon"]))
"One value is not a polygon.")
(is (thrown?
IllegalArgumentException (check-triangle square))
"Not a triangle.")
(is (thrown?
IllegalArgumentException (polygon (vertex 0 0 0) (vertex 1 0 0)))
"Too few vertices.")
(is (thrown?
IllegalArgumentException (polygon (vertex 0 0 0) (vertex 1 0 0)
(vertex 1 1 0) "Not a vertex"
(vertex 0 1 0)))
"Non-vertex included.")
)
))
(deftest gradient-tests
(testing "Finding the gradient across a triangle."
(let [tri (polygon (vertex 0 0 1) (vertex 1 0 0) (vertex 1 1 0.5))
gra (gradient tri)]
(is (nil? (:gradient tri)) "Basic trangle should not have a gradient.")
(is (vertex? (:gradient gra))
"After passing through gradient function, it should have a gradient.")
;; TODO: I need to check that the gradient is being computed correclt,
;; but my brain isn't up to the trigonometry just now.
)))
(deftest centre-tests
(testing "Finding the centres of polygons."
(let [square (polygon (vertex 0 0 0) (vertex 1 0 0)
(vertex 1 1 0) (vertex 0 1 0))
triangle (polygon (vertex 0 0 0) (vertex 0 3 0)
(vertex 4 0 0))
centred (centre triangle)]
(is (vertex= (:centre centred) (vertex 1.3333333 1.0 0.0))
"By inspection (check this maths!).")
(is (thrown?
UnsupportedOperationException
(centre square))
"We can't yet find the centre of a quadrilateral, but we should be
able to do so, so it isn't an illegal argument, it just doesn't
work.")
(is (thrown?
IllegalArgumentException
(centre "Not a polygon"))
"Anything else that isn't a polygon, though, is an illegal argument."))))

View file

@ -0,0 +1,96 @@
(ns cc.journeyman.walkmap.stl-test
(:require [clojure.test :refer :all]
[cc.journeyman.walkmap.stl :refer [canonicalise stl?]]
[cc.journeyman.walkmap.polygon :refer [polygon?]]
[cc.journeyman.walkmap.vertex :refer [vertex?]]))
(deftest canonicalise-test
(testing "Canonicalisation of objects read from STL: vertices."
(is (vertex? (canonicalise {:x 3.0, :y 1.0, :z 1.0}))
"Vertex: should have an `:walkmap.id/id` and `:kind` = `:vertex`.")
(is (= (:x (canonicalise {:x 3.0, :y 1.0, :z 1.0})) 3.0)
"`:x` value should be unchanged.")
(is (= (:y (canonicalise {:x 3.0, :y 1.0, :z 1.0})) 1.0)
"`:y` value should be unchanged.")
(is (= (:z (canonicalise {:x 3.0, :y 1.0, :z 1.0})) 1.0)
"`:z` value should be unchanged.")
(is (every?
vertex?
(canonicalise [{:x 3.0, :y 1.0, :z 1.0}
{:x 2.0, :y 3.0, :z 1.0}
{:x 0.0, :y 0.0, :z 1.0}]))
"Vertices: should recurse."))
(testing "Canonicalisation of objects read from STL: facets/polygons."
(let [p {:normal {:x -0.0, :y 0.0, :z 1.0},
:vertices [{:x 3.0, :y 1.0, :z 1.0}
{:x 2.0, :y 3.0, :z 1.0}
{:x 0.0, :y 0.0, :z 1.0}],
:abc 0}
p' (canonicalise p)]
(is (polygon? p')
"Polygon: should have an `:walkmap.id/id` and `:kind` = `:polygon`.")
(is (= (count (:vertices p)) (count (:vertices p')))
"Number of vertices should not change")
(map
#(is (= (map % (:vertices p))(map % (:vertices p')))
(str "Order of vertices should not change: " %))
[:x :y :z]))
(is (every?
polygon?
(canonicalise
[{:normal {:x -0.0, :y 0.0, :z 1.0},
:vertices [{:x 3.0, :y 1.0, :z 1.0}
{:x 2.0, :y 3.0, :z 1.0}
{:x 0.0, :y 0.0, :z 1.0}],
:abc 0}
{:normal {:x 0.0, :y 0.0, :z 1.0},
:vertices [{:x 10.0, :y 4.0, :z 1.0}
{:x 22.0, :y 3.0, :z 1.0}
{:x 13.0, :y 5.0, :z 1.0}],
:abc 0}
{:normal {:x 0.0, :y 0.0, :z 1.0},
:vertices [{:x 26.0, :y 46.0, :z 1.0}
{:x 29.0, :y 49.0, :z 1.0}
{:x 31.0, :y 61.0, :z 1.0}],
:abc 0}
{:normal {:x -0.0, :y 0.0, :z 1.0},
:vertices [{:x 16.0, :y 33.0, :z 1.0}
{:x 15.0, :y 35.0, :z 1.0}
{:x 13.0, :y 32.0, :z 1.0}],
:abc 0}
{:normal {:x 0.0, :y 0.0, :z 1.0},
:vertices [{:x 81.0, :y 0.0, :z 1.0}
{:x 54.0, :y 27.0, :z 1.0}
{:x 51.0, :y 20.0, :z 1.0}],
:abc 0}]))
"Facets/polygons: should recurse."))
(testing "Canonicalisation of entire STL structure."
(let [stl {:header "Dummy test STL",
:count 5,
:facets [{:normal {:x -0.0, :y 0.0, :z 1.0},
:vertices [{:x 3.0, :y 1.0, :z 1.0}
{:x 2.0, :y 3.0, :z 1.0}
{:x 0.0, :y 0.0, :z 1.0}],
:abc 0}
{:normal {:x 0.0, :y 0.0, :z 1.0},
:vertices [{:x 10.0, :y 4.0, :z 1.0}
{:x 22.0, :y 3.0, :z 1.0}
{:x 13.0, :y 5.0, :z 1.0}],
:abc 0}
{:normal {:x 0.0, :y 0.0, :z 1.0},
:vertices [{:x 26.0, :y 46.0, :z 1.0}
{:x 29.0, :y 49.0, :z 1.0}
{:x 31.0, :y 61.0, :z 1.0}],
:abc 0}
{:normal {:x -0.0, :y 0.0, :z 1.0},
:vertices [{:x 16.0, :y 33.0, :z 1.0}
{:x 15.0, :y 35.0, :z 1.0}
{:x 13.0, :y 32.0, :z 1.0}],
:abc 0}
{:normal {:x 0.0, :y 0.0, :z 1.0},
:vertices [{:x 81.0, :y 0.0, :z 1.0}
{:x 54.0, :y 27.0, :z 1.0}
{:x 51.0, :y 20.0, :z 1.0}],
:abc 0}]}
stl' (canonicalise stl)]
(is (stl? stl') "Stl: should have an `:walkmap.id/id` and `:kind` = `:stl`."))))

View file

@ -0,0 +1,135 @@
(ns cc.journeyman.walkmap.superstructure-test
(:require [clojure.set :refer [subset?]]
[clojure.test :refer :all]
[cc.journeyman.walkmap.path :as p]
[cc.journeyman.walkmap.polygon :as q]
[cc.journeyman.walkmap.superstructure :refer [retrieve store vertex-index]]
[cc.journeyman.walkmap.tag :as t]
[cc.journeyman.walkmap.utils :as u]
[cc.journeyman.walkmap.vertex :as v]))
(deftest store-test
(testing "Object storage"
(let [p (p/path
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand)))
id (:walkmap.id/id p)
s (store p)
r (id s)]
(is (= (:walkmap.id/id r) id)
"A representation should be stored in `s` keyed by `id`, and the id of that representation should be `id`.")
(is (= (:kind r) (:kind p))
"The representation should have the same value for `:kind`.")
(is (= (count (:vertices p)) (count (:vertices r)))
"The representation of `p` in `s` should have the same number of vertices as `p`.")
(is (every? v/vertex? (:vertices p))
"Every vertex of `p` should be a vertex.")
(is (every? keyword? (:vertices r))
"Every vertex of the representation of `p` in `s` should be a keyword.")
(is (every? v/vertex? (map #(s %) (:vertices r)))
"The value in `s` of every vertex of the representation of `p` in `s`
should be a vertex.")
(is (subset? (set (:vertices r)) (set (keys (vertex-index s))))
"All the keys which are vertices of the representation of `p` in `s`
should be present as keys in the vertex-index of `s`.")
(is (every?
#(s (% id))
(map #(set (keys (% (vertex-index s)))) (:vertices r)))
"The value in the vertex-index in `s` for each keyword in the
vertexes of the representation of `p` in `s` should include,
as a key, the `id` of `p`."))))
(deftest retrieve-test
(testing "Object retrieval"
;; the value of `s` here is hand-typed; think of it as a specification
(let [s {:path1 {:walkmap.id/id :path1
:kind :path
:vertices '(:vert_0_0_0
:vert_0_0_1
:vert_1_0_0)}
:vert_0_0_0 {:walkmap.id/id :vert_0_0_0
:kind :vertex
:x 0
:y 0
:z 0}
:vert_0_0_1 {:walkmap.id/id :vert_0_0_1
:kind :vertex
:x 0
:y 0
:z 1}
:vert_1_0_0 {:walkmap.id/id :vert_1_0_0
:kind :vertex
:x 1
:y 0
:z 0}
:walkmap.superstructure/vertex-index {:vert_0_0_0 {:path1 :vert_0_0_0}
:vert_0_0_1 {:path1 :vert_0_0_1}
:vert_1_0_0 {:path1 :vert_1_0_0}}}
expected {:kind :path,
:vertices
'({:kind :vertex, :x 0, :y 0, :z 0, :walkmap.id/id :vert_0_0_0}
{:kind :vertex, :x 0, :y 0, :z 1, :walkmap.id/id :vert_0_0_1}
{:kind :vertex, :x 1, :y 0, :z 0, :walkmap.id/id :vert_1_0_0}),
:walkmap.id/id :path1}]
(is (= (retrieve :path1 s) expected)
"The object reconstructed from the superstructure."))))
(deftest round-trip-test
(testing "Roundtripping an object through the superstructure."
(let [p (p/path
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand)))
id (:walkmap.id/id p)
s (store p)
r (retrieve id s)]
(is (= p r) "As it was, so it shall be."))))
(deftest multi-object-round-trip-test
(testing "Roundtripping two different objects through a superstructure."
(let [p (p/path
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand)))
q (p/path
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand)))
pid (:walkmap.id/id p)
qid (:walkmap.id/id q)
s (store q (store p))
rp (retrieve pid s)
rq (retrieve qid s)]
(is (= p rp) "As `p` was, so it shall be.")
(is (= q rq) "As `q` was, so it shall be.")
(is (not= pid qid)
"It is not possible that the ids should be equal, since they are
gensymmed")
(is (not= rp rq)
"It is not possible that the paths should be equal, since at
minimum, their ids are gensymmed."))))
(deftest store-retrieve-edit-store-test
(testing "After editing a retrieved object and storing it again, a further
retrieve should return the new version."
(let [p (p/path
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand))
(v/vertex (rand) (rand) (rand)))
id (:walkmap.id/id p)
o (store p)
r (retrieve id o)
p' (t/tag
(assoc r :vertices
(conj (:vertices id) (v/vertex (rand) (rand) (rand))))
:edited)
o' (store p' o)
r' (retrieve id o')]
(is (not= r r') "The value referenced by `id` should have changed.")
(is (= r' p') "The value referenced by `id` in `o'` should be equal to `p'`."))))

View file

@ -0,0 +1,54 @@
(ns cc.journeyman.walkmap.tag-test
(:require [clojure.test :refer :all]
[cc.journeyman.walkmap.tag :refer [tag tagged? tags untag]]))
(deftest tag-tests
(testing "Tagging"
(is (set? (:walkmap.tag/tags (tag {:kind :test-obj} :foo :bar :ban :froboz)))
"The value of `:walkmap.tag/tags` should be a set.")
(is (= (count (:walkmap.tag/tags (tag {:kind :test-obj} :foo :bar :ban :froboz))) 4)
"All the tags passed should be added.")
(is (:walkmap.tag/tags (tag {:kind :test-obj} :foo :bar :ban :froboz) :ban)
"`:ban` should be present in the set, and, as it is a set, it
should be valid to apply it to a keyword.")
(is (not ((:walkmap.tag/tags (tag {:kind :test-obj} :foo :bar :ban :froboz)) :cornflakes))
"`:cornflakes should not be present.")
(is (true? (tagged? (tag {:kind :test-obj} :foo :bar :ban :froboz) :bar))
"`tagged?` should return an explicit `true`, not any other value.")
(is (tagged? (tag {:kind :test-obj} :foo :bar :ban :froboz) :bar :froboz)
"We should be able to test for the presence of more than one tag")
(is (false? (tagged? {:kind :test-obj} :foo))
"A missing `:walkmap.tag/tags` should not cause an error.")
(is (= (tagged? (tag {:kind :test-obj} :foo :bar :ban :froboz) :bar :cornflakes) false)
"If any of the queried tags is missing, false should be returned")
(is (tagged? (tag (tag {:kind :test-obj} :foo) :bar) :foo :bar)
"We should be able to add tags to an already tagged object")
(is (false? (tagged? (tag {:kind :test-obj} :foo :bar) :cornflakes))
"`tagged?` should return an explicit `false` if a queried tag is missing.")
(is (= (tags (tag {:kind :test-obj} :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 {:kind :test-obj} :foo :bar :ban :froboz)]
(is (= (untag object :cornflakes) object)
"Removing a missing tag should have no effect.")
(is (tagged? (untag object :foo) :bar :ban :froboz)
"All tags not explicitly removed should still be present.")
(is (false? (tagged? (untag object :bar) :bar))
"But the tag which has been removed should be removed."))
(is (thrown? IllegalArgumentException (tag [] :foo))
"An exception should be thrown if `object` is not a map: `tag`.")
(is (thrown? IllegalArgumentException (tagged? [] :foo))
"An exception should be thrown if `object` is not a map: `tagged?`.")
(is (thrown? IllegalArgumentException (untag [] :foo))
"An exception should be thrown if `object` is not a map: `untag`.")
(is (thrown? IllegalArgumentException (tag {:kind :test-obj} :foo "bar" :ban))
"An exception should be thrown if any of `tags` is not a keyword: `tag`.")
(is (thrown? IllegalArgumentException (tagged? {:kind :test-obj} :foo "bar" :ban))
"An exception should be thrown if any of `tags` is not a keyword: `tagged?`.")
(is (thrown? IllegalArgumentException (untag {:kind :test-obj} :foo "bar" :ban))
"An exception should be thrown if any of `tags` is not a keywordp: `untag`.")
(let [o (tag {:kind :test-obj} :foo '(:bar :ban) :froboz)]
(is (tagged? o :ban :bar :foo :froboz)
"It's now allowed to include lists of tags in the arg list for `tag`."))))

View file

@ -0,0 +1,100 @@
(ns cc.journeyman.walkmap.utils-test
(:require [clojure.test :refer :all]
[cc.journeyman.walkmap.utils :refer [=ish check-kind-type check-kind-type-seq kind-type truncate]]
[cc.journeyman.walkmap.vertex :refer [vertex vertex?]]))
(deftest =ish-tests
(testing "Rough equality"
(is (=ish 5.00000001 5.00000002) "Close enough.")
(is (=ish 5 5) "Perfect.")
(is (not (=ish 5.01 5.02)) "Not close enough.")
(is (=ish 22/7 3.142857) "We hope so!")
(is (=ish 0 0.0) "Tricky conrer case!")
(is (=ish :foo :foo) "Fails over to plain old equals for non-numbers.")
(is (=ish 6 5 10000) "If tolerance is wide enough, anything can be equal.")
(is (not (=ish "hello" "goodbye" 10000)) "Well, except non-numbers, of course.")))
(deftest truncate-tests
(testing "String truncation"
(is (= (truncate "The quick brown fox jumped over the lazy dog" 19)
"The quick brown fox")
"If it's a sting, and longer than the desired length, it should be
truncated.")
(is (= (truncate "The quick brown fox jumped over the lazy dog" 100)
"The quick brown fox jumped over the lazy dog")
"If it's a sting, and shorter than the desired length, it should not be
truncated.")
(is (= (truncate :the-quick-brown-fox 10) :the-quick-brown-fox)
"If it's not a string, it should not be truncated, regardless.")))
(deftest kind-type-tests
(testing "Type identification."
(is (= (kind-type {:kind :test}) :test)
"Maps with a value for `:kind` return that as their kind.")
(is (= (kind-type {:dnik :test}) clojure.lang.PersistentArrayMap)
"Maps with no value for `:kind` are just maps.")
(is (= (kind-type nil) "nil")
"As a special case, the kind of `nil` is the string \"nil\".")
(is (= (kind-type "Fred") java.lang.String)
"The kind-type of anything else is just its Java class.")))
(deftest check-kind-type-tests
(testing "Exception thrown if kind not as expected."
(let [v {:kind :test}]
(is (= (check-kind-type v :test) v)
"If the check passes, the object is returned."))
(let [v "test"]
(is (= (check-kind-type v java.lang.String) v)
"If the check passes, the object is returned."))
(let [v "test"]
(is (= (check-kind-type v string? java.lang.String) v)
"If the check passes, the object is returned."))
(let [v (vertex 1 1 1)]
(is (= (check-kind-type v :vertex) v)
"If the check passes, the object is returned."))
(let [v (vertex 1 1 1)]
(is (= (check-kind-type v vertex? :vertex) v)
"If the check passes, the object is returned."))
(let [v "test"]
(is (thrown? IllegalArgumentException
(check-kind-type v :test))
"If the check doesn't pass, an exception is thrown."))
(let [v {:kind :test}]
(is (thrown? IllegalArgumentException
(check-kind-type v vertex? :vertex))
"If the check doesn't pass, an exception is thrown."))))
(deftest check-kind-type-seq-tests
(testing "Exception thrown if kind not as expected: sequence variant."
(let [v [{:kind :test} {:kind :test}]]
(is (= (check-kind-type-seq v :test) v)
"If the check passes, the object is returned."))
(let [v (list "another" "test")]
(is (= (check-kind-type-seq v java.lang.String) v)
"If the check passes, the object is returned."))
(let [v ["more" "test" "strings"]]
(is (= (check-kind-type-seq v string? java.lang.String) v)
"If the check passes, the object is returned."))
(let [v (list (vertex 1 1 1) (vertex 2 2 2) (vertex 3 3 3))]
(is (= (check-kind-type-seq v :vertex) v)
"If the check passes, the object is returned."))
(let [v (list (vertex 1 1 1))]
(is (= (check-kind-type-seq v vertex? :vertex) v)
"If the check passes, the object is returned."))
(let [v :test]
(is (thrown? IllegalArgumentException
(check-kind-type-seq v :test))
"If the arg isn't a sequence, an exception is thrown."))
(let [v (list (vertex 1 1 1) "test" (vertex 3 3 3))]
(is (thrown? IllegalArgumentException
(check-kind-type-seq v :test))
"If the check doesn't pass for any item, an exception is thrown."))
(let [v (list (vertex 1 1 1) (vertex 2 2 2) "test")]
(is (thrown? IllegalArgumentException
(check-kind-type-seq v vertex? :vertex))
"If the check doesn't pass, an exception is thrown."))))

View file

@ -0,0 +1,148 @@
(ns cc.journeyman.walkmap.vertex-test
(:require [clojure.test :refer :all]
[cc.journeyman.walkmap.utils :refer [=ish kind-type]]
[cc.journeyman.walkmap.vertex :refer [canonicalise ensure3d vertex
vertex= vertex* vertex?
within-box?]]))
(deftest vertex-equal-tests
(testing "Equality of vertices"
(is (vertex= (vertex 0 0 0) (vertex 0 0 0))
"should be equal")
(is (vertex= (vertex 0 0 0) (vertex 0.0000001 0 0))
"differences less than one part in a million should be ignored")
(is (false? (vertex= (vertex 0 0 0) (vertex 0 0 1)))
"should not be equal")
(is (thrown? IllegalArgumentException
(vertex= (vertex 0 0 0) "Not a vertex"))
"Exception should be thrown: not a vertex.")))
(deftest vertex-multiply-tests
(testing "multiplication of vertices"
(let [v (vertex (rand) (rand) (rand))
u (vertex 1 1 1)
v' (vertex* v u)]
(is (vertex= v v')
"Multiplication by {:x 1 :y 1 :z 1} should not change the vertex"))
(let [v (vertex 0.333333 0.25 0.2)
d (vertex 3 4 5)
v' (vertex* v d)
expected (vertex 1 1 1)]
(is (vertex= expected v')
"Multiplication by values other than {:x 1 :y 1 :z 1} should change
the vertex"))
(let [v (vertex 0.3333333 0.25 0.2)
d (vertex 3 4)
v' (vertex* v d)
expected (vertex 1 1 0.2)]
(is (vertex= expected v')
"Multiplication by a 2D vertex should not change `:z`"))
(let [v (vertex 0.3333333 0.25)
d (vertex 3 4)
v' (vertex* v d)
expected (vertex 1 1 0)]
(is (=ish 0 (:z v'))
"Multiplication of a 2D vertex should result in `:z` = zero"))
(is (thrown? IllegalArgumentException
(vertex* 3 (vertex 0 0 0)))
"Exception should be thrown: not a vertex (1st arg).")
(is (thrown? IllegalArgumentException
(vertex* (vertex 0 0 0) "Not a vertex"))
"Exception should be thrown: not a vertex (2nd arg).")))
(deftest canonicalise-tests
(testing "Canonicalisation of vertices."
(is (thrown? IllegalArgumentException
(canonicalise {:x "3" :y 4}))
"Exception should be thrown: not a number (`:x` coord).")
(is (thrown? IllegalArgumentException
(canonicalise {:x 3 :y :Jam}))
"Exception should be thrown: not a number (`:y` coord).")
(is (thrown? IllegalArgumentException
(canonicalise {:x 3 :y :4 :z {:foo "bar"}}))
"Exception should be thrown: not a number (`:z` coord).")
(let [v (canonicalise {:x 3 :y 4})]
(is
(= (:walkmap.id/id v)
(keyword (str "vert_" (:x v) "_" (:y v))))
"Vertex ids should match the expected pattern.")
(is (= (kind-type v) :vertex)
"A canonicalised 2d vertex should have the kind `:vertex`.")
(is (vertex? v)
"A canonicalised 2d vertex should be recognisable as a vertex."))
(let [v (canonicalise {:x 3 :y 4 :z 5})]
(is
(= (:walkmap.id/id v)
(keyword (str "vert_" (:x v) "_" (:y v) "_" (:z v))))
"Vertex ids should match the expected pattern.")
(is (= (kind-type v) :vertex)
"A canonicalised 3d vertex should have the kind `:vertex`.")
(is (vertex? v)
"A canonicalised 3d vertex should be recognisable as a vertex."))))
(deftest ensure3d-tests
(testing "Coercing vertices to three dimensions"
(let [v (vertex 2 3)
v' (ensure3d v)]
(is (zero? (:z v'))
"If not already 3d, and no `dflt` arg specified, `:z` should be zero."))
(let [v (vertex 2 3)
v' (ensure3d v 5)]
(is (= (:z v') 5)
"If not already 3d, and `dflt` arg specified, `:z` should be
equal to `dflt`."))
(let [v (vertex 2 3 4)
v' (ensure3d v 5)]
(is (= v v')
"If already 3d, should be unchanged."))))
(deftest within-box-tests
(testing "Checking whether a vertex is within a specified region: 2d."
(is (within-box? (vertex 2 2) (vertex 1 1) (vertex 3 3)) "Should be.")
(is (within-box? (vertex 1 3) (vertex 1 1) (vertex 3 3)) "Should be.")
(is (false? (within-box? (vertex 0 2) (vertex 1 1) (vertex 3 3)))
"Outside west")
(is (false? (within-box? (vertex 5 2) (vertex 1 1) (vertex 3 3)))
"Outside east")
(is (false? (within-box? (vertex 2 0) (vertex 1 1) (vertex 3 3)))
"Outside south")
(is (false? (within-box? (vertex 2 5) (vertex 1 1) (vertex 3 3)))
"Outside north")
(is (false? (within-box? (vertex 2 3.000001) (vertex 1 1) (vertex 3 3)))
"Very slightly outside north"))
(testing "Checking whether a vertex is within a specified region: 3d."
(is (within-box?
(vertex 2 2 2) (vertex 1 1 1) (vertex 3 3 3)) "Should be.")
(is (within-box?
(vertex 1 3 3) (vertex 1 1 1) (vertex 3 3 3)) "Should be.")
(is (false?
(within-box? (vertex 0 2 2) (vertex 1 1 1) (vertex 3 3 3)))
"Outside west")
(is (false?
(within-box? (vertex 5 2 2) (vertex 1 1 1) (vertex 3 3 3)))
"Outside east")
(is (false?
(within-box? (vertex 2 0 2) (vertex 1 1 1) (vertex 3 3 3)))
"Outside south")
(is (false?
(within-box? (vertex 2 5 2) (vertex 1 1 1) (vertex 3 3 3)))
"Outside north")
(is (false?
(within-box? (vertex 2 0 2) (vertex 1 1 1) (vertex 3 3 3)))
"Outside south")
(is (false?
(within-box? (vertex 2 2 0) (vertex 1 1 1) (vertex 3 3 3)))
"Outside down")
(is (false?
(within-box? (vertex 2 2 5) (vertex 1 1 1) (vertex 3 3 3)))
"Outside up"))
(testing "Bad arguments."
(is (thrown? IllegalArgumentException
(within-box? :fred (vertex 1 1 1) (vertex 3 3 3)))
"Not a vertex: `target`.")
(is (thrown? IllegalArgumentException
(within-box? (vertex 2 2 2) :ginny (vertex 3 3 3)))
"Not a vertex: `minv`.")
(is (thrown? IllegalArgumentException
(within-box? (vertex 2 2 2) (vertex 1 1 1) :henry))
"Not a vertex: `maxv`.")))

View file

@ -1,7 +0,0 @@
(ns walkmap.core-test
(:require [clojure.test :refer :all]
[walkmap.core :refer :all]))
;; (deftest a-test
;; (testing "FIXME, I fail."
;; (is (= 0 1))))

View file

@ -1,46 +0,0 @@
(ns walkmap.edge-test
(:require [clojure.test :refer :all]
[walkmap.edge :refer :all]))
(deftest edge-test
(testing "identification of edges."
(is (edge? {:start {:x 0.0 :y 0.0 :z 0.0} :end {:x 3 :y 4 :z 0.0}}) "It is.")
(is (not (edge? {:start {:y 0.0 :z 0.0} :end {:x 3 :y 4 :z 0.0}})) "Start lacks :x key")
(is (not (edge? {:start {:x nil :y 0.0 :z 0.0} :end {:x 3 :y 4 :z 0.0}})) "Start lacks :x value")
(is (not (edge? {:begin {:x nil :y 0.0 :z 0.0} :end {:x 3 :y 4 :z 0.0}})) "Lacks start key")
(is (not (edge? {:start {:x nil :y 0.0 :z 0.0} :finish {:x 3 :y 4 :z 0.0}})) "Lacks end key")
(is (not (edge? {:start {:x "zero" :y 0.0 :z 0.0} :end {:x 3 :y 4 :z 0.0}})) "Value of x in start is not a number")
))
(deftest length-test
(testing "length of an edge"
(is (= (length {:start {:x 0.0 :y 0.0 :z 0.0} :end {:x 3.0 :y 4.0 :z 0.0}}) 5.0))))
(deftest unit-vector-test
(testing "deriving the unit vector"
(is (=
(unit-vector {:start {:x 0.0 :y 0.0 :z 0.0} :end {:x 3 :y 4 :z 0.0}})
{:x 0.6, :y 0.8, :z 0.0}))
(is (=
(unit-vector {:start {:x 1.0 :y 2.0 :z 3.5} :end {:x 4.0 :y 6.0 :z 3.5}})
{:x 0.6, :y 0.8, :z 0.0}))))
(deftest parallel-test
(testing "parallelism"
(is (parallel? {:start {:x 0.0 :y 0.0 :z 0.0} :end {:x 3 :y 4 :z 0.0}}
{:start {:x 1.0 :y 2.0 :z 3.5} :end {:x 4.0 :y 6.0 :z 3.5}})
"Should be")
(is (not
(parallel? {:start {:x 0.0 :y 0.0 :z 0.0} :end {:x 3 :y 4 :z 0.0}}
{:start {:x 1.0 :y 2.0 :z 3.5} :end {:x 4.0 :y 6.0 :z 3.49}}))
"Should not be!")))
(deftest collinear-test
(testing "collinearity"
(is (collinear? {:start {:x 0.0 :y 0.0 :z 0.0} :end {:x 3.0 :y 4.0 :z 0.0}}
{:start {:x 3.0 :y 4.0 :z 0.0} :end {:x 9.0 :y 12.0 :z 0.0}})
"Should be")
(is (not
(collinear? {:start {:x 0.0 :y 0.0 :z 0.0} :end {:x 3 :y 4 :z 0.0}}
{:start {:x 1.0 :y 2.0 :z 3.5} :end {:x 4.0 :y 6.0 :z 3.5}}))
"Should not be!")))