Class: Terraformer::Coordinate

Inherits:
Object
  • Object
show all
Defined in:
lib/terraformer/coordinate.rb

Constant Summary collapse

EARTH_MEAN_RADIUS =
6371009.to_d

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(_x, _y = nil, _z = nil) ⇒ Coordinate

Returns a new instance of Coordinate.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/terraformer/coordinate.rb', line 43

def initialize _x, _y = nil, _z = nil
  @ary = Array.new 3
  case _x
  when Array
    raise ArgumentError if _y
    self.x = _x[0]
    self.y = _x[1]
    self.z = _x[2] if _x[2]

  when Coordinate
    raise ArgumentError if _y
    self.x = _x.x
    self.y = _x.y
    self.z = _x.z if _x.z

  when Numeric, String
    raise ArgumentError unless _y
    self.x = _x
    self.y = _y
    self.z = _z if _z
  else
    raise ArgumentError.new "invalid argument: #{_x}"
  end
end

Instance Attribute Details

#aryObject

array holding the numeric coordinate values



12
13
14
# File 'lib/terraformer/coordinate.rb', line 12

def ary
  @ary
end

#crsObject

Returns the value of attribute crs.



9
10
11
# File 'lib/terraformer/coordinate.rb', line 9

def crs
  @crs
end

Class Method Details

.big_decimal(n) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/terraformer/coordinate.rb', line 28

def big_decimal n
  case n
  when String
    BigDecimal(n)
  when BigDecimal
    n
  when Numeric
    BigDecimal(n.to_s)
  else
    raise ArgumentError
  end
end

.from_array(a) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
# File 'lib/terraformer/coordinate.rb', line 16

def from_array a
  if Coordinate === a
    a.dup
  elsif Numeric === a[0]
    Coordinate.new a
  elsif Array === a
    a.map {|e| Coordinate.from_array e }
  else
    raise ArgumentError
  end
end

Instance Method Details

#+(obj) ⇒ Object



192
193
194
# File 'lib/terraformer/coordinate.rb', line 192

def + obj
  arithmetic :+, obj
end

#-(obj) ⇒ Object



196
197
198
# File 'lib/terraformer/coordinate.rb', line 196

def - obj
  arithmetic :-, obj
end

#<=>(other) ⇒ Object

Raises:

  • (ArgumentError)


169
170
171
172
173
174
175
176
177
178
# File 'lib/terraformer/coordinate.rb', line 169

def <=> other
  raise ArgumentError unless Coordinate === other
  dx = x - other.x
  dy = y - other.y
  case
  when dx > dy; 1
  when dx < dy; -1
  else;         0
  end
end

#==(other) ⇒ Object



102
103
104
105
106
107
108
109
110
111
# File 'lib/terraformer/coordinate.rb', line 102

def == other
  case other
  when Array
    @ary == other
  when Coordinate
    @ary == other.ary
  else
    false
  end
end

#[](index) ⇒ Object



98
99
100
# File 'lib/terraformer/coordinate.rb', line 98

def [] index
  @ary[index]
end

#buffer(radius, resolution = DEFAULT_BUFFER_RESOLUTION) ⇒ Object



158
159
160
161
162
163
164
165
166
167
# File 'lib/terraformer/coordinate.rb', line 158

def buffer radius, resolution = DEFAULT_BUFFER_RESOLUTION
  center = to_mercator unless mercator?
  coordinates = (1..resolution).map {|step|
    radians = step.to_d * (360.to_d / resolution.to_d) * PI / 180.to_d
    [center.x + radius.to_d * BigMath.cos(radians, PRECISION),
     center.y + radius.to_d * BigMath.sin(radians, PRECISION)]
  }
  coordinates << coordinates[0]
  Polygon.new(coordinates).to_geographic
end

#distance_and_bearing_to(obj) ⇒ Object

Raises:

  • (ArgumentError)


231
232
233
234
# File 'lib/terraformer/coordinate.rb', line 231

def distance_and_bearing_to obj
  raise ArgumentError unless Coordinate === obj
  Geodesic.compute_distance_and_bearing y, x, obj.y, obj.x
end

#distance_to(obj) ⇒ Object



236
237
238
# File 'lib/terraformer/coordinate.rb', line 236

def distance_to obj
  distance_and_bearing_to(obj)[:distance]
end

#dupObject



68
69
70
# File 'lib/terraformer/coordinate.rb', line 68

def dup
  Coordinate.new @ary.dup
end

#euclidean_distance_to(obj) ⇒ Object



207
208
209
# File 'lib/terraformer/coordinate.rb', line 207

def euclidean_distance_to obj
  BigMath.sqrt squared_euclidean_distance_to(obj), PRECISION
end

#final_bearing_to(obj) ⇒ Object



