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: []
         |