Collinearity problem dealt with, some unit tests written.
This commit is contained in:
parent
f92e17c5e8
commit
b6e618695e
15 changed files with 1620 additions and 58 deletions
|
|
@ -2,9 +2,10 @@
|
|||
"Essentially the specification for things we shall consider to be an edge.
|
||||
An edge is a line segment having just a start and an end, with no intervening
|
||||
nodes."
|
||||
(:require [walkmap.path :refer [path? polygon->path]]
|
||||
(:require [clojure.math.numeric-tower :as m]
|
||||
[walkmap.path :refer [path? polygon->path]]
|
||||
[walkmap.polygon :refer [polygon?]]
|
||||
[walkmap.vertex :refer [vertex?]]))
|
||||
[walkmap.vertex :refer [ensure3d vertex?]]))
|
||||
|
||||
(defn edge?
|
||||
"True if `o` satisfies the conditions for a path. A path shall be a map
|
||||
|
|
@ -35,3 +36,47 @@
|
|||
(polygon? o)
|
||||
(path->edges (polygon->path o))))
|
||||
|
||||
(defn length
|
||||
"Return the length of the edge `e`."
|
||||
[e]
|
||||
(let [start (ensure3d (:start e))
|
||||
end (ensure3d (:end e))]
|
||||
(m/sqrt
|
||||
(reduce
|
||||
+
|
||||
(map
|
||||
#(m/expt (- (% end) (% start)) 2)
|
||||
[:x :y :z])))))
|
||||
|
||||
(defn unit-vector
|
||||
"Return an vertex parallel to `e` starting from the coordinate origin. Two
|
||||
edges which are parallel will have the same unit vector."
|
||||
[e]
|
||||
(let [e' {:start (ensure3d (:start e)) :end (ensure3d (:end e))}
|
||||
l (length e')]
|
||||
(reduce
|
||||
merge
|
||||
{}
|
||||
(map
|
||||
(fn [k]
|
||||
{k (/ (- (k (:end e')) (k (:start e'))) l)})
|
||||
[:x :y :z]))))
|
||||
|
||||
(defn parallel?
|
||||
"True if all `edges` passed are parallel with one another."
|
||||
;; TODO: this bears being wary about, dealing with floating point arithmetic.
|
||||
;; Keep an eye out for spurious errors.
|
||||
[& edges]
|
||||
(let [uvs (map unit-vector edges)]
|
||||
(every?
|
||||
#(= % (first uvs))
|
||||
(rest uvs))))
|
||||
|
||||
(defn collinear?
|
||||
"True if edges `e1` and `e2` are collinear with one another."
|
||||
[e1 e2]
|
||||
(parallel?
|
||||
e1
|
||||
e2
|
||||
{:start (:start e1) :end (:start e2)}))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,52 +1,19 @@
|
|||
(ns walkmap.geometry
|
||||
(:require [clojure.math.combinatorics :as combo]
|
||||
[clojure.math.numeric-tower :as m]
|
||||
[walkmap.edge :as edge]
|
||||
[walkmap.edge :as e]
|
||||
[walkmap.path :refer [path? polygon->path]]
|
||||
[walkmap.polygon :refer [polygon?]]
|
||||
[walkmap.vertex :as vertex]))
|
||||
|
||||
(defn collinear?
|
||||
"True if these vertices `v1`, `v2`, `v3` are colinear; false otherwise."
|
||||
;; This is failing...
|
||||
;; see http://www.ambrsoft.com/TrigoCalc/Line3D/LineColinear.htm
|
||||
[v1 v2 v3]
|
||||
(let [a (m/sqrt (+ (- (:x v2) (:x v1)) (- (:y v2) (:y v1)) (- (:z v2) (:z v1))))
|
||||
b (m/sqrt (+ (- (:x v3) (:x v1)) (- (:y v3) (:y v1)) (- (:z v3) (:z v1))))
|
||||
c (m/sqrt (+ (- (:x v3) (:x v2)) (- (:y v3) (:y v2)) (- (:z v3) (:z v2))))]
|
||||
(not
|
||||
(and
|
||||
(> (+ a b) c)
|
||||
(> (+ a c) b)
|
||||
(> (+ b c) a)))))
|
||||
|
||||
;; (collinear? {:x 0 :y 0 :z 0} {:x 1 :y 1 :z 1} {:x 7 :y 7 :z 7})
|
||||
;; (collinear? {:x 0 :y 0 :z 0} {:x 1 :y 2 :z 1} {:x 7 :y 7 :z 7})
|
||||
;; (collinear? {:x 0 :y 0 :z 0} {:x 0 :y 2 :z 0} {:x 0 :y 3 :z 0})
|
||||
|
||||
;; (def v1 {:x 0 :y 0 :z 0})
|
||||
;; (def v2 {:x 0 :y 2 :z 0})
|
||||
;; (def v3 {:x 0 :y 7 :z 0})
|
||||
|
||||
;; (def a (m/sqrt (+ (- (:x v2) (:x v1)) (- (:y v2) (:y v1)) (- (:z v2) (:z v1)))))
|
||||
;; a
|
||||
;; (def b (m/sqrt (+ (- (:x v3) (:x v1)) (- (:y v3) (:y v1)) (- (:z v3) (:z v1)))))
|
||||
;; b
|
||||
;; (def c (m/sqrt (+ (- (:x v3) (:x v2)) (- (:y v3) (:y v2)) (- (:z v3) (:z v2)))))
|
||||
;; c
|
||||
|
||||
;; (> (+ b c) a)
|
||||
;; (> (+ a c) b)
|
||||
;; (> (+ a c) c)
|
||||
[walkmap.vertex :as v]))
|
||||
|
||||
(defn on?
|
||||
"True if the vertex `v` is on the edge `e`."
|
||||
[e v]
|
||||
(let [p (vertex/ensure3d (:start e))
|
||||
q (vertex/ensure3d v)
|
||||
r (vertex/ensure3d (:end e))]
|
||||
(let [p (v/ensure3d (:start e))
|
||||
q (v/ensure3d v)
|
||||
r (v/ensure3d (:end e))]
|
||||
(and
|
||||
(collinear? p q r)
|
||||
(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)))
|
||||
|
|
|
|||
|
|
@ -17,24 +17,27 @@
|
|||
(number? (:y o))
|
||||
(or (nil? (:z o)) (number? (:z o)))))
|
||||
|
||||
(defn ensure3d
|
||||
(def ensure3d
|
||||
"Given a vertex `o`, if `o` has a `:z` value, just return `o`; otherwise
|
||||
return a vertex like `o` but having thie `dflt` value as the value of its
|
||||
`:z` key, or zero as the value of its `:z` key if `dflt` is not specified.
|
||||
|
||||
If `o` is not a vertex, throws an exception."
|
||||
([o]
|
||||
(ensure3d o 0.0))
|
||||
([o dflt]
|
||||
(cond
|
||||
(not (vertex? o)) (throw (Exception. "Not a vertex!"))
|
||||
(:z o) o
|
||||
:else (assoc o :z dflt))))
|
||||
(memoize
|
||||
(fn
|
||||
([o]
|
||||
(ensure3d o 0.0))
|
||||
([o dflt]
|
||||
(cond
|
||||
(not (vertex? o)) (throw (Exception. "Not a vertex!"))
|
||||
(:z o) o
|
||||
:else (assoc o :z dflt))))))
|
||||
|
||||
(defn ensure2d
|
||||
(def ensure2d
|
||||
"If `o` is a vertex, set its `:z` value to zero; else throw an exception."
|
||||
[o]
|
||||
(if
|
||||
(vertex? o)
|
||||
(assoc o :z 0.0)
|
||||
(throw (Exception. "Not a vertex!"))))
|
||||
(memoize
|
||||
(fn [o]
|
||||
(if
|
||||
(vertex? o)
|
||||
(assoc o :z 0.0)
|
||||
(throw (Exception. "Not a vertex!"))))))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue