class Geospatial::Location

This location is specifically relating to a WGS84 coordinate on Earth.

Attributes

latitude[R]
longitude[R]

Public Class Methods

from_ecef(x, y, z) click to toggle source
# File lib/geospatial/location.rb, line 50
def from_ecef(x, y, z)
        # Constants (WGS ellipsoid)
        a = WGS84_A
        e = WGS84_E
                
        b = Math::sqrt((a*a) * (1.0-(e*e)))
        ep = Math::sqrt(((a*a)-(b*b))/(b*b))
        
        p = Math::sqrt((x*x)+(y*y))
        th = Math::atan2(a*z, b*p)
        
        lon = Math::atan2(y, x)
        lat = Math::atan2((z+ep*ep*b*(Math::sin(th) ** 3)), (p-e*e*a*(Math::cos(th)**3)))
        
        # n = a / Math::sqrt(1.0-e*e*(Math::sin(lat) ** 2))
        # alt = p / Math::cos(lat)-n
        
        return self.new(lat*R2D, lon*R2D)
end
new(longitude, latitude) click to toggle source
# File lib/geospatial/location.rb, line 73
def initialize(longitude, latitude)
        @longitude = longitude
        @latitude = latitude
end

Public Instance Methods

-(other) click to toggle source
# File lib/geospatial/location.rb, line 202
def - other
        Distance.new(self.distance_from(other))
end
<=>(other) click to toggle source
# File lib/geospatial/location.rb, line 100
def <=> other
        to_a <=> other.to_a
end
bearing_from(other) click to toggle source

@return [Numeric] bearing in degrees.

# File lib/geospatial/location.rb, line 177
def bearing_from(other)
        lon1 = other.longitude * D2R 
        lat1 = other.latitude * D2R 
        lon2 = self.longitude * D2R 
        lat2 = self.latitude * D2R 
        
        return Math::atan2(
                Math::sin(lon2 - lon1) * Math::cos(lat2),
                Math::cos(lat1) * Math::sin(lat2) - Math::sin(lat1) * Math::cos(lat2) * Math::cos(lon2-lon1)
        ) * R2D
end
bounding_box(distance, radius = R) click to toggle source

janmatuschek.de/LatitudeLongitudeBoundingCoordinates

# File lib/geospatial/location.rb, line 110
def bounding_box(distance, radius = R)
        raise ArgumentError.new("Invalid distance or radius") if distance < 0 or radius < 0

        # angular distance in radians on a great circle
        angular_distance = distance / radius

        min_latitude = (self.latitude * D2R) - angular_distance
        max_latitude = (self.latitude * D2R) + angular_distance

        if min_latitude > MIN_LATITUDE and max_latitude < MAX_LATITUDE
                longitude_delta = Math::asin(Math::sin(angular_distance) / Math::cos(self.latitude * D2R))
                
                min_longitude = (self.longitude * D2R) - longitude_delta
                min_longitude += 2.0 * Math::PI if (min_longitude < MIN_LONGITUDE)
                
                max_longitude = (self.longitude * D2R) + longitude_delta;
                max_longitude -= 2.0 * Math::PI if (max_longitude > MAX_LONGITUDE)
        else
                # a pole is within the distance
                min_latitude = [min_latitude, MIN_LATITUDE].max
                max_latitude = [max_latitude, MAX_LATITUDE].min
                
                min_longitude = MIN_LONGITUDE
                max_longitude = MAX_LONGITUDE
        end
        
        return {
                :latitude => Range.new(min_latitude * R2D, max_latitude * R2D),
                :longitude => Range.new(min_longitude * R2D, max_longitude * R2D),
        }
end
distance_from(other) click to toggle source

calculate distance in metres between us and something else ref: codingandweb.blogspot.co.nz/2012/04/calculating-distance-between-two-points.html

# File lib/geospatial/location.rb, line 160
def distance_from(other)
        rlong1 = self.longitude * D2R
        rlat1 = self.latitude * D2R
        rlong2 = other.longitude * D2R
        rlat2 = other.latitude * D2R
        
        dlon = rlong1 - rlong2
        dlat = rlat1 - rlat2
        
        a = Math::sin(dlat/2) ** 2 + Math::cos(rlat1) * Math::cos(rlat2) * Math::sin(dlon/2) ** 2
        c = 2 * Math::atan2(Math::sqrt(a), Math::sqrt(1-a))
        d = R * c
        
        return d
end
inspect()
Alias for: to_s
location_by(bearing, distance) click to toggle source

@param distance [Numeric] distance in meters. @param bearing [Numeric] bearing in degrees.

# File lib/geospatial/location.rb, line 191
def location_by(bearing, distance)
        lon1 = self.longitude * D2R
        lat1 = self.latitude * D2R
        
        lat2 = Math::asin(Math::sin(lat1)*Math::cos(distance/R) + Math::cos(lat1)*Math::sin(distance/R)*Math::cos(bearing * D2R))
        
        lon2 = lon1 + Math::atan2(Math::sin(bearing * D2R)*Math::sin(distance/R)*Math::cos(lat1), Math::cos(distance/R)-Math::sin(lat1)*Math::sin(lat2))
        
        return self.class.new(lon2 * R2D, lat2 * R2D)
end
midpoints_to(other, count) { |location_by(bearing, step * i)| ... } click to toggle source

Compute count midpoints between self and other. @param count [Integer] the number of segments to generate.

# File lib/geospatial/location.rb, line 208
def midpoints_to(other, count)
        return to_enum(:midpoints_to, other, count) unless block_given?
        
        distance = other.distance_from(self)
        bearing = other.bearing_from(self)
        
        step = distance / count
        
        (1...count).each do |i|
                yield self.location_by(bearing, step * i)
        end
end
to_a() click to toggle source
# File lib/geospatial/location.rb, line 82
def to_a
        [@longitude, @latitude]
end
to_ary() click to toggle source
# File lib/geospatial/location.rb, line 86
def to_ary
        to_a
end
to_ecef() click to toggle source

Converts latitude, longitude to ECEF coordinate system

# File lib/geospatial/location.rb, line 143
def to_ecef
        clon = Math::cos(lon * D2R)
        slon = Math::sin(lon * D2R)
        clat = Math::cos(lat * D2R)
        slat = Math::sin(lat * D2R)

        n = WGS84_A / Math::sqrt(1.0 - WGS84_E * WGS84_E * slat * slat)

        x = n * clat * clon
        y = n * clat * slon
        z = n * (1.0 - WGS84_E * WGS84_E) * slat
        
        return x, y, z
end
to_h() click to toggle source
# File lib/geospatial/location.rb, line 90
def to_h
        {latitude: @latitude, longitude: @longitude}
end
to_s() click to toggle source
# File lib/geospatial/location.rb, line 94
def to_s
        "#{self.class}[#{self.longitude.to_f}, #{self.latitude.to_f}]"
end
Also aliased as: inspect
valid?() click to toggle source
# File lib/geospatial/location.rb, line 78
def valid?
        VALID_LONGITUDE.include?(longitude) and VALID_LATITUDE.include?(latitude)
end