geo_swap 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|