Line intersection looking good.
This commit is contained in:
parent
79174af2c1
commit
1ab35dbe7d
|
@ -27,29 +27,29 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/edge.clj.html">walkmap.edge</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:100.0%;
|
||||
float:left;"> 164 </div></td>
|
||||
<td class="with-number">100.00 %</td>
|
||||
style="width:98.31697054698458%;
|
||||
float:left;"> 701 </div><div class="not-covered"
|
||||
style="width:1.6830294530154277%;
|
||||
float:left;"> 12 </div></td>
|
||||
<td class="with-number">98.32 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:100.0%;
|
||||
float:left;"> 40 </div></td>
|
||||
style="width:95.1923076923077%;
|
||||
float:left;"> 99 </div><div class="partial"
|
||||
style="width:4.8076923076923075%;
|
||||
float:left;"> 5 </div></td>
|
||||
<td class="with-number">100.00 %</td>
|
||||
<td class="with-number">70</td><td class="with-number">7</td><td class="with-number">40</td>
|
||||
<td class="with-number">189</td><td class="with-number">18</td><td class="with-number">104</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>
|
||||
style="width:100.0%;
|
||||
float:left;"> 62 </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;"> 10 </div></td>
|
||||
<td class="with-number">100.00 %</td>
|
||||
<td class="with-number">17</td><td class="with-number">1</td><td class="with-number">10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/ocean.clj.html">walkmap.ocean</a></td><td class="with-bar"><div class="covered"
|
||||
|
@ -79,39 +79,39 @@
|
|||
style="width:84.21052631578948%;
|
||||
float:left;"> 32 </div></td>
|
||||
<td class="with-number">15.79 %</td>
|
||||
<td class="with-number">76</td><td class="with-number">7</td><td class="with-number">38</td>
|
||||
<td class="with-number">78</td><td class="with-number">7</td><td class="with-number">38</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/polygon.clj.html">walkmap.polygon</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:91.30434782608695%;
|
||||
float:left;"> 42 </div><div class="not-covered"
|
||||
style="width:8.695652173913043%;
|
||||
float:left;"> 4 </div></td>
|
||||
<td class="with-number">91.30 %</td>
|
||||
style="width:90.56603773584905%;
|
||||
float:left;"> 48 </div><div class="not-covered"
|
||||
style="width:9.433962264150944%;
|
||||
float:left;"> 5 </div></td>
|
||||
<td class="with-number">90.57 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:88.88888888888889%;
|
||||
float:left;"> 8 </div><div class="partial"
|
||||
style="width:11.11111111111111%;
|
||||
style="width:90.0%;
|
||||
float:left;"> 9 </div><div class="partial"
|
||||
style="width:10.0%;
|
||||
float:left;"> 1 </div></td>
|
||||
<td class="with-number">100.00 %</td>
|
||||
<td class="with-number">18</td><td class="with-number">3</td><td class="with-number">9</td>
|
||||
<td class="with-number">19</td><td class="with-number">3</td><td class="with-number">10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/stl.clj.html">walkmap.stl</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:52.02156334231806%;
|
||||
float:left;"> 193 </div><div class="not-covered"
|
||||
style="width:47.97843665768194%;
|
||||
float:left;"> 178 </div></td>
|
||||
<td class="with-number">52.02 %</td>
|
||||
style="width:56.777996070726914%;
|
||||
float:left;"> 289 </div><div class="not-covered"
|
||||
style="width:43.222003929273086%;
|
||||
float:left;"> 220 </div></td>
|
||||
<td class="with-number">56.78 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:36.8421052631579%;
|
||||
float:left;"> 28 </div><div class="partial"
|
||||
style="width:11.842105263157896%;
|
||||
float:left;"> 9 </div><div class="not-covered"
|
||||
style="width:51.31578947368421%;
|
||||
float:left;"> 39 </div></td>
|
||||
<td class="with-number">48.68 %</td>
|
||||
<td class="with-number">148</td><td class="with-number">13</td><td class="with-number">76</td>
|
||||
style="width:44.0%;
|
||||
float:left;"> 44 </div><div class="partial"
|
||||
style="width:10.0%;
|
||||
float:left;"> 10 </div><div class="not-covered"
|
||||
style="width:46.0%;
|
||||
float:left;"> 46 </div></td>
|
||||
<td class="with-number">54.00 %</td>
|
||||
<td class="with-number">191</td><td class="with-number">14</td><td class="with-number">100</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/superstructure.clj.html">walkmap.superstructure</a></td><td class="with-bar"><div class="covered"
|
||||
|
@ -126,7 +126,7 @@
|
|||
style="width:85.18518518518519%;
|
||||
float:left;"> 23 </div></td>
|
||||
<td class="with-number">14.81 %</td>
|
||||
<td class="with-number">74</td><td class="with-number">8</td><td class="with-number">27</td>
|
||||
<td class="with-number">85</td><td class="with-number">9</td><td class="with-number">27</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/svg.clj.html">walkmap.svg</a></td><td class="with-bar"><div class="covered"
|
||||
|
@ -167,30 +167,30 @@
|
|||
style="width:70.0%;
|
||||
float:left;"> 7 </div></td>
|
||||
<td class="with-number">30.00 %</td>
|
||||
<td class="with-number">26</td><td class="with-number">2</td><td class="with-number">10</td>
|
||||
<td class="with-number">23</td><td class="with-number">3</td><td class="with-number">10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="walkmap/vertex.clj.html">walkmap.vertex</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:84.92063492063492%;
|
||||
float:left;"> 214 </div><div class="not-covered"
|
||||
style="width:15.079365079365079%;
|
||||
float:left;"> 38 </div></td>
|
||||
<td class="with-number">84.92 %</td>
|
||||
style="width:78.08641975308642%;
|
||||
float:left;"> 253 </div><div class="not-covered"
|
||||
style="width:21.91358024691358%;
|
||||
float:left;"> 71 </div></td>
|
||||
<td class="with-number">78.09 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:66.66666666666667%;
|
||||
float:left;"> 28 </div><div class="partial"
|
||||
style="width:16.666666666666668%;
|
||||
float:left;"> 7 </div><div class="not-covered"
|
||||
style="width:16.666666666666668%;
|
||||
float:left;"> 7 </div></td>
|
||||
<td class="with-number">83.33 %</td>
|
||||
<td class="with-number">82</td><td class="with-number">9</td><td class="with-number">42</td>
|
||||
style="width:70.0%;
|
||||
float:left;"> 42 </div><div class="partial"
|
||||
style="width:10.0%;
|
||||
float:left;"> 6 </div><div class="not-covered"
|
||||
style="width:20.0%;
|
||||
float:left;"> 12 </div></td>
|
||||
<td class="with-number">80.00 %</td>
|
||||
<td class="with-number">114</td><td class="with-number">11</td><td class="with-number">60</td>
|
||||
</tr>
|
||||
<tr><td>Totals:</td>
|
||||
<td class="with-bar"></td>
|
||||
<td class="with-number">44.01 %</td>
|
||||
<td class="with-number">61.24 %</td>
|
||||
<td class="with-bar"></td>
|
||||
<td class="with-number">50.55 %</td>
|
||||
<td class="with-number">61.28 %</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
006 [walkmap.polygon :refer [polygon?]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 [walkmap.vertex :refer [ensure3d vertex?]]))
|
||||
007 [walkmap.vertex :refer [ensure2d ensure3d vertex vertex= vertex?]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
008
|
||||
|
@ -119,100 +119,457 @@
|
|||
038
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
039 (defn unit-vector
|
||||
039 (defn centre
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
040 "Return an vertex parallel to `e` starting from the coordinate origin. Two
|
||||
040 "Return the vertex that represents the centre of this `edge`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
041 edges which are parallel will have the same unit vector."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 [e]
|
||||
</span><br/>
|
||||
<span class="covered" title="14 out of 14 forms covered">
|
||||
043 (let [e' {:start (ensure3d (:start e)) :end (ensure3d (:end e))}
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
044 l (length e')]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
045 (reduce
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
046 merge
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
047 {}
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
048 (map
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
049 (fn [k]
|
||||
</span><br/>
|
||||
<span class="covered" title="17 out of 17 forms covered">
|
||||
050 {k (/ (- (k (:end e')) (k (:start e'))) l)})
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
051 [:x :y :z]))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
052
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
053 (defn parallel?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
054 "True if all `edges` passed are parallel with one another."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
055 ;; TODO: this bears being wary about, dealing with floating point arithmetic.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
056 ;; Keep an eye out for spurious errors.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
057 [& edges]
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
058 (let [uvs (map unit-vector edges)]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
059 (every?
|
||||
041 [edge]
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
060 #(= % (first uvs))
|
||||
042 (let [s (ensure3d (:start edge))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
043 e (ensure3d (:end edge))]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
044 (vertex
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
045 (+ (:x s) (/ (- (:x e) (:x s)) 2))
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
046 (+ (:y s) (/ (- (:y e) (:y s)) 2))
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
047 (+ (:z s) (/ (- (:z e) (:z s)) 2)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
048
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
049 (defn unit-vector
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
050 "Return an vertex parallel to `e` starting from the coordinate origin. Two
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
051 edges which are parallel will have the same unit vector."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
052 [e]
|
||||
</span><br/>
|
||||
<span class="covered" title="14 out of 14 forms covered">
|
||||
053 (let [e' {:start (ensure3d (:start e)) :end (ensure3d (:end e))}
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
061 (rest uvs))))
|
||||
054 l (length e')]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
055 (reduce
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
056 merge
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
057 {}
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
058 (map
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
059 (fn [k]
|
||||
</span><br/>
|
||||
<span class="covered" title="17 out of 17 forms covered">
|
||||
060 {k (/ (- (k (:end e')) (k (:start e'))) l)})
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
061 [:x :y :z]))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
062
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
063 (defn collinear?
|
||||
063 (defn parallel?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 "True if edges `e1` and `e2` are collinear with one another."
|
||||
064 "True if all `edges` passed are parallel with one another."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
065 [e1 e2]
|
||||
065 [& edges]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
066 (parallel?
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
066 (let [uvs (map unit-vector edges)]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
067 e1
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
067 (every?
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
068 e2
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
068 #(vertex= % (first uvs))
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
069 {:start (:start e1) :end (:start e2)}))
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
069 (rest uvs))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
070
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
071 (defn collinear?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
072 "True if edges `e1` and `e2` are collinear with one another."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
073 [e1 e2]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
074 (parallel?
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
075 e1
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
076 e2
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
077 (if (vertex= (:start e1) (:start e2))
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
078 {:start (:start e1) :end (:end e2)}
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
079 {:start (:start e1) :end (:start e2)})))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
080
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
081 (defn collinear2d?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
082 "True if the projections of edges `e1`, `e2` onto the x, y plane are
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
083 collinear."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
084 [e1 e2]
|
||||
</span><br/>
|
||||
<span class="covered" title="15 out of 15 forms covered">
|
||||
085 (collinear? {:start (ensure2d (:start e1)) :end (ensure2d (:end e1))}
|
||||
</span><br/>
|
||||
<span class="covered" title="13 out of 13 forms covered">
|
||||
086 {:start (ensure2d (:start e2)) :end (ensure2d (:end e2))}))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
087
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
088 (defn minimaxd
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
089 "Apply function `f` to `coord` of the vertices at start and end of `edge`
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
090 and return the result. Intended use case is `f` = `min` or `max`, `coord`
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
091 is `:x`, `:y` or `:z`. No checks are made for sane arguments."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
092 [edge coord f]
|
||||
</span><br/>
|
||||
<span class="covered" title="15 out of 15 forms covered">
|
||||
093 (apply f (list (coord (:start edge)) (coord (:end edge)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
094
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
095 (defn on?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
096 "True if the vertex `v` is on the edge `e`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
097 [e v]
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
098 (let [p (ensure3d (:start e))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
099 q (ensure3d v)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
100 r (ensure3d (:end e))]
|
||||
</span><br/>
|
||||
<span class="partial" title="20 out of 25 forms covered">
|
||||
101 (and
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
102 (collinear? (edge p q) (edge q r))
|
||||
</span><br/>
|
||||
<span class="covered" title="13 out of 13 forms covered">
|
||||
103 (<= (:x q) (max (:x p) (:x r)))
|
||||
</span><br/>
|
||||
<span class="covered" title="13 out of 13 forms covered">
|
||||
104 (>= (:x q) (min (:x p) (:x r)))
|
||||
</span><br/>
|
||||
<span class="covered" title="13 out of 13 forms covered">
|
||||
105 (<= (:y q) (max (:y p) (:y r)))
|
||||
</span><br/>
|
||||
<span class="covered" title="13 out of 13 forms covered">
|
||||
106 (>= (:y q) (min (:y p) (:y r)))
|
||||
</span><br/>
|
||||
<span class="covered" title="13 out of 13 forms covered">
|
||||
107 (<= (:z q) (max (:z p) (:z r)))
|
||||
</span><br/>
|
||||
<span class="covered" title="12 out of 12 forms covered">
|
||||
108 (>= (:z q) (min (:z p) (:z r))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
109
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
110 (defn on2d?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
111 "True if vertex `v` is on edge `e` when projected onto the x, y plane."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
112 [e v]
|
||||
</span><br/>
|
||||
<span class="covered" title="15 out of 15 forms covered">
|
||||
113 (on? (edge (ensure2d (:start e)) (ensure2d (:end e))) v))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
114
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
115 (defn overlaps2d?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
116 "True if the recangle in the x,y plane bisected by edge `e1` overlaps that
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
117 bisected by edge `e2`. It is an error if either `e1` or `e2` is not an edge."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
118 [e1 e2]
|
||||
</span><br/>
|
||||
<span class="partial" title="11 out of 12 forms covered">
|
||||
119 (when (and (edge? e1) (edge? e2))
|
||||
</span><br/>
|
||||
<span class="partial" title="11 out of 13 forms covered">
|
||||
120 (and
|
||||
</span><br/>
|
||||
<span class="covered" title="12 out of 12 forms covered">
|
||||
121 (> (minimaxd e1 :x max) (minimaxd e2 :x min))
|
||||
</span><br/>
|
||||
<span class="covered" title="12 out of 12 forms covered">
|
||||
122 (< (minimaxd e1 :x min) (minimaxd e2 :x max))
|
||||
</span><br/>
|
||||
<span class="covered" title="12 out of 12 forms covered">
|
||||
123 (> (minimaxd e1 :y max) (minimaxd e2 :y min))
|
||||
</span><br/>
|
||||
<span class="covered" title="11 out of 11 forms covered">
|
||||
124 (< (minimaxd e1 :y min) (minimaxd e2 :y max)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
125
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
126 ;; Don't think I need this.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
127 ;; (defn orientation
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
128 ;; "Determine whether the ordered sequence of vertices `p`, `q` and `r` run
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
129 ;; clockwise, collinear or anticlockwise in the x,y plane."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
130 ;; [p q r]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
131 ;; (let [v (- (* (- (:y q) (:y p)) (- (:x r) (:x q)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
132 ;; (* (- (:x q) (:x p)) (- (:y r) (:y q))))]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
133 ;; (cond
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
134 ;; (zero? v) :collinear
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
135 ;; (pos? v) :clockwise
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
136 ;; :else
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
137 ;; :anticlockwise)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
138
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
139 (defn intersection2d
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
140 "The probability of two lines intersecting in 3d space is low, and actually
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
141 that is mostly not something we're interested in. We're interested in
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
142 intersection in the `x,y` plane. This function returns a vertex representing
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
143 a point vertically over the intersection of edges `e1`, `e2` in the `x,y`
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
144 plane, whose `z` coordinate is
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
145
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
146 * 0 if both edges are 2d (i.e. have missing or zero `z` coordinates);
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
147 * if one edge is 2d, then the point on the other edge over the intersection;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
148 * otherwise, the average of the z coordinates of the points on the two
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
149 edges over the intersection.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
150
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
151 If no such intersection exists, `nil` is returned.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
152
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
153 It is an error, and an exception will be thrown, if either `e1` or `e2` is
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
154 not an edge."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
155 [e1 e2]
|
||||
</span><br/>
|
||||
<span class="covered" title="11 out of 11 forms covered">
|
||||
156 (if (and (edge? e1) (edge? e2))
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
157 (when
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
158 (overlaps2d? e1 e2) ;; relatively cheap check
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
159 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
160 (collinear2d? e1 e2)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
161 ;; any point within the overlap will do, but we'll pick the end of e1
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
162 ;; which is on e2
|
||||
</span><br/>
|
||||
<span class="partial" title="10 out of 13 forms covered">
|
||||
163 (if (on2d? e2 (:start e1)) (:start e1) (:end e1))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
164 ;; blatantly stolen from
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
165 ;; https://gist.github.com/cassiel/3e725b49670356a9b936
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
166 (let [x1 (:x (:start e1))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
167 x2 (:x (:end e1))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
168 x3 (:x (:start e2))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
169 x4 (:x (:end e2))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
170 y1 (:y (:start e1))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
171 y2 (:y (:end e1))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
172 y3 (:y (:start e2))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
173 y4 (:y (:end e2))
|
||||
</span><br/>
|
||||
<span class="covered" title="12 out of 12 forms covered">
|
||||
174 denom (- (* (- x1 x2) (- y3 y4))
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
175 (* (- y1 y2) (- x3 x4)))
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
176 x1y2-y1x2 (- (* x1 y2) (* y1 x2))
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
177 x3y4-y3x4 (- (* x3 y4) (* y3 x4))
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
178 px-num (- (* x1y2-y1x2 (- x3 x4))
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
179 (* (- x1 x2) x3y4-y3x4))
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
180 py-num (- (* x1y2-y1x2 (- y3 y4))
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
181 (* (- y1 y2) x3y4-y3x4))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
182 result (when-not (zero? denom)
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
183 (vertex (/ px-num denom) (/ py-num denom)))]
|
||||
</span><br/>
|
||||
<span class="partial" title="19 out of 20 forms covered">
|
||||
184 (when (and result (on2d? e1 result) (on2d? e2 result)) result))))
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
185 (throw (IllegalArgumentException.
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
186 (str
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
187 "Both `e1` and `e2` must be edges."
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
188 (map #(or (:kind %) (type %)) [e1 e2]))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
189
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -11,70 +11,49 @@
|
|||
002 (:require [clojure.math.combinatorics :as combo]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 [clojure.math.numeric-tower :as m]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 [walkmap.edge :as e]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 [walkmap.path :refer [path? polygon->path]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 [walkmap.polygon :refer [polygon?]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 [walkmap.vertex :as v]))
|
||||
003 [clojure.math.numeric-tower :as m]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
008
|
||||
004
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
009 (defn on?
|
||||
005 (defn =ish
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 "True if the vertex `v` is on the edge `e`."
|
||||
006 "True if numbers `n1`, `n2` are roughly equal; that is to say, equal to
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 [e v]
|
||||
007 within `tolerance` (defaults to one part in a million)."
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
012 (let [p (v/ensure3d (:start e))
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 ([n1 n2]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
013 q (v/ensure3d v)
|
||||
<span class="covered" title="11 out of 11 forms covered">
|
||||
009 (if (and (number? n1) (number? n2))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
014 r (v/ensure3d (:end e))]
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
010 (let [m (m/abs (min n1 n2))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 25 forms covered">
|
||||
015 (and
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
011 t (if (zero? m) 0.000001 (* 0.000001 m))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
016 (e/collinear? p q r)
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
012 (=ish n1 n2 t))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
017 (<= (:x q) (max (:x p) (:x r)))
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
013 (= n1 n2)))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
018 (>= (:x q) (min (:x p) (:x r)))
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 ([n1 n2 tolerance]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
019 (<= (:y q) (max (:y p) (:y r)))
|
||||
<span class="covered" title="11 out of 11 forms covered">
|
||||
015 (if (and (number? n1) (number? n2))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
020 (>= (:y q) (min (:y p) (:y r)))
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
016 (< (m/abs (- n1 n2)) tolerance)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
021 (<= (:z q) (max (:z p) (:z r)))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 12 forms covered">
|
||||
022 (>= (:z q) (min (:z p) (:z r))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
023
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
024
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
017 (= n1 n2))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
010 "True if `o` satisfies the conditions for a path. A path shall be a map
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 having the key `:nodes`, whose value shall be a sequence of vertices as
|
||||
011 having the key `:vertices`, whose value shall be a sequence of vertices as
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 defined in `walkmap.vertex`."
|
||||
|
@ -47,7 +47,7 @@
|
|||
014 (let
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
015 [v (:nodes o)]
|
||||
015 [v (:vertices o)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 22 forms covered">
|
||||
016 (and
|
||||
|
@ -86,7 +86,7 @@
|
|||
027 (every? vertex? vertices)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
028 {:nodes vertices :id (keyword (gensym "path")) :kind :path}
|
||||
028 {:vertices vertices :id (keyword (gensym "path")) :kind :path}
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
029 (throw (IllegalArgumentException. "Each item on path must be a vertex."))))
|
||||
|
@ -125,7 +125,7 @@
|
|||
040 (polygon? o)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 21 forms covered">
|
||||
041 (assoc (dissoc o :vertices) :kind :path :nodes (concat (:vertices o) (list (first (:vertices o)))))
|
||||
041 (assoc (dissoc o :vertices) :kind :path :vertices (concat (:vertices o) (list (first (:vertices o)))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
042 (throw (IllegalArgumentException. "Not a polygon!"))))
|
||||
|
@ -175,62 +175,68 @@
|
|||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
057 (cons
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
058 ;; TODO: think about: when constructing an edge from a path, should the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
059 ;; constructed edge be tagged with the tags of the path?
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
058 (e/edge (first o) (rest o))
|
||||
060 (e/edge (first o) (rest o))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
059 (path->edges (rest o))))
|
||||
061 (path->edges (rest o))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
060 (path? o)
|
||||
062 (path? o)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
061 (path->edges (:nodes o))
|
||||
063 (path->edges (:vertices o))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 :else
|
||||
064 :else
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
063 (throw (IllegalArgumentException.
|
||||
065 (throw (IllegalArgumentException.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 "Not a path or sequence of vertices!"))))
|
||||
066 "Not a path or sequence of vertices!"))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
065
|
||||
067
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
066 (defn length
|
||||
068 (defn length
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
067 "Return the length of this path, in metres. **Note that**
|
||||
069 "Return the length of this path, in metres. **Note that**
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
068 1. This is not the same as the distance from the start to the end of the
|
||||
070 1. This is not the same as the distance from the start to the end of the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
069 path, which, except for absolutely straight paths, will be shorter;
|
||||
071 path, which, except for absolutely straight paths, will be shorter;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
070 2. It is not even quite the same as the length of the path *as rendered*,
|
||||
072 2. It is not even quite the same as the length of the path *as rendered*,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
071 since paths will generally be rendered as spline curves."
|
||||
073 since paths will generally be rendered as spline curves."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
072 [path]
|
||||
074 [path]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
073 (if
|
||||
075 (if
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
074 (path? path)
|
||||
076 (path? path)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
075 (reduce + (map e/length (path->edges path)))
|
||||
077 (reduce + (map e/length (path->edges path)))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
076 (throw (IllegalArgumentException. "Not a path!"))))
|
||||
078 (throw (IllegalArgumentException. "Not a path!"))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<span class="covered" title="3 out of 3 forms covered">
|
||||
011 [v (:vertices o)]
|
||||
</span><br/>
|
||||
<span class="partial" title="14 out of 18 forms covered">
|
||||
<span class="partial" title="17 out of 22 forms covered">
|
||||
012 (and
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
|
@ -49,14 +49,17 @@
|
|||
<span class="covered" title="4 out of 4 forms covered">
|
||||
015 (every? vertex? v)
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
016 (or (nil? (:kind o)) (= (:kind o) :polygon)))))
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
016 (:id o)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
017
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
017 (or (nil? (:kind o)) (= (:kind o) :polygon)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
018
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
019
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -26,427 +26,556 @@
|
|||
007 [taoensso.timbre :as l :refer [info error spy]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 [walkmap.polygon :refer [polygon?]]
|
||||
008 [walkmap.edge :as e]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 [walkmap.vertex :as v])
|
||||
009 [walkmap.polygon :refer [polygon?]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 (:import org.clojars.smee.binary.core.BinaryIO
|
||||
010 [walkmap.tag :refer [tag]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 java.io.DataInput))
|
||||
011 [walkmap.vertex :as v])
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 (:import org.clojars.smee.binary.core.BinaryIO
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 java.io.DataInput))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
012
|
||||
014
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
013 (defn stl?
|
||||
015 (defn stl?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 "True if `o` is recogniseable as an STL structure. An STL structure must
|
||||
016 "True if `o` is recogniseable as an STL structure. An STL structure must
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 have a key `:facets`, whose value must be a sequence of polygons; and
|
||||
017 have a key `:facets`, whose value must be a sequence of polygons; and
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 may have a key `:header` whose value should be a string, and/or a key
|
||||
018 may have a key `:header` whose value should be a string, and/or a key
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 `:count`, whose value should be a positive integer.
|
||||
019 `:count`, whose value should be a positive integer.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
018
|
||||
020
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 If `verify-count?` is passed and is not `false`, verify that the value of
|
||||
021 If `verify-count?` is passed and is not `false`, verify that the value of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 the `:count` header is equal to the number of facets."
|
||||
022 the `:count` header is equal to the number of facets."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ([o]
|
||||
023 ([o]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
022 (stl? o false))
|
||||
024 (stl? o false))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ([o verify-count?]
|
||||
025 ([o verify-count?]
|
||||
</span><br/>
|
||||
<span class="partial" title="20 out of 26 forms covered">
|
||||
024 (and
|
||||
026 (and
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
025 (map? o)
|
||||
027 (map? o)
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
026 (:facets o)
|
||||
028 (:facets o)
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
027 (every? polygon? (:facets o))
|
||||
029 (every? polygon? (:facets o))
|
||||
</span><br/>
|
||||
<span class="partial" title="9 out of 10 forms covered">
|
||||
028 (if (:header o) (string? (:header o)) true)
|
||||
030 (if (:header o) (string? (:header o)) true)
|
||||
</span><br/>
|
||||
<span class="partial" title="9 out of 10 forms covered">
|
||||
029 (if (:count o) (integer? (:count o)) true)
|
||||
031 (if (:count o) (integer? (:count o)) true)
|
||||
</span><br/>
|
||||
<span class="partial" title="14 out of 15 forms covered">
|
||||
030 (or (nil? (:kind o)) (= (:kind o) :stl))
|
||||
032 (or (nil? (:kind o)) (= (:kind o) :stl))
|
||||
</span><br/>
|
||||
<span class="partial" title="1 out of 11 forms covered">
|
||||
031 (if verify-count? (= (:count o) (count (:facets o))) true))))
|
||||
033 (if verify-count? (= (:count o) (count (:facets o))) true))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
032
|
||||
034
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
033 (def vect
|
||||
035 (def vect
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
034 "A codec for vectors within a binary STL file."
|
||||
036 "A codec for vectors within a binary STL file."
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
035 (b/ordered-map
|
||||
037 (b/ordered-map
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 :x :float-le
|
||||
038 :x :float-le
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 :y :float-le
|
||||
039 :y :float-le
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 :z :float-le))
|
||||
040 :z :float-le))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
039
|
||||
041
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
040 (def facet
|
||||
042 (def facet
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
041 "A codec for a facet (triangle) within a binary STL file."
|
||||
043 "A codec for a facet (triangle) within a binary STL file."
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
042 (b/ordered-map
|
||||
044 (b/ordered-map
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
043 :normal vect
|
||||
045 :normal vect
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
044 :vertices [vect vect vect]
|
||||
046 :vertices [vect vect vect]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
045 :abc :ushort-le))
|
||||
047 :abc :ushort-le))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
046
|
||||
048
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
047 (def binary-stl
|
||||
049 (def binary-stl
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
048 "A codec for binary STL files"
|
||||
050 "A codec for binary STL files"
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
049 (b/ordered-map
|
||||
051 (b/ordered-map
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
050 :header (b/string "ISO-8859-1" :length 80) ;; for the time being we neither know nor care what's in this.
|
||||
052 :header (b/string "ISO-8859-1" :length 80) ;; for the time being we neither know nor care what's in this.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
051 :count :uint-le
|
||||
053 :count :uint-le
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
052 :facets (b/repeated facet)))
|
||||
054 :facets (b/repeated facet)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
053
|
||||
055
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
054 (defn canonicalise
|
||||
056 (defn centre
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
055 "Objects read in from STL won't have all the keys/values we need them to have."
|
||||
057 "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">
|
||||
056 [o]
|
||||
058 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">
|
||||
059 dimensions. This only works for triangles, so is here not in
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 `walkmap.polygon`. It is an error (although no exception is currently
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
061 thrown) if the object past is not a triangular polygon."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 [facet]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
063 (let [vs (:vertices facet)
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
064 v1 (first vs)
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
065 opposite (e/edge (nth vs 1) (nth vs 2))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
066 oc (e/centre opposite)]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
067 (assoc
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
068 facet
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
069 :centre
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
070 (v/vertex
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
071 (+ (:x v1) (* (- (:x oc) (:x v1)) 2/3))
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
072 (+ (:y v1) (* (- (:y oc) (:y v1)) 2/3))
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
073 (+ (:z v1) (* (- (:z oc) (:z v1)) 2/3))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
074
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
075 (defn canonicalise
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
076 "Objects read in from STL won't have all the keys/values we need them to have.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
077 `o` may be a map (representing a facet or a vertex), or a sequence of such maps;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 if it isn't recognised it is at present just returned unchanged. `map-kind`, if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
079 passed, must be a keyword indicating the value represented by the `z` axis
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
080 (defaults to `:height`). It is an error, and an exception will be thrown, if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
081 `map-kind` is not a keyword."
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
082 ([o] (canonicalise o :height))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
083 ([o map-kind]
|
||||
</span><br/>
|
||||
<span class="partial" title="2 out of 3 forms covered">
|
||||
084 (when-not
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
085 (keyword? map-kind)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
086 (throw (IllegalArgumentException.
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
087 (subs (str "Must be a keyword: " (or map-kind "nil")) 0 80))))
|
||||
</span><br/>
|
||||
<span class="partial" title="4 out of 5 forms covered">
|
||||
057 (cond
|
||||
088 (cond
|
||||
</span><br/>
|
||||
<span class="partial" title="15 out of 16 forms covered">
|
||||
058 (and (coll? o) (not (map? o))) (map canonicalise o)
|
||||
<span class="partial" title="19 out of 20 forms covered">
|
||||
089 (and (coll? o) (not (map? o))) (map #(canonicalise % map-kind) o)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
059 ;; if it has :facets it's an STL structure, but it doesn't yet conform to `stl?`
|
||||
090 ;; if it has :facets it's an STL structure, but it doesn't yet conform to `stl?`
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
060 (:facets o) (assoc o
|
||||
091 (:facets o) (assoc o
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
061 :kind :stl
|
||||
092 :kind :stl
|
||||
</span><br/>
|
||||
<span class="partial" title="11 out of 12 forms covered">
|
||||
062 :id (or (:id o) (keyword (gensym "stl")))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
063 :facets (canonicalise (:facets o)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 ;; if it has :vertices it's a polygon, but it doesn't yet conform to `polygon?`
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
065 (:vertices o) (assoc o
|
||||
</span><br/>
|
||||
<span class="partial" title="11 out of 12 forms covered">
|
||||
066 :id (or (:id o) (keyword (gensym "poly")))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
067 :kind :polygon
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
068 :vertices (canonicalise (:vertices o)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
069 ;; if it has a value for :x it's a vertex, but it doesn't yet conform to `vertex?`
|
||||
093 :id (or (:id o) (keyword (gensym "stl")))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
070 (:x o) (v/canonicalise o)
|
||||
094 :facets (canonicalise (:facets o) map-kind))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
071 ;; shouldn't happen
|
||||
095 ;; if it has :vertices it's a polygon, but it doesn't yet conform to `polygon?`
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
072 :else o))
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
096 (:vertices o) (centre
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
073
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
097 (tag
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
098 (assoc o
|
||||
</span><br/>
|
||||
<span class="partial" title="11 out of 12 forms covered">
|
||||
099 :id (or (:id o) (keyword (gensym "poly")))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
100 :kind :polygon
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
101 :vertices (canonicalise (:vertices o) map-kind))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
074 (defn decode-binary-stl
|
||||
102 :facet map-kind))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
075 "Parse a binary STL file from this `filename` and return an STL structure
|
||||
103 ;; if it has a value for :x it's a vertex, but it doesn't yet conform to `vertex?`
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
104 (:x o) (v/canonicalise o)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
076 representing its contents.
|
||||
105 ;; shouldn't happen
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
106 :else o)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
077
|
||||
107
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
108 (defn decode-binary-stl
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 **NOTE** that we've no way of verifying that the input file is binary STL
|
||||
109 "Parse a binary STL file from this `filename` and return an STL structure
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
079 data, if it is not this will run but will return garbage."
|
||||
110 representing its contents. `map-kind`, if passed, must be a keyword
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
080 [filename]
|
||||
111 indicating the value represented by the `z` axis (defaults to `:height`).
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
112 It is an error, and an exception will be thrown, if `map-kind` is not a
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
113 keyword.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
114
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
115 **NOTE** that we've no way of verifying that the input file is binary STL
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
116 data, if it is not this will run but will return garbage."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
117 ([filename]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
081 (let [in (io/input-stream filename)]
|
||||
118 (decode-binary-stl filename :height))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
082 (canonicalise (b/decode binary-stl in))))
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
119 ([filename map-kind]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
120 (when-not
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
121 (keyword? map-kind)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
122 (throw (IllegalArgumentException.
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
123 (subs (str "Must be a keyword: " (or map-kind "nil")) 0 80))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
124 (let [in (io/input-stream filename)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
125 (canonicalise (b/decode binary-stl in) map-kind))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
083
|
||||
126
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
084 (defn- vect->str [prefix v]
|
||||
127 (defn- vect->str [prefix v]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 16 forms covered">
|
||||
085 (str prefix " " (:x v) " " (:y v) " " (:z v) "\n"))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
086
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
087 (defn- facet2str [tri]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
088 (str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
089 (vect->str "facet normal" (:normal tri))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
090 "outer loop\n"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
091 (apply str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
092 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
093 #(vect->str "vertex" %)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
094 (:vertices tri)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
095 "endloop\nendfacet\n"))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
096
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
097 (defn stl->ascii
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
098 "Return as a string an ASCII rendering of the `stl` structure."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
099 ([stl]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
100 (stl->ascii stl "unknown"))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
101 ([stl solidname]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
102 (str
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
103 "solid "
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
104 solidname
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
105 (s/trim (:header stl))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
106 "\n"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
107 (apply
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
108 str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
109 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
110 facet2str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
111 (:facets stl)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
112 "endsolid "
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
113 solidname
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
114 "\n")))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
115
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
116 (defn write-ascii-stl
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
117 "Write an `stl` structure as read by `decode-binary-stl` to this
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
118 `filename` as ASCII encoded STL."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
119 ([filename stl]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
120 (let [b (fs/base-name filename true)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
121 (write-ascii-stl
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
122 filename stl
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 15 forms covered">
|
||||
123 (subs b 0 (or (s/index-of b ".") (count b))))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
124 ([filename stl solidname]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 16 forms covered">
|
||||
125 (l/debug "Solid name is " solidname)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
126 (spit
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
127 filename
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
128 (stl->ascii stl solidname))))
|
||||
128 (str prefix " " (:x v) " " (:y v) " " (:z v) "\n"))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
129
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
130 (defn binary-stl-to-ascii
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
131 "Convert the binary STL file indicated by `in-filename`, and write it to
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
132 `out-filename`, if specified; otherwise, to a file with the same basename
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
133 as `in-filename` but the extension `.ascii.stl`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
134 ([in-filename]
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
130 (defn- facet2str [tri]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
135 (let [[_ ext] (fs/split-ext in-filename)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
136 (binary-stl-to-ascii
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
137 in-filename
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
138 (str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
139 (subs
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
140 in-filename
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
141 0
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
142 (or
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
143 (s/last-index-of in-filename ".")
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
144 (count in-filename)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
145 ".ascii"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
146 ext))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
147 ([in-filename out-filename]
|
||||
131 (str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
148 (write-ascii-stl out-filename (decode-binary-stl in-filename))))
|
||||
132 (vect->str "facet normal" (:normal tri))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
133 "outer loop\n"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
134 (apply str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
135 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
136 #(vect->str "vertex" %)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
137 (:vertices tri)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
138 "endloop\nendfacet\n"))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
139
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
140 (defn stl->ascii
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
141 "Return as a string an ASCII rendering of the `stl` structure."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
142 ([stl]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
143 (stl->ascii stl "unknown"))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
144 ([stl solidname]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
145 (str
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
146 "solid "
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
147 solidname
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
148 (s/trim (:header stl))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
149 "\n"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
150 (apply
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
151 str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
152 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
153 facet2str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
154 (:facets stl)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
155 "endsolid "
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
156 solidname
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
157 "\n")))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
158
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
159 (defn write-ascii-stl
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
160 "Write an `stl` structure as read by `decode-binary-stl` to this
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
161 `filename` as ASCII encoded STL."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
162 ([filename stl]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
163 (let [b (fs/base-name filename true)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
164 (write-ascii-stl
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
165 filename stl
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 15 forms covered">
|
||||
166 (subs b 0 (or (s/index-of b ".") (count b))))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
167 ([filename stl solidname]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 16 forms covered">
|
||||
168 (l/debug "Solid name is " solidname)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
169 (spit
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
170 filename
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
171 (stl->ascii stl solidname))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
172
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
173 (defn binary-stl-to-ascii
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
174 "Convert the binary STL file indicated by `in-filename`, and write it to
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
175 `out-filename`, if specified; otherwise, to a file with the same basename
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
176 as `in-filename` but the extension `.ascii.stl`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
177 ([in-filename]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
178 (let [[_ ext] (fs/split-ext in-filename)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
179 (binary-stl-to-ascii
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
180 in-filename
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
181 (str
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
182 (subs
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
183 in-filename
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
184 0
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
185 (or
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
186 (s/last-index-of in-filename ".")
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
187 (count in-filename)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
188 ".ascii"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
189 ext))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
190 ([in-filename out-filename]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
191 (write-ascii-stl out-filename (decode-binary-stl in-filename))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -28,203 +28,236 @@
|
|||
<span class="blank" title="0 out of 0 forms covered">
|
||||
008
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
009 (defn index-vertex
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 ;; TODO: Think about reification/dereification. How can we cull a polygon, if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 "Return a superstructure like `s` in which object `o` is indexed by vertex
|
||||
010 ;; some vertices still index it? I *think* that what's needed is that when
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 `v`. It is an error (and an exception may be thrown) if
|
||||
011 ;; we store something in the superstructure, we replace all its vertices (and
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 ;; other dependent structures, if any with their ids - as well as, obviously,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 ;; adding/merging those vertices/dependent structures into the superstructure
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 ;; as first class objects in themselves. That means, for each identified thing,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 ;; the superstructure only contains one copy of it.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 ;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 ;; The question then is, when we want to do things with those objects, do we
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 ;; exteract a copy with its dependent structures fixed back up (reification),
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 ;; or do we indirect through the superstructure every time we want to access
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 ;; them? In a sense, the copy in the superstructure is the 'one true copy',
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ;; but it may become very difficult then to have one true copy of the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 ;; superstructure - unless we replace the superstructure altogether with a
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ;; database, which may be the Right Thing To Do.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
012
|
||||
024
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
025 (defn index-vertex
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 1. `s` is not a map;
|
||||
026 "Return a superstructure like `s` in which object `o` is indexed by vertex
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 2. `o` is not a map;
|
||||
027 `v`. It is an error (and an exception may be thrown) if
|
||||
</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">
|
||||
015 3. `o` does not have a value for the key `:id`;
|
||||
029 1. `s` is not a map;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 4. `v` is not a vertex."
|
||||
030 2. `o` is not a map;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 ;; two copies of the same vertex are not identical enough to one another
|
||||
031 3. `o` does not have a value for the key `:id`;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 ;; to be used as keys in a map. So our vertices need to have ids, and we need
|
||||
032 4. `v` is not a vertex."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 ;; to key the vertex-index by vertex ids.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 ;; TODO: BUT WE CANNOT USE GENSYMED ids, because two vertices with the same
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ;; vertices must have the same id!
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 [s o v]
|
||||
033 [s o v]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
023 (if-not (v/vertex? o)
|
||||
034 (if-not (v/vertex? o)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
024 (if (:id o)
|
||||
035 (if (:id o)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
025 (if (v/vertex? v)
|
||||
036 (if (v/vertex? v)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
026 (let [vi (or (:vertex-index s) {})
|
||||
037 (let [vi (or (:vertex-index s) {})
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
027 current (or (vi (:id v)) {})]
|
||||
038 current (or (vi (:id v)) {})]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
028 ;; deep-merge doesn't merge sets, only maps; so at this
|
||||
039 ;; deep-merge doesn't merge sets, only maps; so at this
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 ;; stage we need to build a map.
|
||||
040 ;; stage we need to build a map.
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 15 forms covered">
|
||||
030 (assoc vi (:id v) (assoc current (:id o) (:id v))))
|
||||
041 (assoc vi (:id v) (assoc current (:id o) (:id v))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
031 (throw (IllegalArgumentException. "Not a vertex: " v)))
|
||||
042 (throw (IllegalArgumentException. "Not a vertex: " v)))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
032 (throw (IllegalArgumentException. (subs (str "No `:id` value: " o) 0 80))))
|
||||
043 (throw (IllegalArgumentException. (subs (str "No `:id` value: " o) 0 80))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
033 ;; it shouldn't actually be an error to try to index a vertex, but it
|
||||
044 ;; it shouldn't actually be an error to try to index a vertex, but it
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
034 ;; also isn't useful to do so, so I'd be inclined to ignore it.
|
||||
045 ;; also isn't useful to do so, so I'd be inclined to ignore it.
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
035 (:vertex-index s)))
|
||||
046 (:vertex-index s)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
036
|
||||
047
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
037 (defn index-vertices
|
||||
048 (defn index-vertices
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 "Return a superstructure like `s` in which object `o` is indexed by its
|
||||
049 "Return a superstructure like `s` in which object `o` is indexed by its
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
039 vertices. It is an error (and an exception may be thrown) if
|
||||
050 vertices. It is an error (and an exception may be thrown) if
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
040
|
||||
051
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
041 1. `s` is not a map;
|
||||
052 1. `s` is not a map;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 2. `o` is not a map;
|
||||
053 2. `o` is not a map;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 3. `o` does not have a value for the key `:id`."
|
||||
054 3. `o` does not have a value for the key `:id`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
044 [s o]
|
||||
055 [s o]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
045 (assoc
|
||||
056 (assoc
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
046 s
|
||||
057 s
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
047 :vertex-index
|
||||
058 :vertex-index
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
048 (reduce
|
||||
059 (reduce
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
049 u/deep-merge
|
||||
060 u/deep-merge
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
050 (map
|
||||
061 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
051 #(index-vertex s o %)
|
||||
062 #(index-vertex s o %)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
052 (u/vertices o)))))
|
||||
063 (u/vertices o)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
053
|
||||
064
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
054 (defn add-to-superstructure
|
||||
065 (defn add-to-superstructure
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
055 "Return a superstructure like `s` with object `o` added. If `o` is a collection,
|
||||
066 "Return a superstructure like `s` with object `o` added. If `o` is a collection,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
056 return a superstructure like `s` with each element of `o` added. If only one
|
||||
067 return a superstructure like `s` with each element of `o` added. If only one
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
057 argument is supplied it will be assumed to represent `o` and a new
|
||||
068 argument is supplied it will be assumed to represent `o` and a new
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
058 superstructure will be returned.
|
||||
069 superstructure will be returned.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
059
|
||||
070
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 It is an error (and an exception may be thrown) if
|
||||
071 It is an error (and an exception may be thrown) if
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
061
|
||||
072
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 1. `s` is not a map;
|
||||
073 1. `s` is not a map;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
063 2. `o` is not a map, or a sequence of maps."
|
||||
074 2. `o` is not a map, or a sequence of maps."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 ([o]
|
||||
075 ([o]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
065 (add-to-superstructure {} o))
|
||||
076 (add-to-superstructure {} o))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
066 ([s o]
|
||||
077 ([s o]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
067 (cond
|
||||
078 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 18 forms covered">
|
||||
068 (map? o) (let [o' (if (:id o) o (assoc o :id (keyword (gensym "obj"))))]
|
||||
079 (map? o) (let [o' (if (:id o) o (assoc o :id (keyword (gensym "obj"))))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
069 (index-vertices (assoc s (:id o') o') o'))
|
||||
080 (index-vertices (assoc s (:id o') o') o'))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 14 forms covered">
|
||||
070 (coll? o) (reduce u/deep-merge (map #(add-to-superstructure s %) o))
|
||||
081 (coll? o) (reduce u/deep-merge (map #(add-to-superstructure s %) o))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
071 (nil? o) o
|
||||
082 (nil? o) o
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
072 :else
|
||||
083 :else
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
073 (throw (IllegalArgumentException. (str "Don't know how to index " (or (type o) "nil")))))))
|
||||
084 (throw (IllegalArgumentException. (str "Don't know how to index " (or (type o) "nil")))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
074
|
||||
085
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
028 "Return an object like this `object` but with these `tags` added to its tags,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 if they are not already present.It is an error (and an exception will be
|
||||
029 if they are not already present. It is an error (and an exception will be
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 thrown) if
|
||||
|
|
|
@ -11,76 +11,67 @@
|
|||
002 "Miscellaneous utility functions."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 (:require [walkmap.path :as p]
|
||||
003 (:require [clojure.math.numeric-tower :as m]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 [walkmap.polygon :as q]
|
||||
004 [walkmap.path :as p]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 [walkmap.vertex :as v]))
|
||||
005 [walkmap.polygon :as q]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 [walkmap.vertex :as v]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
006
|
||||
007
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
007 (defn deep-merge
|
||||
008 (defn deep-merge
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 "Recursively merges maps. If vals are not maps, the last value wins."
|
||||
009 "Recursively merges maps. If vals are not maps, the last value wins."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 ;; TODO: not my implementation, not sure I entirely trust it.
|
||||
010 ;; TODO: not my implementation, not sure I entirely trust it.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 [& vals]
|
||||
011 [& vals]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
011 (if (every? map? vals)
|
||||
012 (if (every? map? vals)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
012 (apply merge-with deep-merge vals)
|
||||
013 (apply merge-with deep-merge vals)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
013 (last vals)))
|
||||
014 (last vals)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
014
|
||||
015
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
015 (defn vertices
|
||||
016 (defn vertices
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 "If `o` is an object with vertices, return those vertices, else nil."
|
||||
017 "If `o` is an object with vertices, return those vertices, else nil."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 ;; TODO: it's possibly a design mistake that I'm currently distinguishing
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 ;; between polygons and paths on the basis that one has `:vertices` and
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 ;; the other has `:nodes`. Possibly it would be better to have a key
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 ;; `:closed` which was `true` for polygons, `false` (or missing) for
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ;; paths.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 [o]
|
||||
018 [o]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
023 (cond
|
||||
019 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
024 (v/vertex? o) (list o)
|
||||
020 (v/vertex? o) (list o)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
025 (q/polygon? o) (:vertices o)
|
||||
021 (q/polygon? o) (:vertices o)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
026 (p/path? o) (:nodes o)))
|
||||
022 (p/path? o) (:vertices o)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
023
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -17,238 +17,334 @@
|
|||
004 Note that there's no `distance` function here; to find the distance between
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 two vertices, create an edge from them and use `walkmap.edge/length`.")
|
||||
005 two vertices, create an edge from them and use `walkmap.edge/length`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 (:require [clojure.math.numeric-tower :as m]
|
||||
</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 [walkmap.geometry :refer [=ish]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
006
|
||||
009
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
007 (defn vertex-key
|
||||
010 (defn vertex-key
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 "Making sure we get the same key everytime we key a vertex with the same
|
||||
011 "Making sure we get the same key everytime we key a vertex with the same
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 coordinates. `o` must have numeric values for `:x`, `:y`, and optionally
|
||||
012 coordinates. `o` must have numeric values for `:x`, `:y`, and optionally
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 `:z`."
|
||||
013 `:z`; it is an error and an exception will be thrown if `o` does not
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 [o]
|
||||
014 conform to this specification.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
015
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 **Note:** these keys can be quite long. No apology is made: it is required
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 that the same key can *never* refer to two different locations in space."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 [o]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
019 (keyword
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
020 (s/replace
|
||||
</span><br/>
|
||||
<span class="partial" title="2 out of 3 forms covered">
|
||||
012 (cond
|
||||
021 (cond
|
||||
</span><br/>
|
||||
<span class="partial" title="32 out of 34 forms covered">
|
||||
013 (and (:x o) (:y o) (:z o)) (keyword (str "vert{" (:x o) "|" (:y o) "|" (:z o) "}"))
|
||||
</span><br/>
|
||||
<span class="partial" title="22 out of 23 forms covered">
|
||||
014 (and (:x o) (:y o)) (keyword (str "vert{" (:x o) "|" (:y o) "}"))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
015 :else (throw (IllegalArgumentException. "Not a vertex."))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
016
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
017 (defn vertex?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 "True if `o` satisfies the conditions for a vertex. That is, essentially,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 that it must rerpresent a two- or three- dimensional vector. A vertex is
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 shall be a map having at least the keys `:x` and `:y`, where the value of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 those keys is a number. If the key `:z` is also present, its value must also
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 be a number.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
023
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 The name `vector?` was not used as that would clash with a function of that
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 name in `clojure.core` whose semantics are entirely different."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 [o]
|
||||
</span><br/>
|
||||
<span class="partial" title="23 out of 26 forms covered">
|
||||
027 (and
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
028 (map? o)
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
029 (:id o)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
030 (number? (:x o))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
031 (number? (:y o))
|
||||
<span class="partial" title="15 out of 17 forms covered">
|
||||
022 (and (:x o) (:y o) (:z o))
|
||||
</span><br/>
|
||||
<span class="covered" title="14 out of 14 forms covered">
|
||||
032 (or (nil? (:z o)) (number? (:z o)))
|
||||
023 (str "vert_" (:x o) "_" (:y o) "_" (:z o))
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
033 (or (nil? (:kind o)) (= (:kind o) :vertex))))
|
||||
<span class="partial" title="9 out of 10 forms covered">
|
||||
024 (and (:x o) (:y o))
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
025 (str "vert_" (:x o) "_" (:y o))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 :else
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
027 (throw (IllegalArgumentException.
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
028 (subs (str "Not a vertex: " (or o "nil")) 0 80))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 "."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 "-")))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
034
|
||||
031
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
035 (defn vertex
|
||||
032 (defn vertex?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 "Make a vertex with this `x`, `y` and (if provided) `z` values. Returns a map
|
||||
033 "True if `o` satisfies the conditions for a vertex. That is, essentially,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 with those values, plus a unique `:id` value, and `:kind` set to `:vertex`.
|
||||
034 that it must rerpresent a two- or three- dimensional vector. A vertex is
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 It's not necessary to use this function to create a vertex, but the `:id`
|
||||
035 shall be a map having at least the keys `:x` and `:y`, where the value of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
039 must be present and must be unique."
|
||||
036 those keys is a number. If the key `:z` is also present, its value must also
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
040 ([x y]
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
041 (let [v {:x x :y y :kind :vertex}]
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
042 (assoc v :id (vertex-key v))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 ([x y z]
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
044 (assoc (vertex x y) :z z)))
|
||||
037 be a number.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
045
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
046 (defn canonicalise
|
||||
038
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
047 "If `o` is a map with numeric values for `:x`, `:y` and optionally `:z`,
|
||||
039 The name `vector?` was not used as that would clash with a function of that
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
048 upgrade it to something we will recognise as a vertex."
|
||||
040 name in `clojure.core` whose semantics are entirely different."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
049 [o]
|
||||
041 [o]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
050 (if
|
||||
</span><br/>
|
||||
<span class="partial" title="13 out of 17 forms covered">
|
||||
051 (and
|
||||
<span class="partial" title="23 out of 26 forms covered">
|
||||
042 (and
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
052 (map? o)
|
||||
043 (map? o)
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
044 (:id o)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
053 (number? (:x o))
|
||||
045 (number? (:x o))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
054 (number? (:y o))
|
||||
046 (number? (:y o))
|
||||
</span><br/>
|
||||
<span class="covered" title="14 out of 14 forms covered">
|
||||
047 (or (nil? (:z o)) (number? (:z o)))
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
055 (or (nil? (:z o)) (number? (:z o))))
|
||||
048 (or (nil? (:kind o)) (= (:kind o) :vertex))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
049
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
050 (defn vertex=
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
051 "True if vertices `v1`, `v2` represent the same vertex."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
052 [v1 v2]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
053 (every?
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
054 #(=ish (% v1) (% v2))
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
055 [:x :y :z]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
056
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
057 (defn vertex
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
058 "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">
|
||||
059 with those values, plus a unique `:id` value, and `:kind` set to `:vertex`.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 It's not necessary to use this function to create a vertex, but the `:id`
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
061 must be present and must be unique."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 ([x y]
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
063 (let [v {:x x :y y :kind :vertex}]
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
064 (assoc v :id (vertex-key v))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
065 ([x y z]
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
056 (assoc o :kind :vertex :id (vertex-key o))
|
||||
066 (let [v (assoc (vertex x y) :z z)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
057 (throw (IllegalArgumentException. "Not a proto-vertex: must have numeric `:x` and `:y`."))))
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
067 (assoc v :id (vertex-key v)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
058
|
||||
068
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
059 (def ensure3d
|
||||
069 (defn canonicalise
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 "Given a vertex `o`, if `o` has a `:z` value, just return `o`; otherwise
|
||||
070 "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">
|
||||
061 return a vertex like `o` but having thie `dflt` value as the value of its
|
||||
071 upgrade it to something we will recognise as a vertex."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 `: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">
|
||||
063
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 If `o` is not a vertex, throws an exception."
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
065 (memoize
|
||||
072 [o]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
066 (fn
|
||||
073 (if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
067 ([o]
|
||||
<span class="partial" title="13 out of 17 forms covered">
|
||||
074 (and
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
068 (ensure3d o 0.0))
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
075 (map? o)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
069 ([o dflt]
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
076 (number? (:x o))
|
||||
</span><br/>
|
||||
<span class="partial" title="2 out of 3 forms covered">
|
||||
070 (cond
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
077 (number? (:y o))
|
||||
</span><br/>
|
||||
<span class="partial" title="5 out of 8 forms covered">
|
||||
071 (not (vertex? o)) (throw (IllegalArgumentException. "Not a vertex!"))
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
078 (or (nil? (:z o)) (number? (:z o))))
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
072 (:z o) o
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
073 :else (assoc o :z dflt))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
074
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
075 (def ensure2d
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
076 "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">
|
||||
077 (memoize
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
078 (fn [o]
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
079 (assoc o :kind :vertex :id (vertex-key o))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
079 (if
|
||||
080 (throw
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
081 (IllegalArgumentException.
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
082 (subs
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
080 (vertex? o)
|
||||
083 (str "Not a proto-vertex: must have numeric `:x` and `:y`: "
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
081 (assoc o :z 0.0)
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
084 (or o "nil"))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
082 (throw (IllegalArgumentException. "Not a vertex!"))))))
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
085 0 80)))))
|
||||
</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 (def ensure3d
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
088 "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">
|
||||
089 return a vertex like `o` but having thie `dflt` value as the value of its
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
090 `: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">
|
||||
091
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
092 If `o` is not a vertex, throws an exception."
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
093 (memoize
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
094 (fn
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
095 ([o]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
096 (ensure3d o 0.0))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
097 ([o dflt]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
098 (cond
|
||||
</span><br/>
|
||||
<span class="partial" title="5 out of 6 forms covered">
|
||||
099 (not (vertex? o)) (throw
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
100 (IllegalArgumentException.
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
101 (subs (str "Not a vertex: " (or o "nil")) 0 80)))
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
102 (:z o) o
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
103 :else (assoc o :z dflt))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
104
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
105 (def ensure2d
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
106 "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">
|
||||
107 (memoize
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
108 (fn [o]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
109 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
110 (vertex? o)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
111 (assoc o :z 0.0)
|
||||
</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 13 forms covered">
|
||||
114 (subs (str "Not a vertex: " (or o "nil")) 0 80)))))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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="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><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-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#L9">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>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -5,15 +5,15 @@
|
|||
<ol>
|
||||
<li><code>s</code> is not a map;</li>
|
||||
<li><code>o</code> is not a map, or a sequence of maps.</li>
|
||||
</ol></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/superstructure.clj#L54">view source</a></div></div><div class="public anchor" id="var-index-vertex"><h3>index-vertex</h3><div class="usage"><code>(index-vertex s o v)</code></div><div class="doc"><div class="markdown"><p>Return a superstructure like <code>s</code> in which object <code>o</code> is indexed by vertex <code>v</code>. It is an error (and an exception may be thrown) if</p>
|
||||
</ol></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/superstructure.clj#L65">view source</a></div></div><div class="public anchor" id="var-index-vertex"><h3>index-vertex</h3><div class="usage"><code>(index-vertex s o v)</code></div><div class="doc"><div class="markdown"><p>Return a superstructure like <code>s</code> in which object <code>o</code> is indexed by vertex <code>v</code>. It is an error (and an exception may be thrown) if</p>
|
||||
<ol>
|
||||
<li><code>s</code> is not a map;</li>
|
||||
<li><code>o</code> is not a map;</li>
|
||||
<li><code>o</code> does not have a value for the key <code>:id</code>;</li>
|
||||
<li><code>v</code> is not a vertex.</li>
|
||||
</ol></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/superstructure.clj#L9">view source</a></div></div><div class="public anchor" id="var-index-vertices"><h3>index-vertices</h3><div class="usage"><code>(index-vertices s o)</code></div><div class="doc"><div class="markdown"><p>Return a superstructure like <code>s</code> in which object <code>o</code> is indexed by its vertices. It is an error (and an exception may be thrown) if</p>
|
||||
</ol></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/superstructure.clj#L25">view source</a></div></div><div class="public anchor" id="var-index-vertices"><h3>index-vertices</h3><div class="usage"><code>(index-vertices s o)</code></div><div class="doc"><div class="markdown"><p>Return a superstructure like <code>s</code> in which object <code>o</code> is indexed by its vertices. It is an error (and an exception may be thrown) if</p>
|
||||
<ol>
|
||||
<li><code>s</code> is not a map;</li>
|
||||
<li><code>o</code> is not a map;</li>
|
||||
<li><code>o</code> does not have a value for the key <code>:id</code>.</li>
|
||||
</ol></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/superstructure.clj#L37">view source</a></div></div></div></body></html>
|
||||
</ol></div></div><div class="src-link"><a href="https://github.com/simon-brooke/walkmap/blob/master/src/walkmap/superstructure.clj#L48">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
|
@ -4,7 +4,7 @@
|
|||
nodes."
|
||||
(:require [clojure.math.numeric-tower :as m]
|
||||
[walkmap.polygon :refer [polygon?]]
|
||||
[walkmap.vertex :refer [ensure3d vertex?]]))
|
||||
[walkmap.vertex :refer [ensure2d ensure3d vertex vertex= vertex?]]))
|
||||
|
||||
(defn edge
|
||||
"Return an edge between vertices `v1` and `v2`."
|
||||
|
@ -36,6 +36,16 @@
|
|||
#(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."
|
||||
|
@ -52,12 +62,10 @@
|
|||
|
||||
(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))
|
||||
#(vertex= % (first uvs))
|
||||
(rest uvs))))
|
||||
|
||||
(defn collinear?
|
||||
|
@ -66,5 +74,116 @@
|
|||
(parallel?
|
||||
e1
|
||||
e2
|
||||
{:start (:start e1) :end (:start 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."
|
||||
[e1 e2]
|
||||
(when (and (edge? e1) (edge? e2))
|
||||
(and
|
||||
(> (minimaxd e1 :x max) (minimaxd e2 :x min))
|
||||
(< (minimaxd e1 :x min) (minimaxd e2 :x max))
|
||||
(> (minimaxd e1 :y max) (minimaxd e2 :y min))
|
||||
(< (minimaxd e1 :y min) (minimaxd e2 :y max)))))
|
||||
|
||||
;; Don't think I need this.
|
||||
;; (defn orientation
|
||||
;; "Determine whether the ordered sequence of vertices `p`, `q` and `r` run
|
||||
;; clockwise, collinear or anticlockwise in the x,y plane."
|
||||
;; [p q r]
|
||||
;; (let [v (- (* (- (:y q) (:y p)) (- (:x r) (:x q)))
|
||||
;; (* (- (:x q) (:x p)) (- (:y r) (:y q))))]
|
||||
;; (cond
|
||||
;; (zero? v) :collinear
|
||||
;; (pos? v) :clockwise
|
||||
;; :else
|
||||
;; :anticlockwise)))
|
||||
|
||||
(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]
|
||||
(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 (:x (:start e1))
|
||||
x2 (:x (:end e1))
|
||||
x3 (:x (:start e2))
|
||||
x4 (:x (:end e2))
|
||||
y1 (:y (:start e1))
|
||||
y2 (:y (:end e1))
|
||||
y3 (:y (:start e2))
|
||||
y4 (:y (: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]))))))
|
||||
|
||||
|
|
|
@ -1,24 +1,17 @@
|
|||
(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))))))
|
||||
|
||||
[clojure.math.numeric-tower :as m]))
|
||||
|
||||
(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)."
|
||||
([n1 n2]
|
||||
(if (and (number? n1) (number? n2))
|
||||
(let [m (m/abs (min n1 n2))
|
||||
t (if (zero? m) 0.000001 (* 0.000001 m))]
|
||||
(=ish n1 n2 t))
|
||||
(= n1 n2)))
|
||||
([n1 n2 tolerance]
|
||||
(if (and (number? n1) (number? n2))
|
||||
(< (m/abs (- n1 n2)) tolerance)
|
||||
(= n1 n2))))
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
(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
|
||||
having the key `:vertices`, whose value shall be a sequence of vertices as
|
||||
defined in `walkmap.vertex`."
|
||||
[o]
|
||||
(let
|
||||
[v (:nodes o)]
|
||||
[v (:vertices o)]
|
||||
(and
|
||||
(seq? v)
|
||||
(> (count v) 2)
|
||||
|
@ -25,7 +25,7 @@
|
|||
[& vertices]
|
||||
(if
|
||||
(every? vertex? vertices)
|
||||
{:nodes vertices :id (keyword (gensym "path")) :kind :path}
|
||||
{:vertices vertices :id (keyword (gensym "path")) :kind :path}
|
||||
(throw (IllegalArgumentException. "Each item on path must be a vertex."))))
|
||||
|
||||
(defn polygon->path
|
||||
|
@ -38,7 +38,7 @@
|
|||
[o]
|
||||
(if
|
||||
(polygon? o)
|
||||
(assoc (dissoc o :vertices) :kind :path :nodes (concat (:vertices o) (list (first (:vertices o)))))
|
||||
(assoc (dissoc o :vertices) :kind :path :vertices (concat (:vertices o) (list (first (:vertices o)))))
|
||||
(throw (IllegalArgumentException. "Not a polygon!"))))
|
||||
|
||||
(defn path->edges
|
||||
|
@ -60,7 +60,7 @@
|
|||
(e/edge (first o) (rest o))
|
||||
(path->edges (rest o))))
|
||||
(path? o)
|
||||
(path->edges (:nodes o))
|
||||
(path->edges (:vertices o))
|
||||
:else
|
||||
(throw (IllegalArgumentException.
|
||||
"Not a path or sequence of vertices!"))))
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
(coll? v)
|
||||
(> (count v) 2)
|
||||
(every? vertex? v)
|
||||
(:id o)
|
||||
(or (nil? (:kind o)) (= (:kind o) :polygon)))))
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
[me.raynes.fs :as fs]
|
||||
[org.clojars.smee.binary.core :as b]
|
||||
[taoensso.timbre :as l :refer [info error spy]]
|
||||
[walkmap.edge :as e]
|
||||
[walkmap.polygon :refer [polygon?]]
|
||||
[walkmap.tag :refer [tag]]
|
||||
[walkmap.vertex :as v])
|
||||
(:import org.clojars.smee.binary.core.BinaryIO
|
||||
java.io.DataInput))
|
||||
|
@ -51,35 +53,76 @@
|
|||
:count :uint-le
|
||||
:facets (b/repeated facet)))
|
||||
|
||||
(defn 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 facet)
|
||||
v1 (first vs)
|
||||
opposite (e/edge (nth vs 1) (nth vs 2))
|
||||
oc (e/centre opposite)]
|
||||
(assoc
|
||||
facet
|
||||
:centre
|
||||
(v/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 canonicalise
|
||||
"Objects read in from STL won't have all the keys/values we need them to have."
|
||||
[o]
|
||||
"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 map-kind]
|
||||
(when-not
|
||||
(keyword? map-kind)
|
||||
(throw (IllegalArgumentException.
|
||||
(subs (str "Must be a keyword: " (or map-kind "nil")) 0 80))))
|
||||
(cond
|
||||
(and (coll? o) (not (map? o))) (map canonicalise o)
|
||||
(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
|
||||
:id (or (:id o) (keyword (gensym "stl")))
|
||||
:facets (canonicalise (:facets o)))
|
||||
:facets (canonicalise (:facets o) map-kind))
|
||||
;; if it has :vertices it's a polygon, but it doesn't yet conform to `polygon?`
|
||||
(:vertices o) (assoc o
|
||||
(:vertices o) (centre
|
||||
(tag
|
||||
(assoc o
|
||||
:id (or (:id o) (keyword (gensym "poly")))
|
||||
:kind :polygon
|
||||
:vertices (canonicalise (:vertices o)))
|
||||
:vertices (canonicalise (:vertices o) map-kind))
|
||||
:facet map-kind))
|
||||
;; if it has a value for :x it's a vertex, but it doesn't yet conform to `vertex?`
|
||||
(:x o) (v/canonicalise o)
|
||||
;; shouldn't happen
|
||||
:else o))
|
||||
:else o)))
|
||||
|
||||
(defn decode-binary-stl
|
||||
"Parse a binary STL file from this `filename` and return an STL structure
|
||||
representing its contents.
|
||||
representing its contents. `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.
|
||||
|
||||
**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]
|
||||
([filename]
|
||||
(decode-binary-stl filename :height))
|
||||
([filename map-kind]
|
||||
(when-not
|
||||
(keyword? map-kind)
|
||||
(throw (IllegalArgumentException.
|
||||
(subs (str "Must be a keyword: " (or map-kind "nil")) 0 80))))
|
||||
(let [in (io/input-stream filename)]
|
||||
(canonicalise (b/decode binary-stl in))))
|
||||
(canonicalise (b/decode binary-stl in) map-kind))))
|
||||
|
||||
(defn- vect->str [prefix v]
|
||||
(str prefix " " (:x v) " " (:y v) " " (:z v) "\n"))
|
||||
|
|
|
@ -6,6 +6,22 @@
|
|||
[walkmap.utils :as u]
|
||||
[walkmap.vertex :as v]))
|
||||
|
||||
;; 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.
|
||||
|
||||
(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
|
||||
|
@ -14,11 +30,6 @@
|
|||
2. `o` is not a map;
|
||||
3. `o` does not have a value for the key `:id`;
|
||||
4. `v` is not a vertex."
|
||||
;; two copies of the same vertex are not identical enough to one another
|
||||
;; to be used as keys in a map. So our vertices need to have ids, and we need
|
||||
;; to key the vertex-index by vertex ids.
|
||||
;; TODO: BUT WE CANNOT USE GENSYMED ids, because two vertices with the same
|
||||
;; vertices must have the same id!
|
||||
[s o v]
|
||||
(if-not (v/vertex? o)
|
||||
(if (:id o)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
(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
|
||||
if they are not already present. It is an error (and an exception will be
|
||||
thrown) if
|
||||
|
||||
1. `object` is not a map;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns walkmap.utils
|
||||
"Miscellaneous utility functions."
|
||||
(:require [walkmap.path :as p]
|
||||
(:require [clojure.math.numeric-tower :as m]
|
||||
[walkmap.path :as p]
|
||||
[walkmap.polygon :as q]
|
||||
[walkmap.vertex :as v]))
|
||||
|
||||
|
@ -14,13 +15,9 @@
|
|||
|
||||
(defn vertices
|
||||
"If `o` is an object with vertices, return those vertices, else nil."
|
||||
;; TODO: it's possibly a design mistake that I'm currently distinguishing
|
||||
;; between polygons and paths on the basis that one has `:vertices` and
|
||||
;; the other has `:nodes`. Possibly it would be better to have a key
|
||||
;; `:closed` which was `true` for polygons, `false` (or missing) for
|
||||
;; paths.
|
||||
[o]
|
||||
(cond
|
||||
(v/vertex? o) (list o)
|
||||
(q/polygon? o) (:vertices o)
|
||||
(p/path? o) (:nodes o)))
|
||||
(p/path? o) (:vertices o)))
|
||||
|
||||
|
|
|
@ -2,17 +2,32 @@
|
|||
"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`.")
|
||||
two vertices, create an edge from them and use `walkmap.edge/length`."
|
||||
(:require [clojure.math.numeric-tower :as m]
|
||||
[clojure.string :as s]
|
||||
[walkmap.geometry :refer [=ish]]))
|
||||
|
||||
(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`."
|
||||
`: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)) (keyword (str "vert{" (:x o) "|" (:y o) "|" (:z o) "}"))
|
||||
(and (:x o) (:y o)) (keyword (str "vert{" (:x o) "|" (:y o) "}"))
|
||||
:else (throw (IllegalArgumentException. "Not a vertex."))))
|
||||
(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.
|
||||
(subs (str "Not a vertex: " (or o "nil")) 0 80))))
|
||||
"."
|
||||
"-")))
|
||||
|
||||
(defn vertex?
|
||||
"True if `o` satisfies the conditions for a vertex. That is, essentially,
|
||||
|
@ -32,6 +47,13 @@
|
|||
(or (nil? (:z o)) (number? (:z o)))
|
||||
(or (nil? (:kind o)) (= (:kind o) :vertex))))
|
||||
|
||||
(defn vertex=
|
||||
"True if vertices `v1`, `v2` represent the same vertex."
|
||||
[v1 v2]
|
||||
(every?
|
||||
#(=ish (% v1) (% v2))
|
||||
[:x :y :z]))
|
||||
|
||||
(defn vertex
|
||||
"Make a vertex with this `x`, `y` and (if provided) `z` values. Returns a map
|
||||
with those values, plus a unique `:id` value, and `:kind` set to `:vertex`.
|
||||
|
@ -41,7 +63,8 @@
|
|||
(let [v {:x x :y y :kind :vertex}]
|
||||
(assoc v :id (vertex-key v))))
|
||||
([x y z]
|
||||
(assoc (vertex x y) :z z)))
|
||||
(let [v (assoc (vertex x y) :z z)]
|
||||
(assoc v :id (vertex-key v)))))
|
||||
|
||||
(defn canonicalise
|
||||
"If `o` is a map with numeric values for `:x`, `:y` and optionally `:z`,
|
||||
|
@ -54,7 +77,12 @@
|
|||
(number? (:y o))
|
||||
(or (nil? (:z o)) (number? (:z o))))
|
||||
(assoc o :kind :vertex :id (vertex-key o))
|
||||
(throw (IllegalArgumentException. "Not a proto-vertex: must have numeric `:x` and `:y`."))))
|
||||
(throw
|
||||
(IllegalArgumentException.
|
||||
(subs
|
||||
(str "Not a proto-vertex: must have numeric `:x` and `:y`: "
|
||||
(or o "nil"))
|
||||
0 80)))))
|
||||
|
||||
(def ensure3d
|
||||
"Given a vertex `o`, if `o` has a `:z` value, just return `o`; otherwise
|
||||
|
@ -68,7 +96,9 @@
|
|||
(ensure3d o 0.0))
|
||||
([o dflt]
|
||||
(cond
|
||||
(not (vertex? o)) (throw (IllegalArgumentException. "Not a vertex!"))
|
||||
(not (vertex? o)) (throw
|
||||
(IllegalArgumentException.
|
||||
(subs (str "Not a vertex: " (or o "nil")) 0 80)))
|
||||
(:z o) o
|
||||
:else (assoc o :z dflt))))))
|
||||
|
||||
|
@ -79,4 +109,6 @@
|
|||
(if
|
||||
(vertex? o)
|
||||
(assoc o :z 0.0)
|
||||
(throw (IllegalArgumentException. "Not a vertex!"))))))
|
||||
(throw
|
||||
(IllegalArgumentException.
|
||||
(subs (str "Not a vertex: " (or o "nil")) 0 80)))))))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
(ns walkmap.edge-test
|
||||
(:require [clojure.test :refer :all]
|
||||
(:require [clojure.math.numeric-tower :as m]
|
||||
[clojure.test :refer :all]
|
||||
[walkmap.edge :refer :all]
|
||||
[walkmap.vertex :refer [vertex]]))
|
||||
|
||||
|
@ -19,6 +20,32 @@
|
|||
:end {:x 3 :y 4 :z 0.0 :id 'bar}})) "Value of x in start is not a number")
|
||||
(is (false? (edge? "I am not an edge")) "Edge mustbe a map.")))
|
||||
|
||||
(deftest collinear-test
|
||||
(testing "collinearity"
|
||||
(is (collinear? {:start {:x 0.0 :y 0.0 :z 0.0 :id 'foo} :end {:x 3.0 :y 4.0 :z 0.0 :id 'bar}}
|
||||
{:start {:x 3.0 :y 4.0 :z 0.0 :id 'foo} :end {:x 9.0 :y 12.0 :z 0.0 :id 'bar}})
|
||||
"Should be")
|
||||
(is (not
|
||||
(collinear? {:start {:x 0.0 :y 0.0 :z 0.0 :id 'foo} :end {:x 3 :y 4 :z 0.0 :id 'bar}}
|
||||
{:start {:x 1.0 :y 2.0 :z 3.5 :id 'foo} :end {:x 4.0 :y 6.0 :z 3.5 :id 'bar}}))
|
||||
"Should not be!")
|
||||
(is (collinear? {:start {:x 0.0 :y 0.0 :z 0.0 :id 'foo} :end {:x 3.0 :y 4.0 :z 0.0 :id 'bar}}
|
||||
{:start {:x 0.0 :y 0.0 :z 0.0 :id 'foo} :end {:x 9.0 :y 12.0 :z 0.0 :id 'bar}})
|
||||
"Edge case: same start location")
|
||||
(is (collinear? {:start {:x 0.0 :y 0.0 :z 0.0 :id 'foo} :end {:x 9.0 :y 12.0 :z 0.0 :id 'bar}}
|
||||
{:start {:x 3.0 :y 4.0 :z 0.0 :id 'foo} :end {:x 9.0 :y 12.0 :z 0.0 :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)))
|
||||
|
@ -28,18 +55,46 @@
|
|||
(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 :id 'foo} :end {:x 3.0 :y 4.0 :z 0.0 :id 'bar}}) 5.0))))
|
||||
|
||||
(deftest unit-vector-test
|
||||
(testing "deriving the unit vector"
|
||||
(is (=
|
||||
(unit-vector {:start {:x 0.0 :y 0.0 :z 0.0 :id 'foo} :end {:x 3 :y 4 :z 0.0 :id 'bar}})
|
||||
{:x 0.6, :y 0.8, :z 0.0}))
|
||||
(is (=
|
||||
(unit-vector {:start {:x 1.0 :y 2.0 :z 3.5 :id 'foo} :end {:x 4.0 :y 6.0 :z 3.5 :id 'bar}})
|
||||
{:x 0.6, :y 0.8, :z 0.0}))))
|
||||
(deftest minimad-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"
|
||||
|
@ -51,12 +106,16 @@
|
|||
{:start {:x 1.0 :y 2.0 :z 3.5 :id 'foo} :end {:x 4.0 :y 6.0 :z 3.49 :id 'bar}}))
|
||||
"Should not be!")))
|
||||
|
||||
(deftest collinear-test
|
||||
(testing "collinearity"
|
||||
(is (collinear? {:start {:x 0.0 :y 0.0 :z 0.0 :id 'foo} :end {:x 3.0 :y 4.0 :z 0.0 :id 'bar}}
|
||||
{:start {:x 3.0 :y 4.0 :z 0.0 :id 'foo} :end {:x 9.0 :y 12.0 :z 0.0 :id 'bar}})
|
||||
"Should be")
|
||||
(is (not
|
||||
(collinear? {:start {:x 0.0 :y 0.0 :z 0.0 :id 'foo} :end {:x 3 :y 4 :z 0.0 :id 'bar}}
|
||||
{:start {:x 1.0 :y 2.0 :z 3.5 :id 'foo} :end {:x 4.0 :y 6.0 :z 3.5 :id 'bar}}))
|
||||
"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 (=
|
||||
(unit-vector {:start {:x 0.0 :y 0.0 :z 0.0 :id 'foo} :end {:x 3 :y 4 :z 0.0 :id 'bar}})
|
||||
{:x 0.6, :y 0.8, :z 0.0}))
|
||||
(is (=
|
||||
(unit-vector {:start {:x 1.0 :y 2.0 :z 3.5 :id 'foo} :end {:x 4.0 :y 6.0 :z 3.5 :id 'bar}})
|
||||
{:x 0.6, :y 0.8, :z 0.0}))))
|
||||
|
|
14
test/walkmap/geometry_test.clj
Normal file
14
test/walkmap/geometry_test.clj
Normal file
|
@ -0,0 +1,14 @@
|
|||
(ns walkmap.geometry-test
|
||||
(:require [clojure.test :refer :all]
|
||||
[walkmap.geometry :refer :all]))
|
||||
|
||||
(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 (=ish "hello" "goodbye" 10000) "Well, except non-numbers, of course.")))
|
Loading…
Reference in a new issue