Longitude is close. Latitude is way out. Progress.

This commit is contained in:
Simon Brooke 2018-06-28 11:39:33 +01:00
parent d8f28ef3cc
commit fd886daa49
4 changed files with 304 additions and 236 deletions

2
.gitignore vendored
View file

@ -17,3 +17,5 @@ pom.xml.asc
\.idea/ \.idea/
yyy-data\.iml yyy-data\.iml
resources/js/

View file

@ -8,6 +8,8 @@
[org.clojure/clojure "1.8.0"] [org.clojure/clojure "1.8.0"]
[org.clojure/data.json "0.2.6"] [org.clojure/data.json "0.2.6"]
[org.clojure/math.numeric-tower "0.0.4"] [org.clojure/math.numeric-tower "0.0.4"]
[lein-light-nrepl "0.0.4"]
[net.mikera/core.matrix "0.62.0"]] [net.mikera/core.matrix "0.62.0"]]
:plugins [[lein-gorilla "0.4.0"]] :plugins [[lein-gorilla "0.4.0"]]
:repl-options {:nrepl-middleware [lighttable.nrepl.handler/lighttable-ops]}
) )

View file

@ -30,7 +30,9 @@
;;;; ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; There are a number of bad design decisions in my implementation of this. ;;; Coordinate system conversion cribbed from https://www.movable-type.co.uk/scripts/latlong-os-gridref.html
;;; There are a number of bad design decisions in my re-implementation of this.
;;; Using protocols and records was probably a mistake. ;;; Using protocols and records was probably a mistake.
;;; ;;;
;;; The decision not only to adopt but to extend the untypable variable names ;;; The decision not only to adopt but to extend the untypable variable names
@ -95,8 +97,7 @@
(latitude [location]) (latitude [location])
(longitude [location]) (longitude [location])
(osgrid [location datum]) (osgrid [location datum])
(vector3d [location]) (vector3d [location]))
)
(defprotocol Transformable (defprotocol Transformable
@ -119,26 +120,29 @@
(apply-transform [this transform] (apply-transform [this transform]
(println (str "(apply-transform " this " " transform ")")) (println (str "(apply-transform " this " " transform ")"))
(let (let
[s1 (+ (/ (:s transform) 1e6) 1) ;; scale [s1 (+' (/ (:s transform) 1e6) 1) ;; scale
rx (radians (/ (:rx transform) 3600)) ;; x-rotation: normalise arcseconds to radians rx (radians (/ (:rx transform) 3600)) ;; x-rotation: normalise arcseconds to radians
ry (radians (/ (:ry transform) 3600)) ;; y-rotation: normalise arcseconds to radians ry (radians (/ (:ry transform) 3600)) ;; y-rotation: normalise arcseconds to radians
rz (radians (/ (:rz transform) 3600)) ;; z-rotation: normalise arcseconds to radians rz (radians (/ (:rz transform) 3600)) ;; z-rotation: normalise arcseconds to radians
x2 (- ;; var x2 = tx + x1*s1 - y1*rz + z1*ry;
(+ (:tx transform) x2 (-'
(* (.x this) s1)) (+' (:tx transform)
(+ (*' (:x this) s1))
(* (.y this) rz) (+'
(* (.z this) ry))) (*' (:y this) rz)
y2 (+ (*' (:z this) ry)))
;; var y2 = ty + x1*rz + y1*s1 - z1*rx;
y2 (+'
(:ty transform) (:ty transform)
(* (.x this) rz) (*' (:x this) rz)
(* (.y this) s1) (*' (:y this) s1)
(- 0 (* (.z this) rx))) (-' 0 (*' (:z this) rx)))
z2 (+ ;; var z2 = tz - x1*ry + y1*rx + z1*s1;
(.z this) z2 (+'
(- 0 (* (.x this) ry)) (:tz transform)
(* (.y this) rx) (-' 0 (*' (:x this) ry))
(* (.z this) s1))] (*' (:y this) rx)
(*' (:z this) s1))]
(Vector3d. x2 y2 z2)))) (Vector3d. x2 y2 z2))))
@ -152,7 +156,7 @@
merge merge
{} {}
(map (map
#(if (number? (t %)) (hash-map % (- 0 (t %)))) ;; (hash-map % (t %))) #(if (number? (t %)) (hash-map % (-' 0 (t %)))) ;; (hash-map % (t %)))
(keys t)))) (keys t))))
@ -163,7 +167,7 @@
"Round the number `n` to `p` places after the decimal point." "Round the number `n` to `p` places after the decimal point."
[n p] [n p]
(let [m (reduce *' 1 (repeat p 10))] (let [m (reduce *' 1 (repeat p 10))]
(double (/ (int (*' n m)) m)))) (double (/ (bigint (*' n m)) m))))
;; (to-fixed 1234.56789 4) ;; (to-fixed 1234.56789 4)
@ -196,10 +200,10 @@
location location
(let [od (datum location) (let [od (datum location)
nd (datums new-datum) nd (datums new-datum)
c (vector3d location)] c (geopoint-to-vector3d location)]
(cond (cond
(= od nd) location (= od nd) location
(= (:key od) :WGS84) (geopoint (= (:key od) :WGS84) (vector3d-to-geopoint
(apply-transform c (:transform nd)) (apply-transform c (:transform nd))
(:datum location)) (:datum location))
(= (:key nd) :WGS84) (geopoint (= (:key nd) :WGS84) (geopoint
@ -239,45 +243,54 @@
(osgrid [location datum] location)) (osgrid [location datum] location))
(defn vector3d-to-geopoint (defn raw-vector3d-to-geopoint
;; My initial design decision to allow datums to be passed as keywords or as maps ;; My initial design decision to allow datums to be passed as keywords or as maps
;; was WRONG: a datum SHALL BE passed as a map ;; was WRONG: a datum SHALL BE passed as a key
[this datum] ([v datum]
(vector3d-to-geopoint (:x v) (:y v) (:z v) datum))
([x y z d]
(let (let
[a (:a (:ellipsoid (datums datum))) [a (:a (:ellipsoid (datums d)))
b (:b (:ellipsoid (datums datum))) b (:b (:ellipsoid (datums d)))
f (:f (:ellipsoid (datums datum))) f (:f (:ellipsoid (datums d)))
e² (- (* 2 f) (* f f)) ;; first eccentricity squared e² (-' (*' 2 f) (*' f f)) ;; first eccentricity squared
ε² (/ e² (- 1 e²)) ;; second eccentricity squared ε² (/ e² (-' 1 e²)) ;; second eccentricity squared
p (sqrt (+ (* (.x this) (.x this)) (* (.y this) (.y this)))) p (sqrt (+' (*' x x) (*' y y)))
;; distance from minor radius ;; distance from minor radius
R (sqrt (+ (* p p) (* (:z this) (:z this)))) R (sqrt (+' (*' p p) (*' z z)))
;; polar radius ;; polar radius
tanβ (* (/ (* b (:z this))(* a p)) (/ (* b (+ 1 ε²)) R)) tanβ (*' (/ (*' b z)(*' a p)) (/ (*' b (+' 1 ε²)) R))
sinβ (/ tanβ (sqrt (+ 1 (* tanβ tanβ)))) sinβ (/ tanβ (sqrt (+' 1 (*' tanβ tanβ))))
cosβ (/ sinβ tanβ) cosβ (/ sinβ tanβ)
φ (if φ (if
(Double/isNaN cosβ) 0 (Double/isNaN cosβ) 0
(atan2 (+ (.z this) (* ε² b sinβ sinβ sinβ)) (atan2 (+' z (*' ε² b sinβ sinβ sinβ))
(- p (* e² a cosβ cosβ cosβ)))) (-' p (*' e² a cosβ cosβ cosβ))))
λ (atan2 (:y this) (:x this)) λ (atan2 y x)
v (/ a (sqrt (- 1 (* e² (sin φ) (sin φ)))))] v (/ a (sqrt (-' 1 (*' e² (sin φ) (sin φ)))))]
(GeoPoint. (degrees φ) (degrees λ) datum))) (GeoPoint. (degrees φ) (degrees λ) d))))
(defn geopoint-to-osgrid ;; memoisation here is used more to break mutual recursion than to speed things
[gp datum] ;; up, although of course it will also speed things up a bit.
(def vector3d-to-geopoint (memoize raw-vector3d-to-geopoint))
(defn raw-geopoint-to-osgrid
([gp datum]
(geopoint-to-osgrid (:latitude gp) (:longitude gp) (:datum gp) datum))
([latitude longitude from-datum to-datum]
;; for bizarrely over-complicated trigonometry, look no further. ;; for bizarrely over-complicated trigonometry, look no further.
(let [point (geopoint gp datum) (let [point (GeoPoint. latitude longitude to-datum)
φ (radians (latitude point)) φ (radians latitude)
λ (radians (longitude point)) λ (radians longitude)
a 6377563.396 ;; Airy 1830 major & minor semi-axes a 6377563.396 ;; Airy 1830 major & minor semi-axes
b 6356256.909 b 6356256.909
F0 0.9996012717 ;; OS Grid scale factor on central meridian F0 0.9996012717 ;; OS Grid scale factor on central meridian
φ0 (radians 49) ;; OS Grid true origin latitude φ0 (radians 49) ;; OS Grid true origin latitude
λ0 (radians -2) ;; OS Grid true origin longitude λ0 (radians -2) ;; OS Grid true origin longitude
Δφ (- φ φ0) ;; latitude offset from origin Δφ (-' φ φ0) ;; latitude offset from origin
Δλ (- λ λ0) ;; longitude offset from origin Δλ (-' λ λ0) ;; longitude offset from origin
Δλ² (reduce * 1 (repeat 2 Δλ)) Δλ² (reduce * 1 (repeat 2 Δλ))
Δλ³ (reduce * 1 (repeat 3 Δλ)) Δλ³ (reduce * 1 (repeat 3 Δλ))
Δλ (reduce * 1 (repeat 4 Δλ)) Δλ (reduce * 1 (repeat 4 Δλ))
@ -285,59 +298,63 @@
Δλ (reduce * 1 (repeat 6 Δλ)) Δλ (reduce * 1 (repeat 6 Δλ))
N0 -100000 ;; northing of true origin, metres N0 -100000 ;; northing of true origin, metres
E0 400000 ;; easting of true origin, metres E0 400000 ;; easting of true origin, metres
e² (- 1 (/ (* b b) (* a a))) ;; eccentricity squared e² (-' 1 (/ (*' b b) (*' a a))) ;; eccentricity squared
n (/ (- a b) (+ a b)) n (/ (-' a b) (+' a b))
n² (* n n) n² (*' n n)
n³ (* n n n) n³ (*' n n n)
sinφ (sin φ) sinφ (sin φ)
sin²φ (* (sin φ) (sin φ)) sin²φ (*' (sin φ) (sin φ))
cosφ (cos φ) cosφ (cos φ)
v (* a (/ F0 (sqrt (- 1 (* e² sin²φ))))) v (*' a (/ F0 (sqrt (-' 1 (*' e² sin²φ)))))
;; nu = transverse radius of curvature ;; nu = transverse radius of curvature
ρ (/ (* a F0 (- 1 e²)) (expt (- 1 (* e² sin²φ)) 1.5)) ρ (/ (*' a F0 (-' 1 e²)) (expt (-' 1 (*' e² sin²φ)) 1.5))
;; rho = meridional radius of curvature ;; rho = meridional radius of curvature
η2 (/ v (- ρ 1)) ;; beware confusing η2 with n² η2 (/ v (-' ρ 1)) ;; beware confusing η2 with n²
Ma (* (+ 1 n (* (/ 5 4) n²) (* (/ 5 4) n³)) Δφ) Ma (*' (+' 1 n (*' (/ 5 4) n²) (*' (/ 5 4) n³)) Δφ)
Mb (* Mb (*
(+ (* 3 n) (* 3 n²) (* (/ 21 8) n³)) (+' (*' 3 n) (*' 3 n²) (*' (/ 21 8) n³))
(sin Δφ) (cos (+ φ φ0))) (sin Δφ) (cos (+' φ φ0)))
Mc (* Mc (*
(+ (* (/ 15 8) n²) (* (/ 15 8) n³)) (+' (*' (/ 15 8) n²) (*' (/ 15 8) n³))
(sin (* 2 Δφ)) (cos (* 2 (+ φ φ0)))) (sin (*' 2 Δφ)) (cos (*' 2 (+' φ φ0))))
Md (* (/ 35 24) n³ (sin (* 3 Δφ)) (cos (* 3 (+ φ φ0)))) Md (*' (/ 35 24) n³ (sin (*' 3 Δφ)) (cos (*' 3 (+' φ φ0))))
M (* b F0 (+ (- Ma Mb) (- Mc Md))) M (*' b F0 (+' (-' Ma Mb) (-' Mc Md)))
;; meridional arc ;; meridional arc
cos³φ (reduce * 1 (repeat 3 cosφ)) cos³φ (reduce * 1 (repeat 3 cosφ))
cosφ (reduce * 1 (repeat 5 cosφ)) cosφ (reduce * 1 (repeat 5 cosφ))
tan²φ (reduce * 1 (repeat 2 (tan φ))) tan²φ (reduce * 1 (repeat 2 (tan φ)))
tanφ (reduce * 1 (repeat 4 (tan φ))) tanφ (reduce * 1 (repeat 4 (tan φ)))
I (+ M N0) I (+' M N0)
II (* (/ v 2) sinφ cosφ) II (*' (/ v 2) sinφ cosφ)
III (* (/ v 24) sinφ cos³φ (- 5 (+ tan²φ (* 9 η2)))) III (*' (/ v 24) sinφ cos³φ (-' 5 (+' tan²φ (*' 9 η2))))
;; var IIIA = (ν/720)*sinφ*cos5φ*(61-58*tan2φ+tan4φ); ;; var IIIA = (ν/720)*sinφ*cos5φ*(61-58*tan2φ+tan4φ);
;; TODO: CHECK JAVASCRIPT OPERATOR PRECEDENCE! ;; TODO: CHECK JAVASCRIPT OPERATOR PRECEDENCE!
IIIA (* (/ v 720) sinφ cosφ (- 61 (+ (* 58 tan²φ) tanφ))) IIIA (*' (/ v 720) sinφ cosφ (-' 61 (+' (*' 58 tan²φ) tanφ)))
IV (* v cosφ) IV (*' v cosφ)
V (* (/ v 6) cos³φ (- (/ v ρ) tan²φ)) V (*' (/ v 6) cos³φ (-' (/ v ρ) tan²φ))
;; var VI = (ν/120) * cos5φ * (5 - 18*tan2φ + tan4φ + 14*η2 - 58*tan2φ*η2); ;; var VI = (ν/120) * cos5φ * (5 - 18*tan2φ + tan4φ + 14*η2 - 58*tan2φ*η2);
VI (* VI (*
(/ v 120) (/ v 120)
cosφ cosφ
(- 5 (-' 5
(+ (* 18 tan²φ) (+' (*' 18 tan²φ)
tanφ tanφ
(* 14 η2) (- 0 (* 58 tan²φ η2))))) (*' 14 η2) (-' 0 (*' 58 tan²φ η2)))))
N (to-fixed (+ I (* II Δλ²) (+ III Δλ) (* IIIA Δλ)) 3) N (to-fixed (+' I (*' II Δλ²) (+' III Δλ) (*' IIIA Δλ)) 3)
E (to-fixed (+ E0 (* IV Δλ) (* V Δλ³) (* VI Δλ)) 3)] E (to-fixed (+' E0 (*' IV Δλ) (*' V Δλ³) (*' VI Δλ)) 3)]
(OsGrid. E N))) (OsGrid. E N))))
(defn geopoint-to-vector3d (def geopoint-to-osgrid (memoize raw-geopoint-to-osgrid))
[geopoint]
(defn raw-geopoint-to-vector3d
([gp]
(println (str "(geopoint-to-vector3d " geopoint ")")) (println (str "(geopoint-to-vector3d " geopoint ")"))
(let [datum (datum geopoint) (geopoint-to-vector3d (:latitude gp) (:longitude gp) (datums (:datum gp))))
φ (radians (latitude geopoint)) ([latitude longitude datum]
λ (radians (longitude geopoint)) (let [φ (radians latitude)
λ (radians longitude)
h 0 h 0
a (:a (:ellipsoid datum)) a (:a (:ellipsoid datum))
f (:f (:ellipsoid datum)) f (:f (:ellipsoid datum))
@ -345,86 +362,91 @@
cosφ (cos φ) cosφ (cos φ)
sinλ (sin λ) sinλ (sin λ)
cosλ (cos λ) cosλ (cos λ)
e² (- (* 2 f) (* f f)) e² (-' (*' 2 f) (*' f f))
v (/ a (sqrt (- 1 (* e² sinφ sinφ))))] v (/ a (sqrt (-' 1 (*' e² sinφ sinφ))))]
(Vector3d. (Vector3d.
(* (+ v h) cosφ cosλ) (*' (+' v h) cosφ cosλ)
(* (+ v h) cosφ sinλ) (*' (+' v h) cosφ sinλ)
(* v (+ h (- 1 e²)) sinφ)))) (*' v (+' h (-' 1 e²)) sinφ)))))
(defn osgrid-to-geopoint (def geopoint-to-vector3d (memoize raw-geopoint-to-vector3d))
[osgrid datum]
(defn raw-osgrid-to-geopoint
([osgrid datum]
(osgrid-to-geopoint (:e osgrid) (:n osgrid) datum))
([E N datum]
(let (let
[d datum [a 6377563.396 ;; Airy 1830 major semi-axis
E (.e osgrid)
N (.n osgrid)
a 6377563.396 ;; Airy 1830 major semi-axis
b 6356256.909 ;; Airy 1830 minor semi-axis b 6356256.909 ;; Airy 1830 minor semi-axis
F0 0.9996012717 ;; national grid scale factor on central meridian F0 0.9996012717 ;; national grid scale factor on central meridian
φ0 (radians 49) ;; national grid true origin latitude φ0 (radians 49) ;; national grid true origin latitude
λ0 (radians -2) ;; national grid true origin longitude λ0 (radians -2) ;; national grid true origin longitude
N0 -100000 ;; northing of true origin, metres N0 -100000 ;; northing of true origin, metres
E0 400000 ;; easting of true origin, metres E0 400000 ;; easting of true origin, metres
e² (- 1 e² (-' 1
(/ (/
(* b b) (*' b b)
(* a a))) ;; eccentricity squared (*' a a))) ;; eccentricity squared
n (/ (- a b) (+ a b)) n (/ (-' a b) (+' a b))
n² (* n n) n² (*' n n)
n³ (* n n n) n³ (*' n n n)
[M φ] (loop [φ φ0 M 0] [M φ] (loop [φ φ0 M 0]
(let (let
[φ (+ φ (/ (- N N0 M) (* a F0))) [φ (+' φ (/ (-' N N0 M) (*' a F0)))
Δφ (- φ φ0) Δφ (-' φ φ0)
Ma (* (+ 1 n (* 5/4 n²) (* 5/4 n³)) Δφ) Ma (*' (+' 1 n (*' 5/4 n²) (*' 5/4 n³)) Δφ)
Mb (* (+ (* n 3) (* n² 3) (* n³ 21/8)) (sin Δφ) (cos Δφ)) Mb (*' (+' (*' n 3) (*' n² 3) (*' n³ 21/8)) (sin Δφ) (cos Δφ))
Mc (* (+ (* n² 15/8) (* n³ 15/8)) (sin (* 2 Δφ)) (cos (* 2 Δφ))) Mc (*' (+' (*' n² 15/8) (*' n³ 15/8)) (sin (*' 2 Δφ)) (cos (*' 2 Δφ)))
Md (* 35/24 n³ (sin (* 3 Δφ)) (cos (* 3 Δφ))) Md (*' 35/24 n³ (sin (*' 3 Δφ)) (cos (*' 3 Δφ)))
M (* b F0 (+ (- 0 Ma) Mb Mc (- 0 Md)))] M (*' b F0 (+' (-' 0 Ma) Mb Mc (-' 0 Md)))]
(if (if
(>= (- N N0 M) 0.00001) (>= (-' N N0 M) 0.00001)
(recur M φ) (recur M φ)
[M φ]))) [M φ])))
sinφ (sin φ) sinφ (sin φ)
sin²φ (* (sin φ) (sin φ)) sin²φ (*' (sin φ) (sin φ))
cosφ (cos φ) cosφ (cos φ)
v (* a (/ F0 (sqrt (- 1 (* e² sin²φ))))) v (*' a (/ F0 (sqrt (-' 1 (*' e² sin²φ)))))
v³ (reduce * 1 (repeat 3 v)) v³ (reduce * 1 (repeat 3 v))
v (reduce * 1 (repeat 5 v)) v (reduce * 1 (repeat 5 v))
v (reduce * 1 (repeat 7 v)) v (reduce * 1 (repeat 7 v))
;; nu = transverse radius of curvature ;; nu = transverse radius of curvature
ρ (/ (* a F0 (- 1 e²)) (expt (- 1 (* e² sin²φ)) 1.5)) ρ (/ (*' a F0 (-' 1 e²)) (expt (-' 1 (*' e² sin²φ)) 1.5))
;; rho = meridional radius of curvature ;; rho = meridional radius of curvature
η2 (/ v (- ρ 1)) ;; beware confusing η2 with n² η2 (/ v (-' ρ 1)) ;; beware confusing η2 with n²
tanφ (tan φ) tanφ (tan φ)
tan²φ (reduce * 1 (repeat 2 tanφ)) tan²φ (reduce * 1 (repeat 2 tanφ))
tanφ (reduce * 1 (repeat 4 tanφ)) tanφ (reduce * 1 (repeat 4 tanφ))
tanφ (reduce * 1 (repeat 6 tanφ)) tanφ (reduce * 1 (repeat 6 tanφ))
secφ (/ 1 cosφ) secφ (/ 1 cosφ)
VII (/ tanφ (* 2 ρ v)) VII (/ tanφ (*' 2 ρ v))
;; TODO: check Javascript operator precedence! ;; TODO: check Javascript operator precedence!
VIII (* (/ tanφ (* 24 ρ v³) (+ 5 (* 3 tan²φ) η2 (- 0 (* 9 tan²φ η2))))) VIII (*' (/ tanφ (*' 24 ρ v³) (+' 5 (*' 3 tan²φ) η2 (-' 0 (*' 9 tan²φ η2)))))
;; var VIII = tanφ/(24*ρ*ν3)*(5+3*tan2φ+η2-9*tan2φ*η2); ;; var VIII = tanφ/(24*ρ*ν3)*(5+3*tan2φ+η2-9*tan2φ*η2);
IX (* (/ tanφ (* 720 ρ v)) (+ 61 (* 90 tan²φ) (* 45 tanφ))) IX (*' (/ tanφ (*' 720 ρ v)) (+' 61 (*' 90 tan²φ) (*' 45 tanφ)))
;; var IX = tanφ/(720*ρ*ν5)*(61+90*tan2φ+45*tan4φ); ;; var IX = tanφ/(720*ρ*ν5)*(61+90*tan2φ+45*tan4φ);
X (/ secφ v) X (/ secφ v)
XI (* (/ secφ (* 6 v³)) (+ (/ v ρ) (* 2 tan²φ))) XI (*' (/ secφ (*' 6 v³)) (+' (/ v ρ) (*' 2 tan²φ)))
;; var XI = secφ/(6*ν3)*(ν/ρ+2*tan2φ); ;; var XI = secφ/(6*ν3)*(ν/ρ+2*tan2φ);
XII (* (/ secφ (* 120 v)) (+ 5 (* 28 tan²φ) (* 24 tanφ))) XII (*' (/ secφ (*' 120 v)) (+' 5 (*' 28 tan²φ) (*' 24 tanφ)))
;; var XII = secφ/(120*ν5)*(5+28*tan2φ+24*tan4φ); ;; var XII = secφ/(120*ν5)*(5+28*tan2φ+24*tan4φ);
XIIA (* (/ secφ (* 5040 v)) (+ 61 (* 622 tan²φ) (* 1322 tanφ) (* 720 tanφ))) XIIA (*' (/ secφ (*' 5040 v)) (+' 61 (*' 622 tan²φ) (*' 1322 tanφ) (*' 720 tanφ)))
;; var XIIA = secφ/(5040*ν7)*(61+662*tan2φ+1320*tan4φ+720*tan6φ); ;; var XIIA = secφ/(5040*ν7)*(61+662*tan2φ+1320*tan4φ+720*tan6φ);
Δe (- E E0) Δe (-' E E0)
Δe² (reduce * 1 (repeat 2 Δe)) Δe² (reduce *' 1 (repeat 2 Δe))
Δe³ (reduce * 1 (repeat 3 Δe)) Δe³ (reduce *' 1 (repeat 3 Δe))
Δe (reduce * 1 (repeat 4 Δe)) Δe (reduce *' 1 (repeat 4 Δe))
Δe (reduce * 1 (repeat 5 Δe)) Δe (reduce *' 1 (repeat 5 Δe))
Δe (reduce * 1 (repeat 6 Δe)) Δe (reduce *' 1 (repeat 6 Δe))
Δe (reduce * 1 (repeat 6 Δe)) Δe (reduce *' 1 (repeat 6 Δe))
φ (+ φ (- 0 (+ VII Δe²)) (* VIII Δe) (- 0 (* IX Δe))) φ (+' φ (-' 0 (+' VII Δe²)) (*' VIII Δe) (-' 0 (*' IX Δe)))
λ (+ λ0 (* X Δe) (- 0 (* XI Δe³)) (* IX Δe) (- 0 (* XIIA Δe)))] λ (+' λ0 (*' X Δe) (-' 0 (*' XI Δe³)) (*' IX Δe) (-' 0 (*' XIIA Δe)))]
(.geopoint (GeoPoint. (degrees φ) (degrees λ) :OSGB36) datum))) (GeoPoint. (degrees φ) (degrees λ) :WGS84))))
(def osgrid-to-geopoint (memoize raw-osgrid-to-geopoint))
(defn post-code-data-to-addresses (defn post-code-data-to-addresses
@ -452,42 +474,26 @@
;; (def home (GeoPoint. 54.8240911 -3.9170342 :WGS84)) ;; (def home (GeoPoint. 54.8240911 -3.9170342 :WGS84))
;; ;; ;;
;; (:datum home) ;; ;; (:datum home)
;; (datums (:datum home)) ;; (datums (:datum home))
;; (:ellipsoid (datums (:datum home))) ;; (:ellipsoid (datums (:datum home)))
;; @@
;; =>
;;; {"type":"html","content":"<span class='clj-var'>#&#x27;yyy-data.core/home</span>","value":"#'yyy-data.core/home"}
;; <=
;; @@ ;; ;; @@
;;(.osgrid home :WGS84) ;; (osgrid home :WGS84)
;; @@
;; @@ ;; (def hazelfield (OsGrid. 277656 549165))
;;(:datum home)
;; @@ ;; (apply-transform
;; => ;; (apply-transform
;;; {"type":"html","content":"<span class='clj-keyword'>:WGS84</span>","value":":WGS84"} ;; (Vector3d. 1 1 1)
;; <= ;; { :tx 89.5, :ty 93.8 :tz 123.1 :s -1.2 :rx 0.0 :ry 0.0 :rz 0.156 })
;; (inverse-transform { :tx 89.5, :ty 93.8 :tz 123.1 :s -1.2 :rx 0.0 :ry 0.0 :rz 0.156 }))
;; @@ ;; (inverse-transform { :tx 89.5, :ty 93.8 :tz 123.1 :s -1.2 :rx 0.0 :ry 0.0 :rz 0.156 })
;; (datums (:datum home))
;; @@
;; =>
;;; {"type":"list-like","open":"<span class='clj-map'>{</span>","close":"<span class='clj-map'>}</span>","separator":", ","items":[{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:key</span>","value":":key"},{"type":"html","content":"<span class='clj-keyword'>:WGS84</span>","value":":WGS84"}],"value":"[:key :WGS84]"},{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:ellipsoid</span>","value":":ellipsoid"},{"type":"list-like","open":"<span class='clj-map'>{</span>","close":"<span class='clj-map'>}</span>","separator":", ","items":[{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:a</span>","value":":a"},{"type":"html","content":"<span class='clj-long'>6378137</span>","value":"6378137"}],"value":"[:a 6378137]"},{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:b</span>","value":":b"},{"type":"html","content":"<span class='clj-double'>6356752.314245</span>","value":"6356752.314245"}],"value":"[:b 6356752.314245]"},{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:f</span>","value":":f"},{"type":"html","content":"<span class='clj-double'>0.0033528106647474805</span>","value":"0.0033528106647474805"}],"value":"[:f 0.0033528106647474805]"}],"value":"{:a 6378137, :b 6356752.314245, :f 0.0033528106647474805}"}],"value":"[:ellipsoid {:a 6378137, :b 6356752.314245, :f 0.0033528106647474805}]"},{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:transform</span>","value":":transform"},{"type":"list-like","open":"<span class='clj-map'>{</span>","close":"<span class='clj-map'>}</span>","separator":", ","items":[{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:tx</span>","value":":tx"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[:tx 0.0]"},{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:ty</span>","value":":ty"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[:ty 0.0]"},{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:tz</span>","value":":tz"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[:tz 0.0]"},{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:s</span>","value":":s"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[:s 0.0]"},{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:rx</span>","value":":rx"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[:rx 0.0]"},{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:ry</span>","value":":ry"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[:ry 0.0]"},{"type":"list-like","open":"","close":"","separator":" ","items":[{"type":"html","content":"<span class='clj-keyword'>:rz</span>","value":":rz"},{"type":"html","content":"<span class='clj-double'>0.0</span>","value":"0.0"}],"value":"[:rz 0.0]"}],"value":"{:tx 0.0, :ty 0.0, :tz 0.0, :s 0.0, :rx 0.0, :ry 0.0, :rz 0.0}"}],"value":"[:transform {:tx 0.0, :ty 0.0, :tz 0.0, :s 0.0, :rx 0.0, :ry 0.0, :rz 0.0}]"}],"value":"{:key :WGS84, :ellipsoid {:a 6378137, :b 6356752.314245, :f 0.0033528106647474805}, :transform {:tx 0.0, :ty 0.0, :tz 0.0, :s 0.0, :rx 0.0, :ry 0.0, :rz 0.0}}"}
;; <=
;; @@
*ns*
;; @@
;; =>
;;; {"type":"html","content":"<span class='clj-unkown'>#namespace[yyy-data.core]</span>","value":"#namespace[yyy-data.core]"}
;; <=
;; @@ ;; (geopoint (osgrid-to-geopoint hazelfield :froboz) :WGS84)
;; @@

View file

@ -1,7 +1,65 @@
(ns yyy-data.core-test (ns yyy-data.core-test
(:require [clojure.test :refer :all] (:require [clojure.test :refer :all]
[adl-data.core :refer :all])) [yyy-data.core :refer :all]))
(defn abs [n]
(if (pos? n) n (- 0 n)))
(deftest vector-tests
(testing "vector transformation round-trip."
(let [unit-vector (yyy_data.core.Vector3d. 1 1 1)
transformed (apply-transform
(apply-transform unit-vector (:transform (:ED50 datums)))
(inverse-transform (:transform (:ED50 datums))))]
(is
(< (abs (- 1 (:x transformed))) 0.001)
(str "Components should be close to 1: x: " (:x transformed)))
(is
(< (abs (- 1 (:y transformed))) 0.001)
(str "Components should be close to 1: y: " (:y transformed)))
(is
(< (abs (- 1 (:z transformed))) 0.001)
(str "Components should be close to 1: z: " (:z transformed))))))
(deftest osgrid-to-geopoint-tests
(testing "osgrid to geopoint one way"
(let
[hazelfield (yyy_data.core.OsGrid. 277656 549165)
actual (geopoint hazelfield :WGS84)]
(is
(< (abs (- (:latitude actual) 54.822218)) 0.001)
(str "Latitude should be 54.822219: " (:latitude actual)))
(is
(< (abs (- (:longitude actual) -3.906009)) 0.001)
(str "Longitude should be -3.906009: " (:longitude actual))))))
(deftest geopoint-to-osgrid-tests
(testing "geopoint to osgrid one way"
(let
[hazelfield (yyy_data.core.GeoPoint. 54.822218 -3.906009 :WGS84)
actual (osgrid hazelfield :WGS84)]
(is
(< (abs (- (:n actual) 549165)) 0.001)
(str "Northing should be 549165: " (:n actual)))
(is
(< (abs (- (:e actual) 277656)) 0.001)
(str "Easting should be 277656: " (:e actual))))))
(deftest osgrid-to-geopoint-round-trip-tests
(testing "osgrid to geopoint round trip"
(let
[hazelfield (yyy_data.core.OsGrid. 277656 549165)
latlon (geopoint hazelfield :WGS84)
hazelfield' (osgrid latlon :WGS84)]
(is
(< (abs (- (:e hazelfield) (:e hazelfield'))) 0.001)
(str "Components should be close to one another: easting: "
(:e hazelfield) ", " (:e hazelfield')))
(is
(< (abs (- (:n hazelfield) (:n hazelfield'))) 0.001)
(str "Components should be close to one another: northing: "
(:n hazelfield) ", " (:n hazelfield'))))))
(deftest a-test
(testing "FIXME, I fail."
(is (= 0 1))))