Started MicroWorld integration; more work on unit tests
This commit is contained in:
parent
5328e89c96
commit
3ba8033be8
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -18,3 +18,5 @@ resources/isle_of_man.svg
|
|||
resources/small_hill.svg
|
||||
|
||||
s.edn
|
||||
|
||||
.eastwood
|
||||
|
|
|
@ -40,6 +40,21 @@
|
|||
<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.7647058823529411%;
|
||||
float:left;"> 3 </div><div class="not-covered"
|
||||
style="width:98.23529411764706%;
|
||||
float:left;"> 167 </div></td>
|
||||
<td class="with-number">1.76 %</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">95</td><td class="with-number">8</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%;
|
||||
|
@ -70,18 +85,20 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/polygon.clj.html">walkmap.polygon</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:91.85393258426966%;
|
||||
float:left;"> 327 </div><div class="not-covered"
|
||||
style="width:8.146067415730338%;
|
||||
float:left;"> 29 </div></td>
|
||||
<td class="with-number">91.85 %</td>
|
||||
style="width:71.45969498910675%;
|
||||
float:left;"> 328 </div><div class="not-covered"
|
||||
style="width:28.540305010893245%;
|
||||
float:left;"> 131 </div></td>
|
||||
<td class="with-number">71.46 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:89.58333333333333%;
|
||||
style="width:76.78571428571429%;
|
||||
float:left;"> 43 </div><div class="partial"
|
||||
style="width:10.416666666666666%;
|
||||
float:left;"> 5 </div></td>
|
||||
<td class="with-number">100.00 %</td>
|
||||
<td class="with-number">97</td><td class="with-number">11</td><td class="with-number">48</td>
|
||||
style="width:10.714285714285714%;
|
||||
float:left;"> 6 </div><div class="not-covered"
|
||||
style="width:12.5%;
|
||||
float:left;"> 7 </div></td>
|
||||
<td class="with-number">87.50 %</td>
|
||||
<td class="with-number">114</td><td class="with-number">13</td><td class="with-number">56</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/read_svg.clj.html">walkmap.read-svg</a></td><td class="with-bar"><div class="covered"
|
||||
|
@ -111,11 +128,11 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/stl.clj.html">walkmap.stl</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:50.638297872340424%;
|
||||
style="width:49.07216494845361%;
|
||||
float:left;"> 238 </div><div class="not-covered"
|
||||
style="width:49.361702127659576%;
|
||||
float:left;"> 232 </div></td>
|
||||
<td class="with-number">50.64 %</td>
|
||||
style="width:50.92783505154639%;
|
||||
float:left;"> 247 </div></td>
|
||||
<td class="with-number">49.07 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:40.56603773584906%;
|
||||
float:left;"> 43 </div><div class="partial"
|
||||
|
@ -128,11 +145,11 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/superstructure.clj.html">walkmap.superstructure</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:70.6043956043956%;
|
||||
float:left;"> 257 </div><div class="not-covered"
|
||||
style="width:29.395604395604394%;
|
||||
style="width:71.76781002638522%;
|
||||
float:left;"> 272 </div><div class="not-covered"
|
||||
style="width:28.232189973614776%;
|
||||
float:left;"> 107 </div></td>
|
||||
<td class="with-number">70.60 %</td>
|
||||
<td class="with-number">71.77 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:71.26436781609195%;
|
||||
float:left;"> 62 </div><div class="partial"
|
||||
|
@ -145,11 +162,11 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/svg.clj.html">walkmap.svg</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:4.21455938697318%;
|
||||
style="width:3.7542662116040955%;
|
||||
float:left;"> 11 </div><div class="not-covered"
|
||||
style="width:95.78544061302682%;
|
||||
float:left;"> 250 </div></td>
|
||||
<td class="with-number">4.21 %</td>
|
||||
style="width:96.24573378839591%;
|
||||
float:left;"> 282 </div></td>
|
||||
<td class="with-number">3.75 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:12.121212121212121%;
|
||||
float:left;"> 8 </div><div class="not-covered"
|
||||
|
@ -161,7 +178,7 @@
|
|||
<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;"> 162 </div></td>
|
||||
float:left;"> 178 </div></td>
|
||||
<td class="with-number">100.00 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:100.0%;
|
||||
|
@ -171,43 +188,43 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/utils.clj.html">walkmap.utils</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:52.91005291005291%;
|
||||
float:left;"> 400 </div><div class="not-covered"
|
||||
style="width:47.08994708994709%;
|
||||
float:left;"> 356 </div></td>
|
||||
<td class="with-number">52.91 %</td>
|
||||
style="width:56.216931216931215%;
|
||||
float:left;"> 425 </div><div class="not-covered"
|
||||
style="width:43.783068783068785%;
|
||||
float:left;"> 331 </div></td>
|
||||
<td class="with-number">56.22 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:63.888888888888886%;
|
||||
float:left;"> 23 </div><div class="partial"
|
||||
style="width:8.333333333333334%;
|
||||
float:left;"> 3 </div><div class="not-covered"
|
||||
style="width:27.77777777777778%;
|
||||
float:left;"> 10 </div></td>
|
||||
<td class="with-number">72.22 %</td>
|
||||
style="width:69.44444444444444%;
|
||||
float:left;"> 25 </div><div class="partial"
|
||||
style="width:11.11111111111111%;
|
||||
float:left;"> 4 </div><div class="not-covered"
|
||||
style="width:19.444444444444443%;
|
||||
float:left;"> 7 </div></td>
|
||||
<td class="with-number">80.56 %</td>
|
||||
<td class="with-number">101</td><td class="with-number">9</td><td class="with-number">36</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/vertex.clj.html">walkmap.vertex</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:69.0909090909091%;
|
||||
float:left;"> 380 </div><div class="not-covered"
|
||||
style="width:30.90909090909091%;
|
||||
float:left;"> 170 </div></td>
|
||||
<td class="with-number">69.09 %</td>
|
||||
style="width:86.52094717668488%;
|
||||
float:left;"> 475 </div><div class="not-covered"
|
||||
style="width:13.479052823315119%;
|
||||
float:left;"> 74 </div></td>
|
||||
<td class="with-number">86.52 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:63.013698630136986%;
|
||||
float:left;"> 46 </div><div class="partial"
|
||||
style="width:20.54794520547945%;
|
||||
float:left;"> 15 </div><div class="not-covered"
|
||||
style="width:16.438356164383563%;
|
||||
float:left;"> 12 </div></td>
|
||||
<td class="with-number">83.56 %</td>
|
||||
<td class="with-number">149</td><td class="with-number">15</td><td class="with-number">73</td>
|
||||
style="width:82.1917808219178%;
|
||||
float:left;"> 60 </div><div class="partial"
|
||||
style="width:15.068493150684931%;
|
||||
float:left;"> 11 </div><div class="not-covered"
|
||||
style="width:2.73972602739726%;
|
||||
float:left;"> 2 </div></td>
|
||||
<td class="with-number">97.26 %</td>
|
||||
<td class="with-number">150</td><td class="with-number">15</td><td class="with-number">73</td>
|
||||
</tr>
|
||||
<tr><td>Totals:</td>
|
||||
<td class="with-bar"></td>
|
||||
<td class="with-number">66.22 %</td>
|
||||
<td class="with-number">64.52 %</td>
|
||||
<td class="with-bar"></td>
|
||||
<td class="with-number">70.05 %</td>
|
||||
<td class="with-number">67.67 %</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
|
|
293
docs/cloverage/walkmap/microworld.clj.html
Normal file
293
docs/cloverage/walkmap/microworld.clj.html
Normal file
|
@ -0,0 +1,293 @@
|
|||
<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 (ns walkmap.microworld
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 "An interface between walkmap and microworld, to allow use of microworld
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 functionality to model things like rainfall, soil fertility, settlement
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 and so on."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 (:require [clojure.edn :as edn :only [read]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 [clojure.java.io :as io]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 [clojure.string :as s]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 [mw-cli.core :refer [process]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 [mw-engine.core :refer [run-world]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 [mw-engine.heightmap :as h]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 [mw-engine.drainage :as d]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 [mw-parser.bulk :as parser]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 [taoensso.timbre :as l]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 [walkmap.edge :as e]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 [walkmap.polygon :as p :only [check-polygon polygon? rectangle]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 [walkmap.superstructure :refer [store]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 [walkmap.tag :as t :only [tag tags]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 [walkmap.utils :as u :only [check-kind-type check-kind-type-seq kind-type truncate]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 [walkmap.vertex :as v :only [vertex vertex?]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
020
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ;; (def settlement-rules (parser/compile-file "resources/rules/settlement_rules.txt"))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
022
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ;; (def w0 (h/apply-heightmap "../the-great-game/resources/maps/heightmap.png"))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 ;; (def w1 (d/rain-world (d/flood-hollows w0)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 ;; (def w2 (drainage/flow-world-nr w1))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
026
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
027 ;; (def w3 (run-world w2 nil settlement-rules 100))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
028
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 ;; (with-open [w (clojure.java.io/writer "settlement_1.edn")]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 ;; (binding [*out* w]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
031 ;; (pr
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
032 ;; (run-world w0 nil settlement-rules 100))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
033
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
034 ;; (process
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
035 ;; (h/apply-heightmap "resources/small_hill.png")
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 ;; (parser/compile-file "resources/rules/settlement_rules.txt")
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 ;; 100
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 ;; "small_hill.edn"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
039 ;; "small_hill.html")
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
040
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
041 (defn cell->polygon
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 ([cell]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
043 (cell->polygon cell (v/vertex 1 1 1)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
044 ([cell scale-vector]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
045 (t/tag
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
046 (assoc
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
047 (merge
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
048 cell
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
049 (let [w (* (:x cell) (:x scale-vector))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
050 s (* (:y cell) (:y scale-vector))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
051 e (+ w (:x scale-vector))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
052 n (+ s (:y scale-vector))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
053 z (* (:altitude cell) (:z scale-vector))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
054 (p/rectangle
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
055 (v/vertex s w z)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
056 (v/vertex n e z))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
057 :walkmap.id/id
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
058 (keyword (gensym "mw-cell")))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
059 (:state cell))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
060
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
061 (defn load-microworld-edn
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 "While it would be possible to call MicroWorld functions directly from
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
063 Walkmap, the fact is that running MicroWorld is so phenomenally
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 compute-heavy that it's much more sensible to do it in batch mode. So the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
065 better plan is to be able to pull the output from MicroWorld - as an EDN
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
066 structure - into a walkmap superstructure."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
067 ([filename]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
068 (load-microworld-edn filename :mw))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
069 ([filename map-kind]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
070 (when-not
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
071 (keyword? map-kind)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
072 (throw (IllegalArgumentException.
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
073 (u/truncate
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
074 (str "Must be a keyword: " (or map-kind "nil")) 80))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
075 (load-microworld-edn filename map-kind nil))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
076 ([filename mapkind superstucture]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
077 (load-microworld-edn filename mapkind superstucture (v/vertex 1 1 1)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 ([filename map-kind superstructure scale-vertex]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
079 (let [mw (try
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
080 (with-open [r (io/reader filename)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
081 (edn/read (java.io.PushbackReader. r)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
082 (catch RuntimeException e
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 15 forms covered">
|
||||
083 (l/error "Error parsing edn file '%s': %s\n"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
084 filename (.getMessage e))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
085 polys (reduce
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
086 concat
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
087 (map (fn [row] (map cell->polygon row)) mw))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
088 (if (map? superstructure)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
089 (reduce
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
090 #(store %2 %1)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
091 superstructure
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
092 polys)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
093 polys))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
094
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
095 ;; (load-microworld-edn "../MicroWorld/mw-cli/isle_of_man.edn" nil {})
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
|
@ -23,7 +23,7 @@
|
|||
006 [walkmap.utils :refer [check-kind-type check-kind-type-seq kind-type]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 [walkmap.vertex :refer [check-vertices vertex vertex?]]))
|
||||
007 [walkmap.vertex :refer [check-vertex check-vertices vertex vertex?]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
008
|
||||
|
@ -139,7 +139,7 @@
|
|||
<span class="covered" title="23 out of 23 forms covered">
|
||||
045 (defmacro check-triangle
|
||||
</span><br/>
|
||||
<span class="partial" title="2 out of 6 forms covered">
|
||||
<span class="partial" title="2 out of 10 forms covered">
|
||||
046 "If `o` is not a triangle, throw an `IllegalArgumentException` with an
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
|
@ -154,7 +154,7 @@
|
|||
<span class="covered" title="1 out of 1 forms covered">
|
||||
050 `(check-kind-type ~o triangle? :triangle))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
<span class="blank" title="0 out of 2 forms covered">
|
||||
051
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
|
@ -179,121 +179,172 @@
|
|||
058
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
059 (defn gradient
|
||||
059 (defn rectangle
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 "Return a polygon like `triangle` but with a key `:gradient` whose value is a
|
||||
060 "Return a rectangle, with edges aligned east-west and north-south, whose
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
061 unit vector representing the gradient across `triangle`."
|
||||
061 south-west corner is the vertex `vsw` and whose north-east corner is the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 [triangle]
|
||||
062 vertex `vne`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
063 [vsw vne]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 ;; we can actually create any rectangle in the xy plane based on two opposite
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
065 ;; corners, but the maths are a bit to advanced for me today. TODO: do it!
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 21 forms covered">
|
||||
066 (let [vnw (vertex (:x (check-vertex vsw))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 18 forms covered">
|
||||
067 (:y (check-vertex vne))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 20 forms covered">
|
||||
068 (/ (reduce + (map #(or (:z %) 0) [vsw vne])) 2))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
069 vse (vertex (:x vne)
|
||||
</span><br/>
|
||||
<span class="partial" title="9 out of 12 forms covered">
|
||||
070 (:y vsw)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 20 forms covered">
|
||||
071 (/ (reduce + (map #(or (:z %) 0) [vsw vne])) 2))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
072 (t/tag (polygon vsw vnw vne vse) :rectangle)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
073
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
074 ;; (rectangle (vertex 1 2 3) (vertex 7 9 4))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
075
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
076 (defn gradient
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
077 "Return a polygon like `triangle` but with a key `:gradient` whose value is a
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 unit vector representing the gradient across `triangle`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
079 [triangle]
|
||||
</span><br/>
|
||||
<span class="covered" title="12 out of 12 forms covered">
|
||||
063 (let [order (sort #(max (:z %1) (:z %2))
|
||||
080 (let [order (sort #(max (:z %1) (:z %2))
|
||||
</span><br/>
|
||||
<span class="partial" title="8 out of 18 forms covered">
|
||||
064 (:vertices (check-triangle triangle)))
|
||||
081 (:vertices (check-triangle triangle)))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
065 highest (first order)
|
||||
082 highest (first order)
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
066 lowest (last order)]
|
||||
083 lowest (last order)]
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
067 (assoc triangle :gradient (e/unit-vector (e/edge lowest highest)))))
|
||||
084 (assoc triangle :gradient (e/unit-vector (e/edge lowest highest)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
068
|
||||
085
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
069 (defn triangle-centre
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
070 "Return a canonicalised `facet` (i.e. a triangular polygon) with an added
|
||||
086 (defn triangle-centre
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
071 key `:centre` whose value represents the centre of this facet in 3
|
||||
087 "Return a canonicalised `facet` (i.e. a triangular polygon) with an added
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
072 dimensions. This only works for triangles, so is here not in
|
||||
088 key `:centre` whose value represents the centre of this facet in 3
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
073 `walkmap.polygon`. It is an error (although no exception is currently
|
||||
089 dimensions. This only works for triangles, so is here not in
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
074 thrown) if the object past is not a triangular polygon."
|
||||
090 `walkmap.polygon`. It is an error (although no exception is currently
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
075 [facet]
|
||||
091 thrown) if the object past is not a triangular polygon."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
092 [facet]
|
||||
</span><br/>
|
||||
<span class="partial" title="9 out of 19 forms covered">
|
||||
076 (let [vs (:vertices (check-triangle facet))
|
||||
093 (let [vs (:vertices (check-triangle facet))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
077 v1 (first vs)
|
||||
094 v1 (first vs)
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
078 opposite (e/edge (nth vs 1) (nth vs 2))
|
||||
095 opposite (e/edge (nth vs 1) (nth vs 2))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
079 oc (e/centre opposite)]
|
||||
096 oc (e/centre opposite)]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
080 (assoc
|
||||
097 (assoc
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
081 facet
|
||||
098 facet
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
082 :centre
|
||||
099 :centre
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
083 (vertex
|
||||
100 (vertex
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
084 (+ (:x v1) (* (- (:x oc) (:x v1)) 2/3))
|
||||
101 (+ (:x v1) (* (- (:x oc) (:x v1)) 2/3))
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
085 (+ (:y v1) (* (- (:y oc) (:y v1)) 2/3))
|
||||
102 (+ (:y v1) (* (- (:y oc) (:y v1)) 2/3))
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
086 (+ (:z v1) (* (- (:z oc) (:z v1)) 2/3))))))
|
||||
103 (+ (:z v1) (* (- (:z oc) (:z v1)) 2/3))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
087
|
||||
104
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
088 (defn centre
|
||||
105 (defn centre
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
089 [poly]
|
||||
106 [poly]
|
||||
</span><br/>
|
||||
<span class="covered" title="22 out of 22 forms covered">
|
||||
090 (case (count (:vertices (check-polygon poly)))
|
||||
107 (case (count (:vertices (check-polygon poly)))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
091 3 (triangle-centre poly)
|
||||
108 3 (triangle-centre poly)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
092 ;; else
|
||||
109 ;; else
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
093 (throw
|
||||
110 (throw
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
094 (UnsupportedOperationException.
|
||||
111 (UnsupportedOperationException.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
095 "The general case of centre for polygons is not yet implemented."))))
|
||||
112 "The general case of centre for polygons is not yet implemented."))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
096
|
||||
113
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
097
|
||||
114
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -550,7 +550,7 @@
|
|||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
182 ([filename stl solidname]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
<span class="not-covered" title="0 out of 16 forms covered">
|
||||
183 (l/debug "Solid name is " solidname)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
|
|
|
@ -355,7 +355,7 @@
|
|||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
117 ([o s]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
118 (l/debug "Finding objects in:" o)
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
|
|
|
@ -274,7 +274,7 @@
|
|||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
090 (:facets stl)))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
<span class="not-covered" title="0 out of 17 forms covered">
|
||||
091 (l/info "Generating SVG for " *preferred-svg-render* " renderer")
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
|
@ -316,7 +316,7 @@
|
|||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
104 (let [s (binary-stl-file->svg in-filename)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
<span class="not-covered" title="0 out of 17 forms covered">
|
||||
105 (l/info "Emitting SVG with " *preferred-svg-render* " renderer")
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 [object & tags]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
<span class="covered" title="20 out of 20 forms covered">
|
||||
039 (l/debug "Tagging" (kind-type object) "with" tags)
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
|
@ -205,8 +205,8 @@
|
|||
<span class="covered" title="7 out of 7 forms covered">
|
||||
067 (str "Must be keywords: " (map kind-type tags')))))
|
||||
</span><br/>
|
||||
<span class="covered" title="12 out of 12 forms covered">
|
||||
068 (assoc object ::tags (difference (::tags object) (set tags')))))
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
068 (update-in object [:walkmap.tag/tags] difference (set tags'))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -61,13 +61,13 @@
|
|||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 [s n]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 21 forms covered">
|
||||
<span class="partial" title="19 out of 21 forms covered">
|
||||
020 (if (and (string? s) (number? n) (> (count s) n))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
021 (subs s 0 n)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
022 s))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
<span class="covered" title="3 out of 3 forms covered">
|
||||
045 (:walkmap.id/id o)
|
||||
</span><br/>
|
||||
<span class="partial" title="7 out of 17 forms covered">
|
||||
<span class="partial" title="13 out of 17 forms covered">
|
||||
046 (number? (:x o))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
|
@ -175,7 +175,7 @@
|
|||
<span class="blank" title="0 out of 0 forms covered">
|
||||
057
|
||||
</span><br/>
|
||||
<span class="partial" title="21 out of 22 forms covered">
|
||||
<span class="covered" title="22 out of 22 forms covered">
|
||||
058 (defmacro check-vertices
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
|
@ -208,10 +208,10 @@
|
|||
<span class="covered" title="16 out of 16 forms covered">
|
||||
068 (check-vertex v1)
|
||||
</span><br/>
|
||||
<span class="partial" title="6 out of 16 forms covered">
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
069 (check-vertex v2)
|
||||
</span><br/>
|
||||
<span class="partial" title="3 out of 12 forms covered">
|
||||
<span class="partial" title="5 out of 12 forms covered">
|
||||
070 (every?
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
|
@ -238,218 +238,221 @@
|
|||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 [v1 v2]
|
||||
</span><br/>
|
||||
<span class="partial" title="6 out of 16 forms covered">
|
||||
079 (check-vertex v1)
|
||||
</span><br/>
|
||||
<span class="partial" title="6 out of 16 forms covered">
|
||||
080 (check-vertex v2)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
081 (let [f (fn [v1 v2 coord]
|
||||
</span><br/>
|
||||
<span class="partial" title="9 out of 10 forms covered">
|
||||
082 (* (or (coord v1) 0)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
083 ;; one here is deliberate!
|
||||
</span><br/>
|
||||
<span class="partial" title="7 out of 8 forms covered">
|
||||
084 (or (coord v2) 1)))]
|
||||
</span><br/>
|
||||
<span class="covered" title="11 out of 11 forms covered">
|
||||
085 (assoc v1 :x (f v1 v2 :x)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
086 :y (f v1 v2 :y)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
087 :z (f v1 v2 :z))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
088
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
089 (defn vertex
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
090 "Make a vertex with this `x`, `y` and (if provided) `z` values. Returns a map
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
091 with those values, plus a unique `:walkmap.id/id` value, and `:kind` set to `:vertex`.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
092 It's not necessary to use this function to create a vertex, but the `:walkmap.id/id`
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
093 must be present and must be unique."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
094 ([x y]
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
095 (let [v {:x x :y y :kind :vertex}]
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
096 (assoc v :walkmap.id/id (vertex-key v))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
097 ([x y z]
|
||||
079 (let [f (fn [v1 v2 coord]
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
098 (let [v {:x x :y y :z z :kind :vertex}]
|
||||
080 (* (or (coord v1) 0)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
081 ;; one here is deliberate!
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
082 (or (coord v2) 1)))]
|
||||
</span><br/>
|
||||
<span class="covered" title="41 out of 41 forms covered">
|
||||
083 (assoc v1 :x (f (check-vertex v1) (check-vertex v2) :x)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
084 :y (f v1 v2 :y)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
085 :z (f v1 v2 :z))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
086
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
087 (defn vertex
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
088 "Make a vertex with this `x`, `y` and (if provided) `z` values. Returns a map
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
089 with those values, plus a unique `:walkmap.id/id` value, and `:kind` set to `:vertex`.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
090 It's not necessary to use this function to create a vertex, but the `:walkmap.id/id`
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
091 must be present and must be unique."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
092 ([x y]
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
093 (let [v {:x x :y y :kind :vertex}]
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
099 (assoc v :walkmap.id/id (vertex-key v)))))
|
||||
094 (assoc v :walkmap.id/id (vertex-key v))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
095 ([x y z]
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
096 (let [v {:x x :y y :z z :kind :vertex}]
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
097 (assoc v :walkmap.id/id (vertex-key v)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
100
|
||||
098
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
101 (defn canonicalise
|
||||
099 (defn canonicalise
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
102 "If `o` is a map with numeric values for `:x`, `:y` and optionally `:z`,
|
||||
100 "If `o` is a map with numeric values for `:x`, `:y` and optionally `:z`,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
103 upgrade it to something we will recognise as a vertex."
|
||||
101 upgrade it to something we will recognise as a vertex."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
104 [o]
|
||||
102 [o]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
105 (if
|
||||
103 (if
|
||||
</span><br/>
|
||||
<span class="partial" title="13 out of 17 forms covered">
|
||||
106 (and
|
||||
<span class="partial" title="16 out of 17 forms covered">
|
||||
104 (and
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
107 (map? o)
|
||||
105 (map? o)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
108 (number? (:x o))
|
||||
106 (number? (:x o))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
109 (number? (:y o))
|
||||
107 (number? (:y o))
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
110 (or (nil? (:z o)) (number? (:z o))))
|
||||
108 (or (nil? (:z o)) (number? (:z o))))
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
111 (assoc o :kind :vertex :walkmap.id/id (vertex-key o))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
112 (throw
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
113 (IllegalArgumentException.
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
114 (truncate
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
115 (str "Not a proto-vertex: must have numeric `:x` and `:y`: "
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
116 (or o "nil"))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
117 80)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
118
|
||||
109 (assoc o :kind :vertex :walkmap.id/id (vertex-key o))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
119 (def ensure3d
|
||||
110 (throw
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
111 (IllegalArgumentException.
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
112 (truncate
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
113 (str "Not a proto-vertex: must have numeric `:x` and `:y`: "
|
||||
</span><br/>
|
||||
<span class="partial" title="5 out of 6 forms covered">
|
||||
114 (or o "nil"))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
120 "Given a vertex `o`, if `o` has a `:z` value, just return `o`; otherwise
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
121 return a vertex like `o` but having this `dflt` value as the value of its
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
122 `:z` key, or zero as the value of its `:z` key if `dflt` is not specified.
|
||||
115 80)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
123
|
||||
116
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
117 (def ensure3d
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
124 If `o` is not a vertex, throws an exception."
|
||||
118 "Given a vertex `o`, if `o` has a `:z` value, just return `o`; otherwise
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
119 return a vertex like `o` but having this `dflt` value as the value of its
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
120 `:z` key, or zero as the value of its `:z` key if `dflt` is not specified.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
121
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
122 If `o` is not a vertex, throws an exception."
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
125 (memoize
|
||||
123 (memoize
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
126 (fn
|
||||
124 (fn
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
127 ([o]
|
||||
125 ([o]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
128 (ensure3d o 0.0))
|
||||
126 (ensure3d o 0.0))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
129 ([o dflt]
|
||||
127 ([o dflt]
|
||||
</span><br/>
|
||||
<span class="partial" title="9 out of 19 forms covered">
|
||||
130 (if (:z (check-vertex o))
|
||||
128 (if (:z (check-vertex o))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
131 o
|
||||
129 o
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
132 (assoc o :z dflt))))))
|
||||
130 (assoc o :z dflt))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
133
|
||||
131
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
134 (def ensure2d
|
||||
132 (def ensure2d
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
135 "If `o` is a vertex, set its `:z` value to zero; else throw an exception."
|
||||
133 "If `o` is a vertex, set its `:z` value to zero; else throw an exception."
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
136 (memoize
|
||||
134 (memoize
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
137 (fn [o]
|
||||
135 (fn [o]
|
||||
</span><br/>
|
||||
<span class="partial" title="10 out of 20 forms covered">
|
||||
138 (assoc (check-vertex o) :z 0.0))))
|
||||
136 (assoc (check-vertex o) :z 0.0))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
139
|
||||
137
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
140 (defn within-box?
|
||||
138 (defn within-box?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
141 "True if `target` is within the box defined by `minv` and `maxv`. All
|
||||
139 "True if `target` is within the box defined by `minv` and `maxv`. All
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
142 arguments must be vertices; additionally, both `minv` and `maxv` must
|
||||
140 arguments must be vertices; additionally, both `minv` and `maxv` must
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
143 have `:z` coordinates."
|
||||
141 have `:z` coordinates."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
144 [target minv maxv]
|
||||
142 [target minv maxv]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 34 forms covered">
|
||||
145 (check-vertices [target minv maxv])
|
||||
<span class="partial" title="14 out of 34 forms covered">
|
||||
143 (check-vertices [target minv maxv])
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
146 (every?
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
144 (every?
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
147 (map
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
145 true?
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 16 forms covered">
|
||||
148 #(< (% minv) (or (% target) 0) (% maxv))
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
146 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
149 [:x :y :z])))
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
147 #(if (% target)
|
||||
</span><br/>
|
||||
<span class="covered" title="11 out of 11 forms covered">
|
||||
148 (<= (% minv) (% target) (% maxv))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
149 true)
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
150 [:x :y :z])))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
[dali "0.7.4"] ;; not currently used because performance issues.
|
||||
[hiccup "1.0.5"]
|
||||
[me.raynes/fs "1.4.6"]
|
||||
[mw-cli "0.1.6-SNAPSHOT"]
|
||||
[mw-engine "0.1.6-SNAPSHOT"]
|
||||
[mw-parser "0.1.6-SNAPSHOT"]
|
||||
[smee/binary "0.5.5"]]
|
||||
:deploy-repositories [["releases" :clojars]
|
||||
["snapshots" :clojars]]
|
||||
|
|
155
resources/rules/settlement_rules.txt
Normal file
155
resources/rules/settlement_rules.txt
Normal 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
|
95
src/walkmap/microworld.clj
Normal file
95
src/walkmap/microworld.clj
Normal file
|
@ -0,0 +1,95 @@
|
|||
(ns 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 [clojure.edn :as edn :only [read]]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as s]
|
||||
[mw-cli.core :refer [process]]
|
||||
[mw-engine.core :refer [run-world]]
|
||||
[mw-engine.heightmap :as h]
|
||||
[mw-engine.drainage :as d]
|
||||
[mw-parser.bulk :as parser]
|
||||
[taoensso.timbre :as l]
|
||||
[walkmap.edge :as e]
|
||||
[walkmap.polygon :as p :only [check-polygon polygon? rectangle]]
|
||||
[walkmap.superstructure :refer [store]]
|
||||
[walkmap.tag :as t :only [tag tags]]
|
||||
[walkmap.utils :as u :only [check-kind-type check-kind-type-seq kind-type truncate]]
|
||||
[walkmap.vertex :as v :only [vertex vertex?]]))
|
||||
|
||||
;; (def settlement-rules (parser/compile-file "resources/rules/settlement_rules.txt"))
|
||||
|
||||
;; (def w0 (h/apply-heightmap "../the-great-game/resources/maps/heightmap.png"))
|
||||
;; (def w1 (d/rain-world (d/flood-hollows w0)))
|
||||
;; (def w2 (drainage/flow-world-nr w1))
|
||||
|
||||
;; (def w3 (run-world w2 nil settlement-rules 100))
|
||||
|
||||
;; (with-open [w (clojure.java.io/writer "settlement_1.edn")]
|
||||
;; (binding [*out* w]
|
||||
;; (pr
|
||||
;; (run-world w0 nil settlement-rules 100))))
|
||||
|
||||
;; (process
|
||||
;; (h/apply-heightmap "resources/small_hill.png")
|
||||
;; (parser/compile-file "resources/rules/settlement_rules.txt")
|
||||
;; 100
|
||||
;; "small_hill.edn"
|
||||
;; "small_hill.html")
|
||||
|
||||
(defn cell->polygon
|
||||
([cell]
|
||||
(cell->polygon cell (v/vertex 1 1 1)))
|
||||
([cell scale-vector]
|
||||
(t/tag
|
||||
(assoc
|
||||
(merge
|
||||
cell
|
||||
(let [w (* (:x cell) (:x scale-vector))
|
||||
s (* (:y cell) (:y scale-vector))
|
||||
e (+ w (:x scale-vector))
|
||||
n (+ s (:y scale-vector))
|
||||
z (* (:altitude cell) (:z scale-vector))]
|
||||
(p/rectangle
|
||||
(v/vertex s w z)
|
||||
(v/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."
|
||||
([filename]
|
||||
(load-microworld-edn filename :mw))
|
||||
([filename map-kind]
|
||||
(when-not
|
||||
(keyword? map-kind)
|
||||
(throw (IllegalArgumentException.
|
||||
(u/truncate
|
||||
(str "Must be a keyword: " (or map-kind "nil")) 80))))
|
||||
(load-microworld-edn filename map-kind nil))
|
||||
([filename mapkind superstucture]
|
||||
(load-microworld-edn filename mapkind superstucture (v/vertex 1 1 1)))
|
||||
([filename map-kind superstructure scale-vertex]
|
||||
(let [mw (try
|
||||
(with-open [r (io/reader filename)]
|
||||
(edn/read (java.io.PushbackReader. r)))
|
||||
(catch RuntimeException e
|
||||
(l/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))))
|
||||
|
||||
;; (load-microworld-edn "../MicroWorld/mw-cli/isle_of_man.edn" nil {})
|
|
@ -4,7 +4,7 @@
|
|||
[walkmap.edge :as e]
|
||||
[walkmap.tag :as t]
|
||||
[walkmap.utils :refer [check-kind-type check-kind-type-seq kind-type]]
|
||||
[walkmap.vertex :refer [check-vertices vertex vertex?]]))
|
||||
[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
|
||||
|
@ -52,9 +52,30 @@
|
|||
(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 :polygon})
|
||||
:kind :polygon}
|
||||
(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))]
|
||||
(t/tag (polygon vsw vnw vne 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
|
||||
|
|
|
@ -65,4 +65,4 @@
|
|||
(when-not (every? keyword? tags')
|
||||
(throw (IllegalArgumentException.
|
||||
(str "Must be keywords: " (map kind-type tags')))))
|
||||
(assoc object ::tags (difference (::tags object) (set tags')))))
|
||||
(update-in object [:walkmap.tag/tags] difference (set tags'))))
|
||||
|
|
|
@ -31,11 +31,11 @@
|
|||
|
||||
(defn =ish
|
||||
"True if numbers `n1`, `n2` are roughly equal; that is to say, equal to
|
||||
within `tolerance` (defaults to one part in a million)."
|
||||
within `tolerance` (defaults to one part in one hundred thousand)."
|
||||
([n1 n2]
|
||||
(if (and (number? n1) (number? n2))
|
||||
(let [m (m/abs (min n1 n2))
|
||||
t (if (zero? m) 0.000001 (* 0.000001 m))]
|
||||
t (if (zero? m) 0.00001 (* 0.00001 m))]
|
||||
(=ish n1 n2 t))
|
||||
(= n1 n2)))
|
||||
([n1 n2 tolerance]
|
||||
|
|
|
@ -76,13 +76,11 @@
|
|||
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]
|
||||
(check-vertex v1)
|
||||
(check-vertex v2)
|
||||
(let [f (fn [v1 v2 coord]
|
||||
(* (or (coord v1) 0)
|
||||
;; one here is deliberate!
|
||||
(or (coord v2) 1)))]
|
||||
(assoc v1 :x (f v1 v2 :x)
|
||||
(assoc v1 :x (f (check-vertex v1) (check-vertex v2) :x)
|
||||
:y (f v1 v2 :y)
|
||||
:z (f v1 v2 :z))))
|
||||
|
||||
|
@ -142,8 +140,12 @@
|
|||
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
|
||||
#(< (% minv) (or (% target) 0) (% maxv))
|
||||
[:x :y :z])))
|
||||
#(if (% target)
|
||||
(<= (% minv) (% target) (% maxv))
|
||||
true)
|
||||
[:x :y :z]))))
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
(check-path
|
||||
(update-in
|
||||
(path (vertex 0 0 0) (vertex 1 1 1))
|
||||
:vertices
|
||||
[:vertices]
|
||||
conj
|
||||
"Not a vertex")))
|
||||
"Checking an invalid path should throw an exception.")
|
||||
|
@ -42,10 +42,10 @@
|
|||
(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 p) (last p))
|
||||
(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 path)) (inc (count (:vertices poly))))
|
||||
(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) %))
|
||||
|
@ -58,13 +58,15 @@
|
|||
"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))))
|
||||
(range (count (:vertices poly)))))
|
||||
(doall
|
||||
(map
|
||||
#(is
|
||||
(vertex= (nth (:vertices poly) (mod (inc %) (count (:vertices poly))))
|
||||
|
@ -72,7 +74,7 @@
|
|||
(str
|
||||
"Each edge should end at the same place as the subsequent
|
||||
vertex: " %))
|
||||
(range (count (:vertices poly)))))
|
||||
(range (count (:vertices poly))))))
|
||||
(is (thrown? IllegalArgumentException
|
||||
(path->edges "Not a legal argument.")))))
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(ns walkmap.utils-test
|
||||
(ns walkmap.vertex-test
|
||||
(:require [clojure.test :refer :all]
|
||||
[walkmap.utils :refer [=ish kind-type]]
|
||||
[walkmap.vertex :refer :all]))
|
||||
|
||||
(deftest vertex-equal-tests
|
||||
|
@ -8,7 +9,7 @@
|
|||
"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 (vertex= (vertex 0 0 0) (vertex 0 0 1))
|
||||
(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"))
|
||||
|
@ -28,18 +29,118 @@
|
|||
(is (vertex= expected v')
|
||||
"Multiplication by values other than {:x 1 :y 1 :z 1} should change
|
||||
the vertex"))
|
||||
(let [v (vertex 0.333333 0.25 0.2)
|
||||
(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.333333 0.25)
|
||||
(let [v (vertex 0.3333333 0.25)
|
||||
d (vertex 3 4)
|
||||
v' (vertex* v d)
|
||||
expected (vertex 1 1 0)]
|
||||
(is (vertex= expected v')
|
||||
(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.")))
|
||||
"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`.")))
|
||||
|
|
Loading…
Reference in a new issue