geo_swap 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/geo_swap.gemspec +1 -0
- data/lib/geo_swap/utilities.rb +10 -0
- data/lib/geo_swap/version.rb +1 -1
- data/lib/geo_swap/zone.rb +19 -0
- data/lib/geo_swap.rb +70 -1
- data/spec/geo_swap/utilities_spec.rb +15 -0
- data/spec/geo_swap/zone_spec.rb +45 -0
- data/spec/geo_swap_spec.rb +49 -0
- metadata +28 -4
data/geo_swap.gemspec
CHANGED
data/lib/geo_swap/version.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
module GeoSwap
|
2
|
+
class Zone
|
3
|
+
def initialize(longitude)
|
4
|
+
@longitude = longitude.to_f
|
5
|
+
end
|
6
|
+
|
7
|
+
def number
|
8
|
+
@number ||= begin
|
9
|
+
number = ((@longitude + 180.0) / 6.0).floor + 1
|
10
|
+
#special case for longitude 180.0
|
11
|
+
(number > 60) ? 60 : number
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def origin
|
16
|
+
@origin ||= ((number - 1) * 6) - 177
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/geo_swap.rb
CHANGED
@@ -1,5 +1,74 @@
|
|
1
1
|
require "geo_swap/version"
|
2
|
+
require 'geo_swap/zone'
|
3
|
+
require 'geo_swap/utilities'
|
2
4
|
|
3
5
|
module GeoSwap
|
4
|
-
|
6
|
+
extend Utilities
|
7
|
+
|
8
|
+
def lat_long_to_utm(lat, long)
|
9
|
+
validate_range(lat, long)
|
10
|
+
lat_radians = degrees_to_radians(lat)
|
11
|
+
long_radians = degrees_to_radians(long)
|
12
|
+
|
13
|
+
zone = Zone.new(long)
|
14
|
+
origin_radians = degrees_to_radians(zone.origin)
|
15
|
+
|
16
|
+
equator_factor = (EQUATORIAL_RADIUS / Math.sqrt(1 - (ECC_SQUARED * (Math.sin(lat_radians) ** 2)))
|
17
|
+
squared_lat_tangent = Math.tan(lat_radians) ** 2
|
18
|
+
ecc_prime_factor = ECC_PRIME_SQUARED * (Math.cos(lat_radians) ** 2)
|
19
|
+
origin_factor = Math.cos(lat_radians) * (long_radians - origin_radians)
|
20
|
+
|
21
|
+
|
22
|
+
ecc_1 = (1 - ecc(1, 1, 4) - ecc(2, 3, 64) - ecc(3, 5, 256))
|
23
|
+
ecc_2 = ecc(1, 3, 8) + ecc(2, 3, 32) + ecc(3, 45, 1024)
|
24
|
+
ecc_3 = ecc(2, 15, 256) + ecc(3, 45, 1024)
|
25
|
+
ecc_4 = ecc(3, 35, 3072)
|
26
|
+
|
27
|
+
latRad_1 = lat_radians
|
28
|
+
latRad_2 = Math.sin(2 * lat_radians)
|
29
|
+
latRad_3 = Math.sin(4 * lat_radians)
|
30
|
+
latRad_4 = Math.sin(6 * lat_radians)
|
31
|
+
|
32
|
+
northing_factor = EQUATORIAL_RADIUS * (
|
33
|
+
ecc_1 * latRad_1 -
|
34
|
+
ecc_2 * latRad_2 +
|
35
|
+
ecc_3 * latRad_3 -
|
36
|
+
ecc_4 * latRad_4
|
37
|
+
)
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
module_function :lat_long_to_utm
|
42
|
+
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
MAX_LATITUDE = 90.0
|
47
|
+
MIN_LATITUDE = -90.0
|
48
|
+
MAX_LONGITUDE = 180
|
49
|
+
MIN_LONGITUDE = -180
|
50
|
+
MAX_CONVERSION_LATITUDE = 84.0
|
51
|
+
MIN_CONVERSION_LATITUDE = -80.0
|
52
|
+
|
53
|
+
EQUATORIAL_RADIUS = 6378137.0
|
54
|
+
ECC_SQUARED = 0.006694380023
|
55
|
+
ECC_PRIME_SQUARED = ECC_SQUARED / (1 - ECC_SQUARED)
|
56
|
+
|
57
|
+
def self.validate_range(lat, long)
|
58
|
+
unless lat.between?(MIN_LATITUDE, MAX_LATITUDE) && long.between?(MIN_LONGITUDE, MAX_LONGITUDE)
|
59
|
+
raise InputError, 'Input coordinates are invalid'
|
60
|
+
end
|
61
|
+
|
62
|
+
unless lat.between?(MIN_CONVERSION_LATITUDE, MAX_CONVERSION_LATITUDE)
|
63
|
+
raise InputError, 'Conversions are unreliable close to the polar regions'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.ecc(power, numerator, denominator)
|
68
|
+
ecc = ECC_SQUARED ** power
|
69
|
+
(numerator * ecc) / denominator
|
70
|
+
end
|
71
|
+
|
5
72
|
end
|
73
|
+
|
74
|
+
class GeoSwap::InputError < StandardError; end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative '../../lib/geo_swap/utilities'
|
2
|
+
|
3
|
+
module GeoSwap
|
4
|
+
describe Utilities do
|
5
|
+
describe 'degrees_to_radians' do
|
6
|
+
DEG_RAD_DATA = [[180, Math::PI], [0, 0], [360, (2 * Math::PI)]]
|
7
|
+
|
8
|
+
it 'converts numbers accurately' do
|
9
|
+
DEG_RAD_DATA.each do |(deg, rad)|
|
10
|
+
Utilities.degrees_to_radians(deg).should == rad
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative '../../lib/geo_swap/zone'
|
2
|
+
|
3
|
+
module GeoSwap
|
4
|
+
describe Zone do
|
5
|
+
|
6
|
+
|
7
|
+
describe 'finding number from lat long' do
|
8
|
+
|
9
|
+
|
10
|
+
ZONE_DATA = [
|
11
|
+
{ long: -180.0, zone_number: 1 },
|
12
|
+
{ long: -147.0, zone_number: 6 },
|
13
|
+
{ long: -139.0, zone_number: 7 },
|
14
|
+
{ long: 0.0, zone_number: 31 },
|
15
|
+
{ long: 62.0, zone_number: 41 },
|
16
|
+
{ long: 71.0, zone_number: 42 },
|
17
|
+
{ long: 110.0, zone_number: 49 },
|
18
|
+
{ long: 141.0, zone_number: 54 },
|
19
|
+
{ long: 180.0, zone_number: 60 },
|
20
|
+
]
|
21
|
+
|
22
|
+
it 'applys the zone formula correctly' do
|
23
|
+
ZONE_DATA.each do |data|
|
24
|
+
Zone.new(data[:long]).number.should == data[:zone_number]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'determining the zone origin' do
|
31
|
+
it 'can migrate from too far left' do
|
32
|
+
Zone.new(-180).origin.should == -177
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'can migrate from too far right' do
|
36
|
+
Zone.new(180).origin.should == 177
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'doesnt change the value when the long is already the origin' do
|
40
|
+
Zone.new(3).origin.should == 3
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative '../lib/geo_swap'
|
2
|
+
|
3
|
+
module GeoSwap
|
4
|
+
|
5
|
+
describe GeoSwap do
|
6
|
+
DATA = [
|
7
|
+
{
|
8
|
+
lat: 29.979175,
|
9
|
+
long: 31.1343583,
|
10
|
+
utm: "36R 320010mE 3317942mN",
|
11
|
+
},
|
12
|
+
{
|
13
|
+
lat: 41.8901694,
|
14
|
+
long: 12.4922694,
|
15
|
+
utm: "33T 291952mE 4640623mN",
|
16
|
+
}
|
17
|
+
]
|
18
|
+
|
19
|
+
describe 'lat_long_to_utm' do
|
20
|
+
def conversion(lat, long)
|
21
|
+
GeoSwap.lat_long_to_utm(lat, long)
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_error(lat, long, message)
|
25
|
+
expect { conversion(lat, long) }.
|
26
|
+
to raise_error(InputError, message)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'rejects data too close to the north pole' do
|
30
|
+
check_error(84.1, 0.0, 'Conversions are unreliable close to the polar regions')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'rejects data too close to the south pole' do
|
34
|
+
check_error(-80.1, 0.0, 'Conversions are unreliable close to the polar regions')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'rejects data outside the possible lat/long range' do
|
38
|
+
check_error(0.0,200.0, 'Input coordinates are invalid')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'correctly converts several reference points' do
|
42
|
+
DATA.each do |data|
|
43
|
+
GeoSwap.lat_long_to_utm(data[:lat], data[:long]).should == data[:utm]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geo_swap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - '='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 10.0.3
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - '='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.12.0
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.12.0
|
30
46
|
description: Simple utility functions for converting between coordinate systems (Lat/Long,
|
31
47
|
UTM, USNG)
|
32
48
|
email:
|
@@ -43,7 +59,12 @@ files:
|
|
43
59
|
- Rakefile
|
44
60
|
- geo_swap.gemspec
|
45
61
|
- lib/geo_swap.rb
|
62
|
+
- lib/geo_swap/utilities.rb
|
46
63
|
- lib/geo_swap/version.rb
|
64
|
+
- lib/geo_swap/zone.rb
|
65
|
+
- spec/geo_swap/utilities_spec.rb
|
66
|
+
- spec/geo_swap/zone_spec.rb
|
67
|
+
- spec/geo_swap_spec.rb
|
47
68
|
homepage: ''
|
48
69
|
licenses: []
|
49
70
|
post_install_message:
|
@@ -58,7 +79,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
58
79
|
version: '0'
|
59
80
|
segments:
|
60
81
|
- 0
|
61
|
-
hash:
|
82
|
+
hash: -10926259193031771
|
62
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
84
|
none: false
|
64
85
|
requirements:
|
@@ -67,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
88
|
version: '0'
|
68
89
|
segments:
|
69
90
|
- 0
|
70
|
-
hash:
|
91
|
+
hash: -10926259193031771
|
71
92
|
requirements: []
|
72
93
|
rubyforge_project:
|
73
94
|
rubygems_version: 1.8.23
|
@@ -75,4 +96,7 @@ signing_key:
|
|
75
96
|
specification_version: 3
|
76
97
|
summary: Simple utility functions for converting between coordinate systems (Lat/Long,
|
77
98
|
UTM, USNG)
|
78
|
-
test_files:
|
99
|
+
test_files:
|
100
|
+
- spec/geo_swap/utilities_spec.rb
|
101
|
+
- spec/geo_swap/zone_spec.rb
|
102
|
+
- spec/geo_swap_spec.rb
|