# Class: AIXM::XY

Inherits:
Object
show all
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.

### 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

Examples:

All of the below are equivalent

``````AIXM.xy(lat: 11.375955555555556, long: -111.37595555555555)
AIXM.xy(lat: %q(11°22'33.44"), long: %q(-111°22'33.44"))
AIXM.xy(lat: %q(11°22'33.44N"), long: %q(111°22'33.44W"))
AIXM.xy(lat: '112233.44N', long: '1112233.44W')``````

## Constant Summary collapse

meters

`6_371_008.8`

• Latitude.

• Longitude.

## Instance Method Summary collapse

• Calculate a new point by adding the distance in the given bearing.

• Bearing to another point.

• Distance to another point as calculated by the Haversine formula.

• constructor

See the overview for examples.

• Whether both longitude and latitude have zero DMS seconds (which may indicate rounded or estimated coordinates).

• Convert to point.

• Human readable representation.

## Constructor Details

### #initialize(lat:, long:) ⇒ XY

See the overview for examples.

 ``` 37 38 39``` ```# File 'lib/aixm/xy.rb', line 37 def initialize(lat:, long:) self.lat, self.long = lat, long end```

## Instance Attribute Details

### #lat ⇒ String, Float #lat=(value) ⇒ Object

Latitude

• #latString, Float

Parameters:

• schema (Symbol, nil)

either `:aixm` or `:ofmx` or `nil`

Returns:

• (String, Float)
• #lat=(value) ⇒ Object

Parameters:

• value (String, Numeric)
 ``` 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

• #longString, Float

Parameters:

• schema (Symbol, nil)

either `:aixm` or `:ofmx` or `nil`

Returns:

• (String, Float)
• #long=(value) ⇒ Object

Parameters:

• value (String, Numeric)
 ``` 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

• 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

Parameters:

Returns:

 ``` 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

Parameters:

Returns:

 ``` 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

Parameters:

Returns:

 ``` 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

Returns:

• (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).

Returns:

• (Boolean)
 ``` 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

Returns:

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

Returns:

• (String)

 ``` 47 48 49``` ```# File 'lib/aixm/xy.rb', line 47 def to_s [lat(:ofmx), long(:ofmx)].join(' '.freeze) end```