swedishgrid 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,46 @@
1
+ = swedishgrid
2
+
3
+ == DESCRIPTION:
4
+
5
+ Convert coordinates between geodetic WGS84 and Swedish grid RT90 and SWEREF99 systems.
6
+ Read more about Swedish grid systems at http://www.lantmateriet.se/templates/LMV_Page.aspx?id=5197
7
+
8
+ == SYNOPSIS:
9
+
10
+ grid = SwedishGrid.new(:rt90)
11
+ grid.grid_to_geodetic(7453389.762, 1727060.905)
12
+ # Outputs => [67.0906813246069, 21.034750437141]
13
+
14
+ == DEPENDENCIES:
15
+
16
+ No dependencies.
17
+
18
+ == INSTALL:
19
+
20
+ sudo gem install icehouse-swedishgrid
21
+
22
+ == LICENSE:
23
+
24
+ SwedishGrid is released under MIT license with permission from Arnold Andreasson.
25
+ Original Javascript-version written by Arnold Andreasson can be
26
+ found at: http://mellifica.se/geodesi/gausskruger.js
27
+
28
+ Copyright (c) 2009 ICE House
29
+
30
+ Permission is hereby granted, free of charge, to any person obtaining a
31
+ copy of this software and associated documentation files (the "Software"),
32
+ to deal in the Software without restriction, including without limitation
33
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
34
+ and/or sell copies of the Software, and to permit persons to whom the
35
+ Software is furnished to do so, subject to the following conditions:
36
+
37
+ The above copyright notice and this permission notice shall be included
38
+ in all copies or substantial portions of the Software.
39
+
40
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
41
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
43
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46
+
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "swedishgrid"
8
+ gem.summary = %Q{TODO}
9
+ gem.email = "info@entanke.se"
10
+ gem.homepage = "http://github.com/icehouse/swedishgrid"
11
+ gem.authors = ["Magnus Enarsson"]
12
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
13
+ end
14
+ rescue LoadError
15
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
16
+ end
17
+
18
+ require 'rake/testtask'
19
+ Rake::TestTask.new(:test) do |test|
20
+ test.libs << 'lib' << 'test'
21
+ test.pattern = 'test/**/*_test.rb'
22
+ test.verbose = true
23
+ end
24
+
25
+ begin
26
+ require 'rcov/rcovtask'
27
+ Rcov::RcovTask.new do |test|
28
+ test.libs << 'test'
29
+ test.pattern = 'test/**/*_test.rb'
30
+ test.verbose = true
31
+ end
32
+ rescue LoadError
33
+ task :rcov do
34
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
35
+ end
36
+ end
37
+
38
+
39
+ task :default => :test
40
+
41
+ require 'rake/rdoctask'
42
+ Rake::RDocTask.new do |rdoc|
43
+ if File.exist?('VERSION.yml')
44
+ config = YAML.load(File.read('VERSION.yml'))
45
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
46
+ else
47
+ version = ""
48
+ end
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "swedishgrid #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
55
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 1
3
+ :patch: 3
4
+ :major: 0
@@ -0,0 +1,112 @@
1
+ class SwedishGrid
2
+
3
+ def initialize(grid)
4
+ case grid
5
+ when :rt90
6
+ # rt90_2.5_gon_v
7
+ @axis = 6378137.0
8
+ @flattening = 1.0 / 298.257222101
9
+ @central_meridian = 15.806284529
10
+ @lat_of_origin = 0.0
11
+ @scale = 1.00000561024
12
+ @false_northing = -667.711
13
+ @false_easting = 1500064.274
14
+ when :sweref99tm
15
+ @axis = 6378137.0
16
+ @flattening = 1.0 / 298.257222101
17
+ @central_meridian = 15.00
18
+ @lat_of_origin = 0.0
19
+ @scale = 0.9996
20
+ @false_northing = 0.0
21
+ @false_easting = 500000.0
22
+ else
23
+ raise "Unknown grid"
24
+ end
25
+ end
26
+
27
+ # Conversion from grid coordinates to geodetic coordinates.
28
+ def grid_to_geodetic(x, y)
29
+ # Prepare ellipsoid-based stuff.
30
+ e2 = @flattening * (2.0 - @flattening)
31
+ n = @flattening / (2.0 - @flattening)
32
+ a_roof = @axis / (1.0 + n) * (1.0 + n*n/4.0 + n*n*n*n/64.0)
33
+ delta1 = n/2.0 - 2.0*n*n/3.0 + 37.0*n*n*n/96.0 - n*n*n*n/360.0
34
+ delta2 = n*n/48.0 + n*n*n/15.0 - 437.0*n*n*n*n/1440.0
35
+ delta3 = 17.0*n*n*n/480.0 - 37*n*n*n*n/840.0
36
+ delta4 = 4397.0*n*n*n*n/161280.0
37
+
38
+ astar = e2 + e2*e2 + e2*e2*e2 + e2*e2*e2*e2
39
+ bstar = -(7.0*e2*e2 + 17.0*e2*e2*e2 + 30.0*e2*e2*e2*e2) / 6.0
40
+ cstar = (224.0*e2*e2*e2 + 889.0*e2*e2*e2*e2) / 120.0
41
+ dstar = -(4279.0*e2*e2*e2*e2) / 1260.0
42
+
43
+ # Convert.
44
+ deg_to_rad = Math::PI / 180
45
+ lambda_zero = @central_meridian * deg_to_rad
46
+ xi = (x - @false_northing) / (@scale * a_roof)
47
+ eta = (y - @false_easting) / (@scale * a_roof)
48
+ xi_prim = xi -
49
+ delta1*Math.sin(2.0*xi) * Math.cosh(2.0*eta) -
50
+ delta2*Math.sin(4.0*xi) * Math.cosh(4.0*eta) -
51
+ delta3*Math.sin(6.0*xi) * Math.cosh(6.0*eta) -
52
+ delta4*Math.sin(8.0*xi) * Math.cosh(8.0*eta)
53
+ eta_prim = eta -
54
+ delta1*Math.cos(2.0*xi) * Math.sinh(2.0*eta) -
55
+ delta2*Math.cos(4.0*xi) * Math.sinh(4.0*eta) -
56
+ delta3*Math.cos(6.0*xi) * Math.sinh(6.0*eta) -
57
+ delta4*Math.cos(8.0*xi) * Math.sinh(8.0*eta)
58
+ phi_star = Math.asin(Math.sin(xi_prim) / Math.cosh(eta_prim))
59
+ delta_lambda = Math.atan(Math.sinh(eta_prim) / Math.cos(xi_prim))
60
+ lng_radian = lambda_zero + delta_lambda
61
+ lat_radian = phi_star + Math.sin(phi_star) * Math.cos(phi_star) *
62
+ (astar +
63
+ bstar*(Math.sin(phi_star) ** 2) +
64
+ cstar*(Math.sin(phi_star) ** 4) +
65
+ dstar*(Math.sin(phi_star) ** 6))
66
+ return [lat_radian * 180.0 / Math::PI, lng_radian * 180.0 / Math::PI]
67
+ end
68
+
69
+ # Conversion from geodetic coordinates to grid coordinates.
70
+ def geodetic_to_grid(latitude, longitude)
71
+ # Prepare ellipsoid-based stuff.
72
+ e2 = @flattening * (2.0 - @flattening)
73
+ n = @flattening / (2.0 - @flattening)
74
+ a_roof = @axis / (1.0 + n) * (1.0 + n*n/4.0 + n*n*n*n/64.0)
75
+ a = e2
76
+ b = (5.0*e2*e2 - e2*e2*e2) / 6.0
77
+ c = (104.0*e2*e2*e2 - 45.0*e2*e2*e2*e2) / 120.0
78
+ d = (1237.0*e2*e2*e2*e2) / 1260.0
79
+ beta1 = n/2.0 - 2.0*n*n/3.0 + 5.0*n*n*n/16.0 + 41.0*n*n*n*n/180.0
80
+ beta2 = 13.0*n*n/48.0 - 3.0*n*n*n/5.0 + 557.0*n*n*n*n/1440.0
81
+ beta3 = 61.0*n*n*n/240.0 - 103.0*n*n*n*n/140.0
82
+ beta4 = 49561.0*n*n*n*n/161280.0
83
+
84
+ # Convert.
85
+ deg_to_rad = Math::PI / 180.0
86
+ phi = latitude * deg_to_rad
87
+ lambda = longitude * deg_to_rad
88
+ lambda_zero = @central_meridian * deg_to_rad
89
+
90
+ phi_star = phi - Math.sin(phi) * Math.cos(phi) * (a +
91
+ b*(Math.sin(phi) ** 2) +
92
+ c*(Math.sin(phi) ** 4) +
93
+ d*(Math.sin(phi) ** 6))
94
+ delta_lambda = lambda - lambda_zero
95
+ xi_prim = Math.atan(Math.tan(phi_star) / Math.cos(delta_lambda))
96
+ eta_prim = Math.atanh(Math.cos(phi_star) * Math.sin(delta_lambda))
97
+ x = @scale * a_roof * (xi_prim +
98
+ beta1 * Math.sin(2.0*xi_prim) * Math.cosh(2.0*eta_prim) +
99
+ beta2 * Math.sin(4.0*xi_prim) * Math.cosh(4.0*eta_prim) +
100
+ beta3 * Math.sin(6.0*xi_prim) * Math.cosh(6.0*eta_prim) +
101
+ beta4 * Math.sin(8.0*xi_prim) * Math.cosh(8.0*eta_prim)) +
102
+ @false_northing
103
+ y = @scale * a_roof * (eta_prim +
104
+ beta1 * Math.cos(2.0*xi_prim) * Math.sinh(2.0*eta_prim) +
105
+ beta2 * Math.cos(4.0*xi_prim) * Math.sinh(4.0*eta_prim) +
106
+ beta3 * Math.cos(6.0*xi_prim) * Math.sinh(6.0*eta_prim) +
107
+ beta4 * Math.cos(8.0*xi_prim) * Math.sinh(8.0*eta_prim)) +
108
+ @false_easting
109
+ return [(x * 1000.0).round / 1000.0, (y * 1000.0).round / 1000.0]
110
+ end
111
+
112
+ end
@@ -0,0 +1,67 @@
1
+ require "test_helper"
2
+
3
+ class TestSwedishGrid < Test::Unit::TestCase
4
+
5
+ LAT_LNG_TOLERANCE = 1.0e-7
6
+ GRID_TOLERANCE = 0.001
7
+
8
+ def setup
9
+ # Points from dokument "Kontrollpunkter" at lantmateritet.se
10
+ # http://www.lantmateriet.se/upload/filer/kartor/geodesi_gps_och_detaljmatning/Transformationer/SWEREF99_RT90_Samband/kontrollpunkter.pdf
11
+ # http://latlong.mellifica.se/
12
+ # WGS 84 and SWEREF 99 are, in principle, interchangeable
13
+
14
+ @rt90 = [ [7453389.762, 1727060.905],
15
+ [7047738.415, 1522128.637],
16
+ [6671665.273, 1441843.186],
17
+ [6249111.351, 1380573.079] ]
18
+
19
+ @sweref99tm = [ [7454204.638, 761811.242],
20
+ [7046077.605, 562140.337],
21
+ [6669189.376, 486557.055],
22
+ [6246136.458, 430374.835] ]
23
+
24
+ @lat_lng = [ [67 + 5/60.0 + 26.452769/3600, 21 + 2/60.0 + 5.101575/3600],
25
+ [63 + 32/60.0 + 14.761735/3600, 16 + 14/60.0 + 59.594626/3600],
26
+ [60 + 9/60.0 + 33.882413/3600, 14 + 45/60.0 + 28.167152/3600],
27
+ [56 + 21/60.0 + 17.199245/3600, 13 + 52/60.0 + 23.754022/3600] ]
28
+
29
+ end
30
+
31
+
32
+ def test_rt90_grid_to_geodetic
33
+ grid = SwedishGrid.new(:rt90)
34
+ (0..3).each do |i|
35
+ coord = grid.grid_to_geodetic(*@rt90[i])
36
+ assert (coord[0] - @lat_lng[i][0]).abs < LAT_LNG_TOLERANCE
37
+ assert (coord[1] - @lat_lng[i][1]).abs < LAT_LNG_TOLERANCE
38
+ end
39
+ end
40
+
41
+ def test_rt90_geodetic_to_grid
42
+ grid = SwedishGrid.new(:rt90)
43
+ (0..3).each do |i|
44
+ coord = grid.geodetic_to_grid(*@lat_lng[i])
45
+ assert (coord[0] - @rt90[i][0]).abs < GRID_TOLERANCE
46
+ assert (coord[1] - @rt90[i][1]).abs < GRID_TOLERANCE
47
+ end
48
+ end
49
+
50
+ def test_sweref99tm_grid_to_geodetic
51
+ grid = SwedishGrid.new(:sweref99tm)
52
+ (0..3).each do |i|
53
+ coord = grid.grid_to_geodetic(*@sweref99tm[i])
54
+ assert (coord[0] - @lat_lng[i][0]).abs < LAT_LNG_TOLERANCE
55
+ assert (coord[1] - @lat_lng[i][1]).abs < LAT_LNG_TOLERANCE
56
+ end
57
+ end
58
+
59
+ def test_sweref99tm_geodetic_to_grid
60
+ grid = SwedishGrid.new(:sweref99tm)
61
+ (0..3).each do |i|
62
+ coord = grid.geodetic_to_grid(*@lat_lng[i])
63
+ assert (coord[0] - @sweref99tm[i][0]).abs < GRID_TOLERANCE
64
+ assert (coord[1] - @sweref99tm[i][1]).abs < GRID_TOLERANCE
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ require 'swedishgrid'
7
+
8
+ class Test::Unit::TestCase
9
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: swedishgrid
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Magnus Enarsson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2009-05-05 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description:
15
+ email: magnus@icehouse.se
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files:
19
+ - README.rdoc
20
+ files:
21
+ - README.rdoc
22
+ - Rakefile
23
+ - VERSION.yml
24
+ - lib/swedishgrid.rb
25
+ - test/swedishgrid_test.rb
26
+ - test/test_helper.rb
27
+ homepage:
28
+ licenses: []
29
+ post_install_message:
30
+ rdoc_options:
31
+ - --charset=UTF-8
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 1.8.24
49
+ signing_key:
50
+ specification_version: 2
51
+ summary: Convert coordinates between geodetic WGS84 and Swedish grid RT90 and SWEREF99
52
+ systems.
53
+ test_files:
54
+ - test/swedishgrid_test.rb
55
+ - test/test_helper.rb