geodesics 1.0.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.
- 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: []
|