244
245
246
# File 'lib/terraformer/coordinate.rb', line 244

def final_bearing_to obj
  distance_and_bearing_to(obj)[:bearing][:final]
end

#geographic?Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/terraformer/coordinate.rb', line 150

def geographic?
  crs.nil? or crs == GEOGRAPHIC_CRS
end

#haversine_distance_to(other) ⇒ Object

Raises:

  • (ArgumentError)


211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/terraformer/coordinate.rb', line 211

def haversine_distance_to other
  raise ArgumentError unless Coordinate === other

  d_lat = (self.y - other.y).to_rad
  d_lon = (self.x - other.x).to_rad

  lat_r = self.y.to_rad
  other_lat_r = other.y.to_rad

  a = BigMath.sin(d_lat / 2, PRECISION)**2 +
      BigMath.sin(d_lon / 2, PRECISION)**2 *
      BigMath.cos(lat_r, PRECISION) * BigMath.cos(other_lat_r, PRECISION)

  y = BigMath.sqrt a, PRECISION
  x = BigMath.sqrt (1 - a), PRECISION
  c = 2 * BigMath.atan2(y, x, PRECISION)

  c * EARTH_MEAN_RADIUS
end

#initial_bearing_to(obj) ⇒ Object



240
241
242
# File 'lib/terraformer/coordinate.rb', line 240

def initial_bearing_to obj
  distance_and_bearing_to(obj)[:bearing][:initial]
end

#inspectObject



113
114
115
# File 'lib/terraformer/coordinate.rb', line 113

def inspect
  "#<Terraformer::Coordinate lon=#{lon.to_s 'F'} lat=#{lat.to_s 'F'} #{z if z }>"
end

#mercator?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/terraformer/coordinate.rb', line 154

def mercator?
  crs == MERCATOR_CRS
end

#squared_euclidean_distance_to(obj) ⇒ Object

Raises:

  • (ArgumentError)


200
201
202
203
204
205
# File 'lib/terraformer/coordinate.rb', line 200

def squared_euclidean_distance_to obj
  raise ArgumentError unless Coordinate === obj
  dx = obj.x - x
  dy = obj.y - y
  dx * dx + dy * dy
end

#to_geographicObject



117
118
119
120
121
122
123
124
125
126
127
# File 'lib/terraformer/coordinate.rb', line 117

def to_geographic
  xerd = (x / EARTH_RADIUS).to_deg
  _x = xerd - (((xerd + 180.0) / 360.0).floor * 360.0)
  _y = (
    (Math::PI / 2).to_d -
    (2 * BigMath.atan(BigMath.exp(-1.0 * y / EARTH_RADIUS, PRECISION), PRECISION))
  ).to_deg
  geog = self.class.new _x.round(PRECISION), _y.round(PRECISION)
  geog.crs = GEOGRAPHIC_CRS
  geog
end

#to_json(*args) ⇒ Object



142
143
144
# File 'lib/terraformer/coordinate.rb', line 142

def to_json *args
  @ary.compact.to_json(*args)
end

#to_mercatorObject



129
130
131
132
133
134
135
136
# File 'lib/terraformer/coordinate.rb', line 129

def to_mercator
  _x = x.to_rad * EARTH_RADIUS
  syr = BigMath.sin y.to_rad, PRECISION
  _y = (EARTH_RADIUS / 2.0) * BigMath.log((1.0 + syr) / (1.0 - syr), PRECISION)
  merc = self.class.new _x.round(PRECISION), _y.round(PRECISION)
  merc.crs = MERCATOR_CRS
  merc
end

#to_pointObject



146
147
148
# File 'lib/terraformer/coordinate.rb', line 146

def to_point
  Point.new self
end

#to_sObject



138
139
140
# File 'lib/terraformer/coordinate.rb', line 138

def to_s
  @ary.compact.join ','
end

#xObject Also known as: lon



72
73
74
# File 'lib/terraformer/coordinate.rb', line 72

def x
  @ary[0]
end

#x=(_x) ⇒ Object



77
78
79
# File 'lib/terraformer/coordinate.rb', line 77

def x= _x
  @ary[0] = Coordinate.big_decimal _x
end

#yObject Also known as: lat



81
82
83
# File 'lib/terraformer/coordinate.rb', line 81

def y
  @ary[1]
end

#y=(_y) ⇒ Object



86
87
88
# File 'lib/terraformer/coordinate.rb', line 86

def y= _y
  @ary[1] = Coordinate.big_decimal _y
end

#zObject



90
91
92
# File 'lib/terraformer/coordinate.rb', line 90

def z
  @ary[2]
end

#z=(_z) ⇒ Object



94
95
96
# File 'lib/terraformer/coordinate.rb', line 94

def z= _z
  @ary[2] = Coordinate.big_decimal _z
end