osgb 0.2.0 → 0.3.0

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.
@@ -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.