Class: Geospatial::Location

Inherits:
Object
  • Object
show all
Defined in:
lib/geospatial/location.rb

Overview

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

Constant Summary collapse

WGS84_A =

WGS 84 semi-major axis constant in meters

6378137.0
WGS84_B =

WGS 84 semi-minor axis constant in meters

6356752.3
EARTH_RADIUS =
(WGS84_A + WGS84_B) / 2.0
WGS84_E =

WGS 84 eccentricity

8.1819190842622e-2
R2D =

Radians to degrees multiplier

(180.0 / Math::PI)
D2R =
(Math::PI / 180.0)
MIN_LONGITUDE =
-180 * D2R
MAX_LONGITUDE =
180 * D2R
VALID_LONGITUDE =
MIN_LONGITUDE...MAX_LONGITUDE
MIN_LATITUDE =
-90.0 * D2R
MAX_LATITUDE =
90 * D2R
VALID_LATITUDE =
MIN_LATITUDE...MAX_LATITUDE

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(longitude, latitude) ⇒ Location

Returns a new instance of Location.



72
73
74
75
# File 'lib/geospatial/location.rb', line 72

def initialize(longitude, latitude)
	@longitude = longitude
	@latitude = latitude
end

Instance Attribute Details

#latitudeObject (readonly)

-90 -> 90 (equivalent to y)



92
93
94
# File 'lib/geospatial/location.rb', line 92

def latitude
  @latitude
end

#longitudeObject (readonly)

-180 -> 180 (equivalent to x)



91
92
93
# File 'lib/geospatial/location.rb', line 91

def longitude
  @longitude
end

Class Method Details

.from_ecef(x, y, z) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/geospatial/location.rb', line 49

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

Instance Method Details

#-(other) ⇒ Object



161
162
163
# File 'lib/geospatial/location.rb', line 161

def - other
	Distance.new(self.distance_from(other))
end

#bounding_box(distance, radius = EARTH_RADIUS) ⇒ Object

Raises:

  • (ArgumentError)


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/geospatial/location.rb', line 95

def bounding_box(distance, radius = EARTH_RADIUS)
	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) ⇒ Object

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



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/geospatial/location.rb', line 145

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 = EARTH_RADIUS * c
	
	return d
end

#to_aObject



81
82
83
# File 'lib/geospatial/location.rb', line 81

def to_a
	[@longitude, @latitude]
end

#to_ecefObject

Converts latitude, longitude to ECEF coordinate system



128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/geospatial/location.rb', line 128

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_sObject Also known as: inspect



85
86
87
# File 'lib/geospatial/location.rb', line 85

def to_s
	"#{self.class}#{self.to_a.inspect}"
end

#valid?Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/geospatial/location.rb', line 77

def valid?
	VALID_LONGITUDE.include?(longitude) and VALID_LATITUDE.include?(latitude)
end