Class: AIXM::XY
- Includes:
- Concerns::HashEquality
- Defined in:
- lib/aixm/xy.rb
Overview
Geographical coordinates
Warning!
Coordinate tuples can be noted in mathematical order (XY = longitude first, latitude second) or in (more common) geographical order (YX = latitude first, longitude second). However you sort the attributes, make sure not to flip them by accident.
See en.wikipedia.org/wiki/Geographic_coordinate_system
Recognized notations:
-
DD - examples: 12.12345678 (north or east), -12.12345678 (south or west)
-
DMS - examples: 11°22’33.44“N, 1112233.44W,
Constants:
-
AIXM::MIN
- characters recognized as DMS minute symbols -
AIXM::SEC
- characters recognized as DMS second symbols -
AIXM::DMS_RE
- regular expression to match DMS coordinate notations
Constant Summary collapse
- EARTH_RADIUS =
meters
6_371_008.8
Instance Attribute Summary collapse
-
#lat ⇒ Object
Latitude.
-
#long ⇒ Object
Longitude.
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#add_distance(distance, bearing) ⇒ AIXM::XY
Calculate a new point by adding the distance in the given bearing.
-
#bearing(other) ⇒ AIXM::A
Bearing to another point.
-
#distance(other) ⇒ AIXM::D
Distance to another point as calculated by the Haversine formula.
-
#initialize(lat:, long:) ⇒ XY
constructor
See the overview for examples.
- #inspect ⇒ String
-
#seconds? ⇒ Boolean
Whether both longitude and latitude have zero DMS seconds (which may indicate rounded or estimated coordinates).
-
#to_point ⇒ AIXM::Component::Geometry::Point
Convert to point.
-
#to_s ⇒ String
Human readable representation.
Methods included from Concerns::HashEquality
Constructor Details
Instance Attribute Details
#lat ⇒ String, Float #lat=(value) ⇒ Object
Latitude
59 60 61 62 63 64 65 |
# File 'lib/aixm/xy.rb', line 59 def lat(schema=nil) case schema when :ofmx then ("%011.8f" % @lat.abs.round(8)) + (@lat.negative? ? 'S' : 'N') when :aixm then @lat.to_dms(2).gsub(/[^\d.]/, '') + (@lat.negative? ? 'S' : 'N') else @lat.round(8) end end |
#long ⇒ String, Float #long=(value) ⇒ Object
Longitude
80 81 82 83 84 85 86 |
# File 'lib/aixm/xy.rb', line 80 def long(schema=nil) case schema when :ofmx then ("%012.8f" % @long.abs.round(8)) + (@long.negative? ? 'W' : 'E') when :aixm then @long.to_dms(3).gsub(/[^\d.]/, '') + (@long.negative? ? 'W' : 'E') else @long.round(8) end end |
Instance Method Details
#==(other) ⇒ Object
163 164 165 |
# File 'lib/aixm/xy.rb', line 163 def ==(other) self.class === other && lat == other.lat && long == other.long end |
#add_distance(distance, bearing) ⇒ AIXM::XY
Calculate a new point by adding the distance in the given bearing
149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/aixm/xy.rb', line 149 def add_distance(distance, bearing) angular_dist = distance.to_m.dim / EARTH_RADIUS dest_lat = Math.asin( Math.sin(lat.to_rad) * Math.cos(angular_dist) + Math.cos(lat.to_rad) * Math.sin(angular_dist) * Math.cos(bearing.to_f.to_rad) ) dest_long = long.to_rad + Math.atan2( Math.sin(bearing.to_f.to_rad) * Math.sin(angular_dist) * Math.cos(lat.to_rad), Math.cos(angular_dist) - Math.sin(lat.to_rad) * Math.sin(dest_lat) ) AIXM.xy(lat: dest_lat.to_deg, long: dest_long.to_deg) end |
#bearing(other) ⇒ AIXM::A
Bearing to another point
131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/aixm/xy.rb', line 131 def bearing(other) fail "cannot calculate bearing to identical point" if self == other delta_long = other.long.to_rad - long.to_rad AIXM.a( Math.atan2( Math.cos(other.lat.to_rad) * Math.sin(delta_long), Math.cos(lat.to_rad) * Math.sin(other.lat.to_rad) - Math.sin(lat.to_rad) * Math.cos(other.lat.to_rad) * Math.cos(delta_long) ).to_deg ) end |
#distance(other) ⇒ AIXM::D
Distance to another point as calculated by the Haversine formula
112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/aixm/xy.rb', line 112 def distance(other) if self == other AIXM.d(0, :m) else value = 2 * EARTH_RADIUS * Math.asin( Math.sqrt( Math.sin((other.lat.to_rad - lat.to_rad) / 2) ** 2 + Math.cos(lat.to_rad) * Math.cos(other.lat.to_rad) * Math.sin((other.long.to_rad - long.to_rad) / 2) ** 2 ) ) AIXM.d(value.round, :m) end end |
#inspect ⇒ String
42 43 44 |
# File 'lib/aixm/xy.rb', line 42 def inspect %Q(#<#{self.class} #{to_s}>) end |
#seconds? ⇒ Boolean
Whether both longitude and latitude have zero DMS seconds (which may indicate rounded or estimated coordinates).
97 98 99 |
# File 'lib/aixm/xy.rb', line 97 def seconds? !(long.to_dms[-6,5].to_f.zero? && lat.to_dms[-6,5].to_f.zero?) end |
#to_point ⇒ AIXM::Component::Geometry::Point
Convert to point
104 105 106 |
# File 'lib/aixm/xy.rb', line 104 def to_point AIXM.point(xy: self) end |
#to_s ⇒ String
Returns human readable representation.
47 48 49 |
# File 'lib/aixm/xy.rb', line 47 def to_s [lat(:ofmx), long(:ofmx)].join(' '.freeze) end |