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 CHANGED
@@ -18,4 +18,5 @@ Gem::Specification.new do |gem|
18
18
  gem.require_paths = ["lib"]
19
19
 
20
20
  gem.add_development_dependency 'rake', '10.0.3'
21
+ gem.add_development_dependency 'rspec', '2.12.0'
21
22
  end
@@ -0,0 +1,10 @@
1
+
2
+ module GeoSwap::Utilities
3
+
4
+ def degrees_to_radians(degrees)
5
+ degrees * (Math::PI / 180)
6
+ end
7
+
8
+ module_function :degrees_to_radians
9
+
10
+ end
@@ -1,3 +1,3 @@
1
1
  module GeoSwap
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -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
- # Your code goes here...
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.1
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: 3296913527661097903
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: 3296913527661097903
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