geodesics 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/geodesics.rb +34 -0
- data/lib/geodesics/central_angles/haversine.rb +18 -0
- data/lib/geodesics/central_angles/spherical.rb +16 -0
- data/lib/geodesics/central_angles/vincenty.rb +20 -0
- data/lib/geodesics/point.rb +47 -0
- data/lib/geodesics/strategies/lambert.rb +51 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9fb097bb88b35fc4b47610fbc4781aadebadbab28f6b4c207b144645515d9a19
|
4
|
+
data.tar.gz: 1f1c7ccb9105b0c3dcd8be45fb5bd512028721affd3cf65d59509f358cee92c5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e102a7f5f1158ae93228e37c1e667ac518f23b47683cf8626ca833f3482c94feb6002bc514c58ac91ebcc2c4e52083f32256c91e1fb4a6b7b615f539c657206b
|
7
|
+
data.tar.gz: 39a076d912a139be79544998462b247e6a425fd4ac7667e2a2dee6bafab64855fbbad0c7d18d21a2d2008b92da8627c6a13b9efc726175cc70b40a15664caf66
|
data/lib/geodesics.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'geodesics/strategies/lambert'
|
4
|
+
require 'geodesics/point'
|
5
|
+
require 'forwardable'
|
6
|
+
|
7
|
+
class Geodesics
|
8
|
+
class << self
|
9
|
+
extend Forwardable
|
10
|
+
def_delegators :new, :distance, :distance_degree, :distance_radian
|
11
|
+
end
|
12
|
+
|
13
|
+
STRATEGY = Strategies::Lambert.new
|
14
|
+
|
15
|
+
def initialize(strategy: STRATEGY)
|
16
|
+
@strategy = strategy
|
17
|
+
end
|
18
|
+
|
19
|
+
def distance_radian(latitude1, longitude1, latitude2, longitude2)
|
20
|
+
@strategy.distance(
|
21
|
+
Radian.new(latitude1, longitude1),
|
22
|
+
Radian.new(latitude2, longitude2)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def distance_degree(latitude1, longitude1, latitude2, longitude2)
|
27
|
+
@strategy.distance(
|
28
|
+
Degree.new(latitude1, longitude1).to_radian,
|
29
|
+
Degree.new(latitude2, longitude2).to_radian
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
alias distance distance_degree
|
34
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Geodesics
|
4
|
+
module CentralAngles
|
5
|
+
# https://en.wikipedia.org/wiki/Versine#Haversine
|
6
|
+
class Haversine
|
7
|
+
def call(point1, point2)
|
8
|
+
2 * Math.asin(
|
9
|
+
Math.sqrt(
|
10
|
+
Math.sin((point1.latitude - point2.latitude).abs / 2)**2 +
|
11
|
+
Math.cos(point1.latitude) * Math.cos(point2.latitude) *
|
12
|
+
Math.sin((point1.longitude - point2.longitude).abs / 2)**2
|
13
|
+
)
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Geodesics
|
4
|
+
module CentralAngles
|
5
|
+
# https://en.wikipedia.org/wiki/Spherical_law_of_cosines
|
6
|
+
class Spherical
|
7
|
+
def call(point1, point2)
|
8
|
+
Math.acos(
|
9
|
+
Math.sin(point1.latitude) * Math.sin(point2.latitude) +
|
10
|
+
Math.cos(point1.latitude) * Math.cos(point2.latitude) *
|
11
|
+
Math.cos((point1.longitude - point2.longitude).abs)
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Geodesics
|
4
|
+
module CentralAngles
|
5
|
+
# https://en.wikipedia.org/wiki/Vincenty%27s_formulae
|
6
|
+
class Vincenty
|
7
|
+
def call(point1, point2)
|
8
|
+
delta_longitude = (point1.longitude - point2.longitude).abs
|
9
|
+
Math.atan(
|
10
|
+
Math.sqrt(
|
11
|
+
(Math.cos(point2.latitude) * Math.sin(delta_longitude))**2 +
|
12
|
+
(Math.cos(point1.latitude) * Math.sin(point2.latitude) - Math.sin(point1.latitude) * Math.cos(point2.latitude) * Math.cos(delta_longitude))**2
|
13
|
+
) / (
|
14
|
+
Math.sin(point1.latitude) * Math.sin(point2.latitude) + Math.cos(point1.latitude) * Math.cos(point2.latitude) * Math.cos(delta_longitude)
|
15
|
+
)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Geodesics
|
4
|
+
class Point
|
5
|
+
RADIAN = Math::PI / 180
|
6
|
+
DEGREE = 180 / Math::PI
|
7
|
+
|
8
|
+
attr_reader :latitude, :longitude
|
9
|
+
|
10
|
+
def initialize(latitude, longitude)
|
11
|
+
@latitude = latitude
|
12
|
+
@longitude = longitude
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
latitude == other.latitude && longitude == other.longitude
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_radian
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_degree
|
24
|
+
self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Radian < Point
|
29
|
+
def to_degree
|
30
|
+
Degree.new(@latitude * DEGREE, @longitude * DEGREE)
|
31
|
+
end
|
32
|
+
|
33
|
+
def ==(other)
|
34
|
+
other.is_a?(Degree) ? super(other.to_radian) : super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Degree < Point
|
39
|
+
def to_radian
|
40
|
+
Radian.new(@latitude * RADIAN, @longitude * RADIAN)
|
41
|
+
end
|
42
|
+
|
43
|
+
def ==(other)
|
44
|
+
other.is_a?(Radian) ? super(other.to_degree) : super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'geodesics/central_angles/haversine'
|
4
|
+
|
5
|
+
class Geodesics
|
6
|
+
module Strategies
|
7
|
+
class Lambert
|
8
|
+
INVERSE_FLATTENING = 298.257223563 # WGS 84
|
9
|
+
FLATTENING = 1.0 / INVERSE_FLATTENING
|
10
|
+
EQUATORIAL_RADIUS = 6_378_137
|
11
|
+
CENTRAL_ANGLE = CentralAngles::Haversine.new
|
12
|
+
|
13
|
+
def initialize(
|
14
|
+
equatorial_radius: EQUATORIAL_RADIUS,
|
15
|
+
flattening: FLATTENING,
|
16
|
+
central_angle: CENTRAL_ANGLE
|
17
|
+
)
|
18
|
+
@equatorial_radius = equatorial_radius
|
19
|
+
@flattening = flattening
|
20
|
+
@central_angle = central_angle
|
21
|
+
end
|
22
|
+
|
23
|
+
def distance(point1, point2)
|
24
|
+
sigma = @central_angle.call(point1, point2)
|
25
|
+
beta1 = parametric_latitude(point1.latitude)
|
26
|
+
beta2 = parametric_latitude(point2.latitude)
|
27
|
+
p = (beta1 + beta2) / 2
|
28
|
+
q = (beta2 - beta1) / 2
|
29
|
+
x = (sigma - sin(sigma)) * sin(p)**2 * cos(q)**2 / cos(sigma / 2)**2
|
30
|
+
y = (sigma + sin(sigma)) * cos(p)**2 * sin(q)**2 / sin(sigma / 2)**2
|
31
|
+
@equatorial_radius * (sigma - @flattening * (x + y) / 2)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def parametric_latitude(latitude)
|
37
|
+
Math.atan((1 - @flattening) * Math.tan(latitude))
|
38
|
+
end
|
39
|
+
|
40
|
+
def sin(radian)
|
41
|
+
v = Math.sin(radian)
|
42
|
+
v < 1e-10 ? 1e-10 : v
|
43
|
+
end
|
44
|
+
|
45
|
+
def cos(radian)
|
46
|
+
v = Math.cos(radian)
|
47
|
+
v < 1e-10 ? 1e-10 : v
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: geodesics
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jian Weihang
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-05-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.11.3
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.11.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 12.3.2
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 12.3.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.68.1
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.68.1
|
55
|
+
description: geodesics calculates the geodesic distance between 2 points with latitude
|
56
|
+
and longitude on ellipsoid Earth using Lambert's formula.
|
57
|
+
email: tonytonyjan@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- lib/geodesics.rb
|
63
|
+
- lib/geodesics/central_angles/haversine.rb
|
64
|
+
- lib/geodesics/central_angles/spherical.rb
|
65
|
+
- lib/geodesics/central_angles/vincenty.rb
|
66
|
+
- lib/geodesics/point.rb
|
67
|
+
- lib/geodesics/strategies/lambert.rb
|
68
|
+
homepage: https://github.com/tonytonyjan/geodesics
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubygems_version: 3.0.2
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: geodesics calculates the geodesic distance between 2 points with latitude
|
91
|
+
and longitude on ellipsoid Earth using Lambert's formula.
|
92
|
+
test_files: []
|