osgb 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,51 @@
1
+ # OSGB
2
+
3
+ Osgb is a library that converts between British (and Irish) grid references and latitude and longitude co-ordinates. It is theoretically precise to about 1m, which is to say it's good for WGS84 and most GPS use but not up to surveying with ITRS or ETRS89. So don't do that.
4
+
5
+ ## Installation
6
+
7
+ In <b>Rails 3</b>, add this to your Gemfile and run `bundle install`.
8
+
9
+ gem "osgb"
10
+
11
+ In <b>Rails 2</b>, add this to your environment.rb file.
12
+
13
+ config.gem "osgb"
14
+
15
+ Alternatively, you can install it as a plugin.
16
+
17
+ rails plugin install git://github.com/spanner/osgb.git
18
+
19
+ ## Status
20
+
21
+ Early days: activerecord interface hasn't settled down, some refactoring likely, bugs entirely possible. The basic algorithms are ancient and sound, though.
22
+
23
+ ## Usage
24
+
25
+ You don't need to make any explicit reference to the gem. It adds conversion methods to the String class:
26
+
27
+ "SD28687846".is_gridref? # -> true
28
+ "SD28687846".to_latlng # -> [54.196763, -3.093320]
29
+ "SD28687846".to_wgs84 # -> [54.196915, -3.094684]
30
+ "1.056789, 55.98978607".is_latlng? # -> true
31
+
32
+ and provides some (tentative) help for your ActiveRecord classes:
33
+
34
+ class Checkpoint < ActiveRecord::Base
35
+ has_gridref :lat => 'lat',
36
+ :lng => 'lng',
37
+ :gridref => 'gridref',
38
+ :validation => false,
39
+ :converstion => true
40
+
41
+ The :lat, :lng and :gridref keys should pass in the names of the relevant columns if they don't match these defaults.
42
+
43
+ ## Bugs and features
44
+
45
+ [Github issues](http://github.com/spanner/osgb/issues) please, or for little things an email or github message is fine.
46
+
47
+ ## Author & Copyright
48
+
49
+ Copyright 2008-2011 Will at spanner.org.
50
+
51
+ Released under the same terms as Ruby
@@ -2,6 +2,7 @@ require 'osgb/angle_conversions' # converts degrees to radians and
2
2
  require 'osgb/ellipsoid' # standard approximations to the squashed-circle shape of the earth
3
3
  require 'osgb/projection' # the geometrical distortions required by a map projection
4
4
  require 'osgb/helmert' # 3d transformation algorithm for mapping between cartesian and ellipsoidal polar coordinates
5
+ require 'osgb/point' # versatile coordinate pair
5
6
  require 'osgb/gridref' # parse grid references and returns lat/long pairs
6
7
  require 'osgb/string_conversions' # add conversion methods to String
7
8
  require 'osgb/railtie' if defined? Rails # add useful methods to ActiveRecord
@@ -21,6 +22,14 @@ Osgb::Projection.new :utm29, :scale => 0.9996, :phi0 => 0, :lambda0 => -9, :e0 =
21
22
  Osgb::Projection.new :utm30, :scale => 0.9996, :phi0 => 0, :lambda0 => -3, :e0 => 500000, :n0 => 0, :ellipsoid => :utm
22
23
  Osgb::Projection.new :utm31, :scale => 0.9996, :phi0 => 0, :lambda0 => 3, :e0 => 500000, :n0 => 0, :ellipsoid => :utm
23
24
 
24
- # the Helmert matrix used to translate to wgs84.
25
+ # the Helmert matrices used to translate from osgb36 to wgs84 and vice versa
25
26
 
26
- Osgb::Helmert.new :wgs84, :tx => 446.448, :ty => -125.157, :tz => 542.060, :rx => 0.1502, :ry => 0.2470, :rz => 0.8421, :s => -20.4894
27
+ Osgb::Helmert.new :osgb36_to_wgs84, :tx => 446.448, :ty => -125.157, :tz => 542.060, :rx => 0.1502, :ry => 0.2470, :rz => 0.8421, :s => -20.4894
28
+ Osgb::Helmert.new :wgs84_to_osgb36, :tx => -446.448, :ty => 125.157, :tz => -542.060, :rx => -0.1502, :ry => -0.2470, :rz => -0.8421, :s => 20.4894
29
+
30
+ # Housekeeping
31
+
32
+ module Osgb
33
+ class TransformationError < StandardError; end
34
+ class ConfigurationError < StandardError; end
35
+ end
@@ -4,22 +4,29 @@ module Osgb
4
4
  # with help from CPAN module Geography::NationalGrid by and (c) P Kent
5
5
 
6
6
  class Gridref
7
- OsTiles = {
7
+
8
+ # maps OS letter codes onto their coordinates in the master grid
9
+ OS_TILES = {
8
10
  :a => [0,4], :b => [1,4], :c => [2,4], :d => [3,4], :e => [4,4],
9
11
  :f => [0,3], :g => [1,3], :h => [2,3], :j => [3,3], :k => [4,3],
10
12
  :l => [0,2], :m => [1,2], :n => [2,2], :o => [3,2], :p => [4,2],
11
13
  :q => [0,1], :r => [1,1], :s => [2,1], :t => [3,1], :u => [4,1],
12
14
  :v => [0,0], :w => [1,0], :x => [2,0], :y => [3,0], :z => [4,0],
13
15
  }
14
- FalseOrigin = {:e => 2, :n => 1}
15
- SquareSize = [nil, 10000, 1000, 100, 10, 1] # shorter grid ref = larger square.
16
+
17
+ # the offset makes all coordinates positive and <1000km
18
+ FALSE_ORIGIN = {:e => 2, :n => 1}
19
+
20
+ # a shorter grid ref denotes a larger square
21
+ SQUARE_SIZE = [nil, 10000, 1000, 100, 10, 1]
16
22
 
17
- attr_accessor :gridref, :projection, :ellipsoid, :datum, :options, :precision
23
+ attr_accessor :gridref, :projection, :ellipsoid, :options, :precision
18
24
 
25
+ @@default_datum = :osgb36
19
26
  @@iteration_ceiling = 1000
20
27
  @@defaults = {
21
28
  :projection => :gb, # mercator projection of input gridref. Can be any projection name: usually :ie or :gb
22
- :precision => 6 # decimal places in the output lat/long
29
+ :precision => 6, # decimal places in the output lat/long
23
30
  }
24
31
 
25
32
  class << self
@@ -27,7 +34,7 @@ module Osgb
27
34
  @@iteration_ceiling
28
35
  end
29
36
  end
30
-
37
+
31
38
  def initialize(string, options={})
32
39
  raise ArgumentError, "invalid grid reference string '#{string}'." unless string.is_gridref?
33
40
  options = @@defaults.merge(options)
@@ -48,16 +55,16 @@ module Osgb
48
55
  end
49
56
 
50
57
  def resolution
51
- digits.length / 2
58
+ @resolution ||= digits.length / 2
52
59
  end
53
60
 
54
61
  def offsets
55
62
  if tile
56
- major = OsTiles[tile[0,1].downcase.to_sym ]
57
- minor = OsTiles[tile[1,1].downcase.to_sym]
63
+ major = OS_TILES[tile[0,1].downcase.to_sym ]
64
+ minor = OS_TILES[tile[1,1].downcase.to_sym]
58
65
  @offset ||= {
59
- :e => (500000 * (major[0] - FalseOrigin[:e])) + (100000 * minor[0]),
60
- :n => (500000 * (major[1] - FalseOrigin[:n])) + (100000 * minor[1])
66
+ :e => (500000 * (major[0] - FALSE_ORIGIN[:e])) + (100000 * minor[0]),
67
+ :n => (500000 * (major[1] - FALSE_ORIGIN[:n])) + (100000 * minor[1])
61
68
  }
62
69
  else
63
70
  { :e => 0, :n => 0 }
@@ -65,40 +72,40 @@ module Osgb
65
72
  end
66
73
 
67
74
  def easting
68
- @east ||= offsets[:e] + digits[0, resolution].to_i * SquareSize[resolution]
75
+ @east ||= offsets[:e] + digits[0, resolution].to_i * SQUARE_SIZE[resolution]
69
76
  end
70
77
 
71
78
  def northing
72
- @north ||= offsets[:n] + digits[resolution, resolution].to_i * SquareSize[resolution]
79
+ @north ||= offsets[:n] + digits[resolution, resolution].to_i * SQUARE_SIZE[resolution]
73
80
  end
74
81
 
75
- def lat
76
- round(coordinates[:lat].to_degrees)
82
+ def lat(datum=nil)
83
+ to_latlng(datum).lat
77
84
  end
78
85
 
79
- def lng
80
- round(coordinates[:lng].to_degrees)
81
- end
82
-
83
- def round(value)
84
- if value.method(:round).arity == 0
85
- multiplier = 10**precision
86
- (value * multiplier).round.to_f / multiplier
87
- else
88
- value.round(precision)
89
- end
86
+ def lng(datum=nil)
87
+ to_latlng(datum).lng
90
88
  end
91
89
 
92
90
  def to_s
93
91
  gridref.to_s
94
92
  end
95
93
 
96
- def to_latlng
97
- [lat, lng]
94
+ # Returns an Osgb::Point corresponding to this grid reference and lying on the specified datum.
95
+ # We default to WGS84 since that is the representation most likely to be useful.
96
+ #
97
+ def to_latlng(datum=nil)
98
+ datum ||= :wgs84
99
+ point.transform_to(datum)
98
100
  end
99
101
 
100
- def coordinates
101
- unless @coordinates
102
+ private
103
+
104
+ # Returns an Osgb::Point corresponding to this grid reference. Since it is not yet transformed,
105
+ # the point will lie on the native OSGB36 datum.
106
+ #
107
+ def point
108
+ unless @point
102
109
  # variable names correspond roughly to symbols in the OS algorithm, lowercased:
103
110
  # n0 = northing of true origin
104
111
  # e0 = easting of true origin
@@ -168,27 +175,10 @@ module Osgb
168
175
  phi = phi - vii*(d**2) + viii*(d**4) - ix*(d**6)
169
176
  lambda = l0 + x*d - xi*(d**3) + xii*(d**5) - xiia*(d**7)
170
177
 
171
- # phi and lambda are lat and long but note that here we are still in radians and osgb36
172
- # if a different output datum is required, the helmert transformation remaps the coordinates onto a new globe
173
-
174
- if datum && datum != :osgb36
175
- target_ellipsoid = Osgb::Ellipsoid[datum]
176
-
177
- if helmert = Osgb::Helmert[datum]
178
- cartesian_coordinates = ellipsoid.polar_to_cartesian(phi, lambda)
179
- transformed = helmert.transform(*cartesian_coordinates)
180
- phi, lambda = target_ellipsoid.cartesian_to_polar(*transformed)
181
- else
182
- raise RuntimeError, "Missing ellipsoid or helmert transformation for #{datum}"
183
- end
184
- end
185
-
186
- @coordinates = {:lat => phi, :lng => lambda}
178
+ @point = Osgb::Point.new(phi.to_degrees, lambda.to_degrees, :osgb36, precision)
187
179
  end
188
- @coordinates
180
+ @point
189
181
  end
190
-
191
- private
192
182
 
193
183
  def sec(radians)
194
184
  1 / Math.cos(radians)
@@ -25,7 +25,7 @@ module Osgb
25
25
  zp = tz - x*ry + y*rx + z*s1
26
26
  [xp, yp, zp]
27
27
  end
28
-
28
+
29
29
  def self.[](name)
30
30
  @@instances[name]
31
31
  end
@@ -0,0 +1,114 @@
1
+ module Osgb
2
+ class Point
3
+ # A coordinate pair on a specified ellipsoid,
4
+ # easy to use either in string or array context
5
+ # and able to perform basic distance and equivalence.
6
+ # calculations.
7
+
8
+ attr_writer :lat, :lng
9
+ attr_accessor :datum, :precision
10
+
11
+ # Usage:
12
+ # Osgb::Point.new(lat[float], lng[float], datum[symbol], precision[integer])
13
+ #
14
+ # Default datum is :osgb36. For most web use you will be using WGS84 points, since
15
+ # that's the standard for most GPS applications and used by google maps:
16
+ #
17
+ # Osgb::Point.new(54.196915, -3.094684, :wgs84)
18
+ # Osgb::Point.new(54.196763, -3.093320).transform_to(:wgs84)
19
+ #
20
+ def initialize(lat, lng, datum=nil, precision=nil)
21
+ @lat = lat.to_f
22
+ @lng = lng.to_f
23
+ @datum = datum || :osgb36
24
+ @precision = precision || 6
25
+ end
26
+
27
+ # Returns the latitude of the point, rounded to the specified precision
28
+ #
29
+ def lat
30
+ round(@lat)
31
+ end
32
+
33
+ # Returns the longitude of the point, rounded to the specified precision
34
+ #
35
+ def lng
36
+ round(@lng)
37
+ end
38
+
39
+ # Returns true if the coordinates are both specified and within the acceptable range.
40
+ #
41
+ def valid?
42
+ lat && lng && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180
43
+ end
44
+
45
+ # Returns the point as a "lat,lng" string.
46
+ def to_s
47
+ "#{lat},#{lng}"
48
+ end
49
+
50
+ # Returns the point as a [lat,lng] array.
51
+ def to_a
52
+ [lat, lng]
53
+ end
54
+
55
+ # Remaps the point onto another datum. If you're turning OS grid references into GPS coordinates you
56
+ # have to remap from OSGB36 to WGS84:
57
+ #
58
+ # point = "SD28687846".to_latlng.transform_to(:wgs84)
59
+ #
60
+ # or more concisely:
61
+ #
62
+ # point = "SD28687846".to_wgs84
63
+ #
64
+ def transform_to(target_datum)
65
+ return self if datum == target_datum
66
+ if helmert = Osgb::Helmert[:"#{self.datum}_to_#{target_datum}"]
67
+ cartesian_coordinates = Osgb::Ellipsoid[self.datum].polar_to_cartesian(@lat.to_radians,@lng.to_radians)
68
+ transformed = helmert.transform(*cartesian_coordinates)
69
+ phi, lambda = Osgb::Ellipsoid[target_datum].cartesian_to_polar(*transformed)
70
+ self.class.new(phi.to_degrees, lambda.to_degrees, target_datum, precision)
71
+ else
72
+ raise Osgb::TransformationError, "Missing helmert transformation for #{self.datum} to #{target_datum}"
73
+ end
74
+ end
75
+
76
+ # Tests the equivalence of two points, however they are specified.
77
+ # If given two Point objects, they can lie on different datums:
78
+ #
79
+ # Osgb::Point.new(54.196763, -3.093320, :osgb36) == Osgb::Point.new(54.196915, -3.094684, :wgs84) # -> true
80
+ #
81
+ # When comparing a point with a string or array representation they are assumed
82
+ # to lie on the same datum:
83
+ #
84
+ # Osgb::Point.new(54.196763, -3.093320) == "54.196763, -3.093320" # -> true
85
+ # Osgb::Point.new(54.196763, -3.093320) == [54.196763, -3.093320] # -> true
86
+ # Osgb::Point.new(54.196763, -3.093320) == "SD28687846" # -> true
87
+ #
88
+ # Two points with different precisions will not be considered equivalent.
89
+ #
90
+ def ==(other)
91
+ case other
92
+ when Osgb::Point
93
+ other = other.transform_to(self.datum) unless other.datum == self.datum
94
+ self.lat == other.lat && self.lng == other.lng && self.datum == other.datum
95
+ when Array
96
+ self.to_a == other
97
+ when String
98
+ self == other.to_latlng(:datum => self.datum) # serves to normalise string representation
99
+ end
100
+ end
101
+
102
+ private
103
+
104
+ def round(value) #:nodoc:
105
+ if value.method(:round).arity == 0
106
+ multiplier = 10**precision
107
+ (value * multiplier).round.to_f / multiplier
108
+ else
109
+ value.round(precision)
110
+ end
111
+ end
112
+
113
+ end
114
+ end
@@ -1,41 +1,135 @@
1
1
  class String
2
+ # Defines a few methods to make the grid reference machinery easily
3
+ # accessible from string objects.
4
+
5
+ # Returns true if the string is a valid grid reference: that is, it consits
6
+ # of two valid square-designation letters then 4, 6, 8 or 10 digits.
7
+ # Invalid, malformed and just plain not a grid reference will all return
8
+ # false.
9
+ #
2
10
  def is_gridref?
3
11
  !!(self.upcase =~ /^(H(P|T|U|Y|Z)|N(A|B|C|D|F|G|H|J|K|L|M|N|O|R|S|T|U|W|X|Y|Z)|OV|S(C|D|E|G|H|J|K|M|N|O|P|R|S|T|U|W|X|Y|Z)|T(A|F|G|L|M|Q|R|V)){1}\d{4}(NE|NW|SE|SW)?$|((H(P|T|U|Y|Z)|N(A|B|C|D|F|G|H|J|K|L|M|N|O|R|S|T|U|W|X|Y|Z)|OV|S(C|D|E|G|H|J|K|M|N|O|P|R|S|T|U|W|X|Y|Z)|T(A|F|G|L|M|Q|R|V)){1}(\d{4}|\d{6}|\d{8}|\d{10}))$/)
4
12
  end
5
13
 
14
+ # Returns true if the string looks like a grid reference, whether or
15
+ # not it is well-formed or valid on the ground. In validation this may allow
16
+ # you to distinguish between mistaken and irrelevant input.
17
+ #
18
+ # "HD123456".resembles_gridref? # -> true
19
+ # "HD123456".is_gridref? # -> false
20
+ # "SD12345".resembles_gridref? # -> true
21
+ # "SD12345".is_gridref? # -> false
22
+ # "WC1 1AA".resembles_gridref? # -> false
23
+ #
24
+ def resembles_gridref?
25
+ !!(self.upcase =~ /^\w\w\d{2,}/)
26
+ end
27
+
28
+ # Returns true if the string can be decomposed into a valid lat/long
29
+ # co-ordinate pair.
30
+ #
6
31
  def is_latlng?
32
+ coordinates && coordinates.valid?
33
+ end
34
+
35
+ # Returns true if the string can be decomposed into a co-ordinate pair,
36
+ # regardless of whether the coordinates are valid.
37
+ #
38
+ def resembles_latlng?
7
39
  !!coordinates
8
40
  end
9
41
 
10
- def coordinates
11
- if matches = self.match(/(-?\d+\.\d+)[,\s]+(-?\d+\.\d+)/)
12
- matches[1,2]
42
+ # Treats the string as a coordinate pair, if that can be done. Any two
43
+ # decimal numbers, positive or negative, separated by any non-digit (and
44
+ # non -) characters are acceptable.
45
+ #
46
+ # "54.196763, -3.093320".coordinates # -> [54.196763, -3.093320]
47
+ #
48
+ def coordinates(datum=:osgb36, options={})
49
+ if matches = self.match(/(-?\d+\.\d+)[^\d\-]+(-?\d+\.\d+)/)
50
+ lat,lng = matches[1,2]
51
+ Osgb::Point.new(lat, lng, datum, options[:precision])
13
52
  else
14
53
  nil
15
54
  end
16
55
  end
17
-
56
+
57
+ # If the string is a valid grid reference, this returns the lat/long point
58
+ # using the specified or default datum. Default is WGS84 for GPS compatibility.
59
+ #
18
60
  def to_latlng(options={})
19
61
  if is_gridref?
20
- Osgb::Gridref.new(self, options).to_latlng
62
+ Osgb::Gridref.new(self, options).to_latlng(options[:datum])
21
63
  else
22
- self.coordinates
64
+ self.coordinates(options[:datum])
23
65
  end
24
66
  end
25
67
 
68
+ # Returns the grid reference as a lat/long pair on the specified or default datum,
69
+ # raising an exception if it is not valid.
70
+ #
71
+ def to_latlng!(options={})
72
+ with_validity_check { to_latlng(options) }
73
+ end
74
+
75
+ # If the string is a valid grid reference, this returns the coordinate pair
76
+ # using the OSGB36 datum, which is the native representation for grid references.
77
+ #
78
+ def to_osgb36(options={})
79
+ if is_gridref?
80
+ Osgb::Gridref.new(self, options).to_latlng(:osgb36)
81
+ else
82
+ self.coordinates(:osgb36, options)
83
+ end
84
+ end
85
+
86
+ # Returns the grid reference as a lat/long pair on OSGB36, raising an exception
87
+ # if it is not valid.
88
+ #
89
+ def to_osgb36!(options={})
90
+ with_validity_check { to_osgb36(options) }
91
+ end
92
+
93
+ # If the string is a valid grid reference, this returns the coordinate pair
94
+ # using the WGS84 datum, which is the most suitable representation for work
95
+ # with GPS or google maps.
96
+ #
26
97
  def to_wgs84(options={})
27
98
  if is_gridref?
28
- Osgb::Gridref.new(self, options.merge(:datum => :wgs84)).to_latlng
99
+ Osgb::Gridref.new(self, options).to_latlng(:wgs84)
29
100
  else
30
- self.coordinates
101
+ self.coordinates(:wgs84, options)
31
102
  end
32
103
  end
33
104
 
105
+ # Returns the grid reference as a lat/long pair on WGS84, raising an exception
106
+ # if it is not valid.
107
+ #
108
+ def to_wgs84!(options={})
109
+ with_validity_check { to_wgs84(options) }
110
+ end
111
+
112
+ # Returns the latitude component of the string, however it can be found. Works
113
+ # for both coordinate pairs and grid references. Defaults to WGS84 if coming from
114
+ # a grid reference.
115
+ #
34
116
  def lat(options={})
35
- to_latlng({:datum => :wgs84}.merge(options))[0]
117
+ to_latlng(options).lat
36
118
  end
37
119
 
120
+ # Returns the longitude component of the string, however it can be found. Works
121
+ # for both coordinate pairs and grid references. Defaults to WGS84 if coming from
122
+ # a grid reference.
123
+ #
38
124
  def lng(options={})
39
- to_latlng({:datum => :wgs84}.merge(options))[1]
40
- end
125
+ to_latlng(options).lng
126
+ end
127
+
128
+ protected
129
+
130
+ def with_validity_check(&block)
131
+ raise Osgb::TransformationError unless is_gridref?
132
+ block.call
133
+ end
134
+
41
135
  end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Osgb::Point do
4
+
5
+ let(:osgb) { Osgb::Point.new(54.196763, -3.093320, :osgb36) }
6
+ let(:wgs) { Osgb::Point.new(54.196915, -3.094684, :wgs84) }
7
+
8
+ it "should have lat and long" do
9
+ wgs.lat.should == 54.196915
10
+ wgs.lng.should == -3.094684
11
+ end
12
+
13
+ it "should be good at equality" do
14
+ (wgs == [54.196915, -3.094684]).should be_true
15
+ (wgs == "54.196915,-3.094684").should be_true
16
+ (wgs == "54.196915, -3.094684").should be_true
17
+ (wgs == "SD28687846").should be_true
18
+ (wgs == "SD13241324").should be_false
19
+ (wgs == osgb).should be_true
20
+ (wgs == Osgb::Point.new(54.196914, -3.094684)).should be_false
21
+ end
22
+
23
+ it "should be good at helmert transformations" do
24
+ osgb.transform_to(:wgs84).should == wgs
25
+ end
26
+ end
@@ -2,26 +2,54 @@ require 'spec_helper'
2
2
 
3
3
  describe String do
4
4
  it "should know whether or not it looks like a grid reference" do
5
- "SD13241324".is_gridref?.should be_true
5
+ "SD28687846".resembles_gridref?.should be_true
6
+ "SD1324132".resembles_gridref?.should be_true
7
+ "catapult".resembles_gridref?.should be_false
8
+ end
9
+
10
+ it "should know whether or not it is a grid reference" do
11
+ "SD28687846".is_gridref?.should be_true
12
+ "SD1324132".is_gridref?.should be_false
6
13
  "catapult".is_gridref?.should be_false
7
14
  "54.196915 -3.094684".is_gridref?.should be_false
8
15
  end
9
16
 
10
17
  it "should know whether or not it looks like a lat/lng pair" do
11
- "SD13241324".is_latlng?.should be_false
18
+ "SD28687846".resembles_latlng?.should be_false
19
+ "catapult".resembles_latlng?.should be_false
20
+ "54.196915 -3.094684".resembles_latlng?.should be_true
21
+ "54.196915, -3.094684".resembles_latlng?.should be_true
22
+ end
23
+
24
+ it "should know whether or not it is a lat/lng pair" do
25
+ "SD28687846".is_latlng?.should be_false
12
26
  "catapult".is_latlng?.should be_false
13
27
  "54.196915 -3.094684".is_latlng?.should be_true
28
+ "104.196915 -3.094684".is_latlng?.should be_false
29
+ "54.196915 -183.094684".is_latlng?.should be_false
14
30
  "54.196915, -3.094684".is_latlng?.should be_true
15
31
  "54.196915|-3.094684".is_latlng?.should be_true
32
+ "54.196915:-3.094684".is_latlng?.should be_true
33
+ "54.196915x-3.094684".is_latlng?.should be_true
16
34
  end
17
35
 
18
36
  it "should turn be able to turn itself into an osgb lat/lng pair" do
19
- "SD28687846".to_latlng(:precision => 6).should == [54.196763, -3.093320]
20
- "SD28687846".to_latlng(:precision => 2).should == [54.2, -3.09]
37
+ "SD28687846".to_osgb36(:precision => 6).to_a.should == [54.196763, -3.093320]
38
+ "SD28687846".to_osgb36(:precision => 6).to_s.should == "54.196763,-3.09332"
39
+ "SD28687846".to_osgb36(:precision => 2).to_a.should == [54.2, -3.09]
40
+ end
41
+
42
+ it "should turn be able to turn itself into a wgs84 lat/lng pair" do
43
+ "SD28687846".to_wgs84(:precision => 6).to_a.should == [54.196915, -3.094684]
44
+ "SD28687846".to_wgs84(:precision => 2).to_a.should == [54.2, -3.09]
45
+ end
46
+
47
+ it "should default to WGS84 representation" do
48
+ "SD28687846".to_latlng(:precision => 6).to_a.should == [54.196915, -3.094684]
21
49
  end
22
50
 
23
- it "should turn be able to turn itself into a wgs84 lat/lng pair for gps use" do
24
- "SD28687846".to_wgs84(:precision => 6).should == [54.196915, -3.094684]
25
- "SD28687846".to_wgs84(:precision => 2).should == [54.2, -3.09]
51
+ it "should blow up if banged" do
52
+ lambda { "SD28687846".to_latlng!(:precision => 6) }.should_not raise_error
53
+ lambda { "SD2868784".to_latlng!(:precision => 6) }.should raise_error(Osgb::TransformationError)
26
54
  end
27
55
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: osgb
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 0.2.0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - William Ross
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-11-24 00:00:00 Z
18
+ date: 2011-11-25 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rspec
@@ -63,17 +63,19 @@ files:
63
63
  - lib/osgb/gridref.rb
64
64
  - lib/osgb/has_gridref.rb
65
65
  - lib/osgb/helmert.rb
66
+ - lib/osgb/point.rb
66
67
  - lib/osgb/projection.rb
67
68
  - lib/osgb/railtie.rb
68
69
  - lib/osgb/string_conversions.rb
69
70
  - lib/osgb.rb
71
+ - spec/point_spec.rb
70
72
  - spec/spec_helper.rb
71
73
  - spec/string_spec.rb
72
74
  - CHANGELOG.rdoc
73
75
  - Gemfile
74
76
  - LICENSE
75
77
  - Rakefile
76
- - README.md
78
+ - README.markdown
77
79
  - init.rb
78
80
  homepage: http://github.com/spanner/osgb
79
81
  licenses: []
data/README.md DELETED
@@ -1,51 +0,0 @@
1
- = OSGB
2
-
3
- Wiki[https://github.com/spanner/osgb/wiki] RDocs[http://rdoc.info/projects/spanner/osgb]
4
-
5
- Osgb is a library that converts between British (and Irish) grid references and latitude and longitude co-ordinates. It is precise to about 5m, which is to say it's good enough for WGS84 and most GPS use but not local enough for surveying to ETRS89.
6
-
7
- == Installation
8
-
9
- In <b>Rails 3</b>, add this to your Gemfile and run +bundle install+.
10
-
11
- gem "osgb"
12
-
13
- In <b>Rails 2</b>, add this to your environment.rb file.
14
-
15
- config.gem "osgb"
16
-
17
- Alternatively, you can install it as a plugin.
18
-
19
- rails plugin install git://github.com/spanner/osgb.git
20
-
21
- == Usage
22
-
23
- You don't need to make any explicit reference to the gem. It adds conversion methods to the String class:
24
-
25
- "SD12341234".is_gridref? # -> true
26
- "SD12341234".to_latlng # ->
27
- "SD12341234".to_WGS84 # ->
28
- "1.056789, 55.98978607".is_latlng? # -> true
29
- "1.056789, 55.98978607".to_gridref # -> true
30
-
31
- and provides some help for your ActiveRecord classes:
32
-
33
- class Checkpoint < ActiveRecord::Base
34
- has_gridref :lat => 'lat',
35
- :lng => 'lng',
36
- :gridref => 'gridref',
37
- :validation => false,
38
- :converstion => true
39
-
40
- The :lat, :lng and :gridref keys should pass in the names of the relevant columns if they don't match these defaults.
41
-
42
- == Questions or Problems?
43
-
44
- If you have any issues with CanCan which you cannot find the solution to in the documentation[https://github.com/ryanb/cancan/wiki], please add an {issue on GitHub}[https://github.com/ryanb/cancan/issues] or fork the project and send a pull request.
45
-
46
- To get the specs running you should call +bundle+ and then +rake+. See the {spec/README}[https://github.com/ryanb/cancan/blob/master/spec/README.rdoc] for more information.
47
-
48
-
49
- == Special Thanks
50
-
51
- CanCan was inspired by declarative_authorization[https://github.com/stffn/declarative_authorization/] and aegis[https://github.com/makandra/aegis]. Also many thanks to the CanCan contributors[https://github.com/ryanb/cancan/contributors]. See the CHANGELOG[https://github.com/ryanb/cancan/blob/master/CHANGELOG.rdoc] for the full list.