vector_geometry 0.0.1

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.
data/COPYING ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 by Andrew Berkeley (andrew.berkeley.is@googlemail.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
20
+
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Add dependencies to develop your gem here.
4
+ # Include everything needed to run rake, tests, features, etc.
5
+ group :development do
6
+ gem "jeweler", "~> 1.6.4"
7
+ gem 'rspec', '~> 2.6.0'
8
+ gem 'rdoc'
9
+ end
@@ -0,0 +1,153 @@
1
+ Vector geometry
2
+ ========
3
+
4
+ Author: Andrew Berkeley (andrew.berkeley.is@googlemail.com)
5
+
6
+ Introduction
7
+ ------------
8
+ This library provides an interface for handling vector geometry in 2- and 3-dimensional space.
9
+
10
+ The following classes are defined
11
+
12
+ <table>
13
+ <tr>
14
+ <td>Geometry::Vector</td>
15
+ <td> Basic 2- or 3D vector and operations</td>
16
+ </tr>
17
+ <tr>
18
+ <td>Geometry::GeoVector</td>
19
+ <td>Subclass of Vector providing additional geometric operations relating to the surface of a spheroid</td>
20
+ </tr>
21
+ <tr>
22
+ <td>Geometry::EarthVector</td>
23
+ <td>Subclass of GeoVector relating specifically to Earth</td>
24
+ </tr>
25
+ <tr>
26
+ <td>Geometry::Spheroid::Base</td>
27
+ <td>Create a representation of an arbitrary spheriod for associating with a given instance of GeoVector</td>
28
+ </tr>
29
+ </table>
30
+
31
+ For example, calculating the distance between two points on the Earth's surface
32
+
33
+ ```ruby
34
+ # Instantiate using geographic coordinates.
35
+ vector_1 = Geometry::EarthVector.from_geographic(80.0,0.0) #=> <EarthVector [1111.1648732245053, 0.0, 6259.542946575613]>
36
+ vector_2 = Geometry::EarthVector.from_geographic(80.0,1.0) #=> <EarthVector [1110.9956374322653, 19.392500986346672, 6259.542946575613]>
37
+
38
+ # Distance across 1 degree longitude at latitude of 80 degrees (km)
39
+ vector_1.great_circle_distance(vector_2) #=> 19.43475314292549
40
+ ```
41
+
42
+ Or the distance of point from a line described by two points
43
+ ```ruby
44
+ vector_3 = Geometry::EarthVector.from_geographic(75.0,5.0) #=> <EarthVector [1649.6615168294907, 144.3266813775607, 6138.7656676742445]>
45
+
46
+ vector_3.great_circle_distance_from_arc(vector_1,vector_2) #=> 567.3634356328112
47
+
48
+ ```
49
+
50
+ Vector
51
+ ------
52
+
53
+ Basic vector operations can be performed as follows.
54
+
55
+ Initialize a vector.
56
+
57
+ ```ruby
58
+ # 2D - pass x, y
59
+ vector = Geometry::Vector.new(15,20)
60
+
61
+ # 3D - pass x, y, z
62
+ vector = Geometry::Vector.new(15,20,4)
63
+
64
+ # 2D - pass magnitude and angle
65
+ vector = Geometry::Vector.from_polar(25, Math::PI)
66
+ ```
67
+
68
+ Vector attributes.
69
+
70
+ ```ruby
71
+ vector = Geometry::Vector.new(15,20,4)
72
+
73
+ vector.x #=> 15
74
+ vector.y #=> 20
75
+ vector.z #=> 4
76
+
77
+ ```
78
+
79
+ Vector operations.
80
+
81
+ ```ruby
82
+
83
+ vector = Geometry::Vector.new(3,4,5)
84
+
85
+ # Magnitude
86
+ vector.magnitude #=> 7.0710678118654755
87
+
88
+ # Normalize
89
+ vector.normalize #=> <Vector [0.4242640687119285, 0.565685424949238, 0.7071067811865475]>
90
+
91
+ vector_1 = Geometry::Vector.new(2,2,1)
92
+ vector_2 = Geometry::Vector.new(2,3,10)
93
+
94
+ # Addition
95
+ vector_1 + vector_2 #=> <Vector [4.0, 5.0, 11.0]>
96
+
97
+ # Subtraction
98
+ vector_1 - vector_2 #=> <Vector [0.0, -1.0, -9.0]>
99
+
100
+ # Multiply by scalar value
101
+ vector_1 * 4 #=> <Vector [8.0, 8.0, 4.0]>
102
+
103
+ # Divide by scalar value
104
+ vector * 4 #=> <Vector [0.5, 0.5, 0.25]>
105
+
106
+ # Calculate dot product of 2 vectors
107
+ vector_1.dot(vector_2) #=> 20.0
108
+
109
+ # Calculate cross product of 2 vectors
110
+ vector_1.cross(vector_2) #=> <Vector [17.0, -18.0, 2.0]>
111
+
112
+ # Calculate angle between 2 vectors (in radians)
113
+ vector_1.angle(vector_2) #=> 0.8929110789963546
114
+
115
+ ```
116
+
117
+ Compare vectors.
118
+
119
+ ```ruby
120
+
121
+ # Are two vectors parallel or orthogonal?
122
+ vector_1 = Geometry::Vector.new(10,0,0)
123
+ vector_2 = Geometry::Vector.new(20,0,0)
124
+ vector_3 = Geometry::Vector.new(0,10,0)
125
+
126
+ vector_1.parallel?(vector_2) #=> true
127
+ vector_1.parallel?(vector_3) #=> false
128
+
129
+ vector_1.orthogonal?(vector_2) #=> false
130
+ vector_1.orthogonal?(vector_3) #=> true
131
+
132
+ # Are two vectors equal
133
+ vector_1 == vector_2 #=> false
134
+ ```
135
+
136
+ Contributing
137
+ ------------
138
+
139
+ If you find a bug or think that you improve on the code, feel free to contribute.
140
+
141
+ You can:
142
+
143
+ * Send the author a message ("andrew.berkeley.is@googlemail.com":mailto:andrew.berkeley.is@googlemail.com)
144
+ * Create an issue
145
+ * Fork the project and submit a pull request.
146
+
147
+
148
+ License
149
+ -------
150
+
151
+ © Copyright 2012 Andrew Berkeley.
152
+
153
+ Licensed under the MIT license (See COPYING file for details)
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+
6
+ begin
7
+ Bundler.setup(:default, :development)
8
+ rescue Bundler::BundlerError => e
9
+ $stderr.puts e.message
10
+ $stderr.puts "Run `bundle install` to install missing gems"
11
+ exit e.status_code
12
+ end
13
+
14
+ require 'rake'
15
+ require 'rspec'
16
+ require 'rspec/core/rake_task'
17
+
18
+ task :default => [:spec]
19
+
20
+ desc "Run specs"
21
+ RSpec::Core::RakeTask.new do |t|
22
+ # Put spec opts in a file named .rspec in root
23
+ end
24
+
25
+ require 'jeweler'
26
+
27
+ Jeweler::Tasks.new do |gem|
28
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
29
+ gem.name = "vector_geometry"
30
+ gem.homepage = "https://github.com/spatchcock/vector_geometry"
31
+ gem.license = "GNU Affero General Public License"
32
+ gem.summary = %Q{Cartesian and spherical geometry using vectors}
33
+ gem.description = %Q{Cartesian and spherical geometry using vectors}
34
+ gem.email = "andrew.berkeley.is@googlemail.com"
35
+ gem.authors = ["Andrew Berkeley"]
36
+ # dependencies defined in Gemfile
37
+ end
38
+
39
+ Jeweler::RubygemsDotOrgTasks.new
40
+
41
+ require 'rdoc/task'
42
+ RDoc::Task.new do |rd|
43
+ rd.title = "Vector Geometry"
44
+ rd.rdoc_dir = 'doc'
45
+ rd.main = "README"
46
+ rd.rdoc_files.include("README", "lib/**/*.rb")
47
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,47 @@
1
+ module Geometry
2
+
3
+ def self.deg_to_rad(deg)
4
+ deg * Math::PI / 180.0
5
+ end
6
+
7
+ def self.rad_to_deg(rad)
8
+ (rad * 180.0) / Math::PI
9
+ end
10
+
11
+ def self.haversine_distance(point_1,point_2,radius, options = {})
12
+ lat_1 = point_1[0]
13
+ lng_1 = point_1[1]
14
+ lat_2 = point_2[0]
15
+ lng_2 = point_2[1]
16
+
17
+ if options[:unit] = :deg
18
+ lat_1 = deg_to_rad(lat_1)
19
+ lng_1 = deg_to_rad(lng_1)
20
+ lat_2 = deg_to_rad(lat_2)
21
+ lng_2 = deg_to_rad(lng_2)
22
+ end
23
+
24
+ lat_diff = 0.5 * (lat_2 - lat_1);
25
+ lat_diff = Math.sin(lat_diff);
26
+ lat_diff = lat_diff * lat_diff;
27
+
28
+ lng_diff = 0.5 * (lng_2 - lng_1);
29
+ lng_diff = Math.sin(lng_diff);
30
+ lng_diff = lng_diff * lng_diff;
31
+
32
+ result = lat_diff;
33
+ result += Math.cos(lat_1) * Math.cos(lat_2) * lng_diff;
34
+ result = Math.sqrt(result);
35
+
36
+ return radius * 2 * Math.asin(result);
37
+
38
+ end
39
+
40
+ def self.pythagorean_distance(point_1, point_2)
41
+ x = point_2[0] - point_1[0]
42
+ y = point_2[1] - point_1[1]
43
+
44
+ Math.sqrt(x * x + y * y).abs
45
+ end
46
+
47
+ end
@@ -0,0 +1,106 @@
1
+ module Geometry
2
+
3
+ module Spheroid
4
+
5
+ # Ellipsoid - 3D analogue of an ellipse. Has 3 axis: a,b and c
6
+ # Spheroid - Ellipsoid with two equal semi-diameters (a = b)
7
+ # Sphere - Ellipsoid with three equal semi-diameters (a = b = c)
8
+ # Geoid -
9
+
10
+ # class Ellipsoid
11
+
12
+ # def initialize(a,b,c)
13
+ # @a_radius = a
14
+ # @b_radius = b
15
+ # @c_radius = c
16
+ # end
17
+
18
+ # def volume
19
+ # (4.0/3.0) * (Math::PI * a_radius * b_radius * c_radius)
20
+ # end
21
+
22
+ # end
23
+
24
+ class Base
25
+
26
+ attr_accessor :polar_radius # semi-minor axis
27
+ attr_accessor :equatorial_radius # semi-major axis
28
+ attr_accessor :unit
29
+
30
+ # Unit is not functional but is simply memoized so that the basis for any calculations
31
+ # is clear
32
+ def initialize(equatorial_radius, polar_radius, unit = :km)
33
+ @polar_radius = polar_radius
34
+ @equatorial_radius = equatorial_radius
35
+ @unit = unit
36
+ end
37
+
38
+ def mean_radius
39
+ # http://en.wikipedia.org/wiki/Earth_radius
40
+ @mean_radius ||= (@polar_radius + 2 * @equatorial_radius) / 3.0
41
+ end
42
+
43
+ def flattening
44
+ # http://en.wikipedia.org/wiki/Reference_ellipsoid
45
+ @flattening ||= (@equatorial_radius - @polar_radius) / @equatorial_radius
46
+ end
47
+
48
+ def inverse_flattening
49
+ @inverse_flattening ||= 1.0 / flattening
50
+ end
51
+
52
+ def flattening_complement_squared
53
+ # http://www.mathworks.co.uk/help/aeroblks/geodetictogeocentriclatitude.html
54
+ @flattening_complement_squared ||= (1.0 - flattening) * (1.0 - flattening)
55
+ end
56
+
57
+ def volume
58
+ @volume ||= (4.0 / 3.0) * (Math::PI * @polar_radius * @equatorial_radius ** 2)
59
+ end
60
+
61
+ # http://en.wikipedia.org/wiki/Earth_radius
62
+ def radius_at_geodetic_latitude(lat, options = {})
63
+ lat = Geometry.deg_to_rad(lat) unless options[:unit] == :radians
64
+
65
+ numerator = (@equatorial_radius**2 * Math.cos(lat))**2 + (@polar_radius**2 * Math.sin(lat))**2
66
+ denominator = (@equatorial_radius * Math.cos(lat))**2 + (@polar_radius * Math.sin(lat))**2
67
+
68
+ Math.sqrt(numerator/denominator)
69
+ end
70
+
71
+ def geodetic_to_geocentric_latitude(lat, options = {})
72
+ lat = Geometry.deg_to_rad(lat) unless options[:unit] == :radians
73
+
74
+ Math.atan(Math.tan(lat) * flattening_complement_squared)
75
+ end
76
+
77
+ # Invoke the haversine formula in the context of the spheroid represented by self
78
+ def haversine_distance(point_1, point_2, options = {})
79
+ Geometry.haversine_distance(point_1, point_2, mean_radius, options)
80
+ end
81
+
82
+ end
83
+
84
+ Mercury = Geometry::Spheroid::Base.new(2439.7, 2439.7)
85
+
86
+ Venus = Geometry::Spheroid::Base.new(6051.8, 6051.8)
87
+
88
+ Earth = Geometry::Spheroid::Base.new(6378.1370, 6356.7523)
89
+
90
+ Moon = Geometry::Spheroid::Base.new(1738.1, 1736.0)
91
+
92
+ Mars = Geometry::Spheroid::Base.new(3396.2, 3376.2)
93
+
94
+ Jupiter = Geometry::Spheroid::Base.new(71492, 66854)
95
+
96
+ Saturn = Geometry::Spheroid::Base.new(60268, 54364)
97
+
98
+ Uranus = Geometry::Spheroid::Base.new(25559, 24973)
99
+
100
+ Neptune = Geometry::Spheroid::Base.new(24764, 24341)
101
+
102
+ Pluto = Geometry::Spheroid::Base.new(1195, 1195)
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,29 @@
1
+ module Geometry
2
+
3
+ module Spheroid
4
+
5
+ class Sphere < Spheroid::Base
6
+
7
+ def initialize(radius, unit = :km)
8
+ super(radius,radius,unit)
9
+ end
10
+
11
+ def radius
12
+ @equatorial_radius
13
+ end
14
+
15
+ def diameter
16
+ @diameter ||= radius * 2.0
17
+ end
18
+
19
+ def circumference
20
+ @circumference ||= 2.0 * Math::PI * radius
21
+ end
22
+
23
+ def surface_area
24
+ @surface_area ||= 4.0 * (Math::PI * radius ** 2)
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ module Geometry
2
+
3
+ class EarthVector < GeoVector
4
+ @@spheroid = Geometry::Spheroid::Earth
5
+ end
6
+
7
+ end
@@ -0,0 +1,234 @@
1
+ module Geometry
2
+
3
+ class GeoVector < Vector
4
+
5
+ @@spheroid = nil
6
+
7
+ def self.from_great_circle_intersection(vector_1,vector_2,vector_3,vector_4)
8
+ normal_to_great_circle_1 = vector_1.cross_normal(vector_2)
9
+ normal_to_great_circle_2 = vector_3.cross_normal(vector_4)
10
+
11
+ unit_vector = normal_to_great_circle_1.cross_normal(normal_to_great_circle_2)
12
+
13
+ if @@spheroid
14
+ unit_vector.scale(@@spheroid.mean_radius)
15
+ else
16
+ unit_vector
17
+ end
18
+ end
19
+
20
+ # Return a 3-dimensional cartesian vector representing the given latitude and longitude.
21
+ def self.from_geographic(lat, lng, options = {})
22
+
23
+ spheroid = @@spheroid || options[:spheroid]
24
+
25
+ unless options[:unit] == :radians
26
+ lat = Geometry.deg_to_rad(lat)
27
+ lng = Geometry.deg_to_rad(lng)
28
+ end
29
+
30
+ # Convert the geodetic latitude to geocentric if required
31
+ geocentric_latitude = options[:geocentric] ? lat : spheroid.geodetic_to_geocentric_latitude(lat, :unit => :radians)
32
+
33
+ # Find the projection of the point on the equatorial plane.
34
+ equatorial_plane_projection = Math.cos(geocentric_latitude)
35
+
36
+ x = Math.cos(lng) * equatorial_plane_projection
37
+ y = Math.sin(lng) * equatorial_plane_projection
38
+ z = Math.sin(geocentric_latitude)
39
+
40
+ unit_vector = self.new(x,y,z)
41
+
42
+ if options[:unit_vector]
43
+ unit_vector
44
+ else
45
+ raise ArgumentError, "No spheroid defined" unless spheroid
46
+
47
+ geodetic_radius = spheroid.radius_at_geodetic_latitude(lat, :unit => :radians)
48
+ unit_vector.scale(geodetic_radius)
49
+ end
50
+ end
51
+
52
+ attr_accessor :geodetic_radius
53
+ attr_accessor :latitude
54
+ attr_accessor :longitude
55
+
56
+ def latitude(options = {})
57
+ @latitude ||= begin
58
+ lat = Math.atan2(@z,@x)
59
+
60
+ lat = Math::PI - lat if lat > Math::PI/2.0
61
+ lat = lat.abs if lat == -0.0
62
+
63
+ lat
64
+ end
65
+
66
+ options[:unit] == :radians ? @latitude : Geometry.rad_to_deg(@latitude)
67
+ end
68
+
69
+ def longitude(options = {})
70
+ @longitude ||= Math.atan2(@y,@x)
71
+
72
+ options[:unit] == :deg ? Geometry.rad_to_deg(@longitude) : @longitude
73
+ end
74
+
75
+ def geodetic_radius(spheroid = @@spheroid)
76
+ @geodetic_radius ||= spheroid.radius_at_geodetic_latitude(latitude)
77
+ end
78
+
79
+ def antipode
80
+ scale(-1.0)
81
+ end
82
+
83
+ def mean_geodetic_radius(other)
84
+ (self.geodetic_radius + other.geodetic_radius) / 2.0
85
+ end
86
+
87
+ def great_circle_distance(other, options = {})
88
+
89
+ angular_distance = angle(other)
90
+
91
+ if @@spheroid && !options[:unit_vector]
92
+ if options[:use_mean_geodetic_radius]
93
+ return angular_distance * mean_geodetic_radius(other)
94
+ else
95
+ return angular_distance * @@spheroid.mean_radius
96
+ end
97
+ else
98
+ angular_distance
99
+ end
100
+ end
101
+
102
+ # Calculate the distance of self from a great circle defined by two points.
103
+ def great_circle_distance_from_great_circle(point_a,point_b)
104
+
105
+ # The shortest distance from a great circle is the perpendicular distance.
106
+
107
+ # Find the vector which is normal to the plane described by the (curved) line together
108
+ # with the origin.
109
+
110
+ normal_to_line = point_a.cross_normal(point_b).scale(@@spheroid.mean_radius)
111
+
112
+ # The line between self and the normal vector is perpendicular to the line.
113
+ #
114
+ # Next, find the intersection between the two lines which represents the shortest distance
115
+ # from self to the line.
116
+
117
+ intersection = GeoVector.from_great_circle_intersection(point_a, point_b, self, normal_to_line)
118
+
119
+ # There are actually two valid intersections (which are antipodes of one another) and we have
120
+ # found one.
121
+ #
122
+ # Return the smallest distance from self to either intersection
123
+
124
+ [self.great_circle_distance(intersection), self.great_circle_distance(intersection.antipode)].min
125
+ end
126
+
127
+ # Calculate the distance of self from a finite line segment defined by two points
128
+ def great_circle_distance_from_arc(point_a,point_b, options = {})
129
+
130
+ # Distance from a line segment is similar to the distance from the infinte line (above)
131
+ # with a modification.
132
+ #
133
+ # The distance from an infinitely long line calculates the shortest distance to an infintitely
134
+ # long line. This is the perpendicular distance. In the case of the line segment, this perpendicular
135
+ # may or may not fall on the line segment part of the more general infinte line.
136
+ #
137
+ # If it does, we can keep the perpendicular distance. If not, the shortest distance will be
138
+ # to either of the two line segments end. Determine which.
139
+
140
+ normal_to_line = point_a.cross_normal(point_b).scale(@@spheroid.mean_radius)
141
+ intersection = GeoVector.from_great_circle_intersection(point_a, point_b, self, normal_to_line)
142
+
143
+ # The point which intersects the two great circles is actually one of two such unique points. We
144
+ # know both fall on the great circle described by the points but we need to establish whether either
145
+ # fall on our line segment, i.e. between them. If so, we can take the perpendicular distance from
146
+ # the intersection point.
147
+
148
+ line_length = point_a.great_circle_distance(point_b, options)
149
+
150
+ if line_length >= intersection.great_circle_distance(point_a, options) &&
151
+ line_length >= intersection.great_circle_distance(point_b, options)
152
+
153
+ # The intersection falls on the line segment.
154
+ # Calculate the perpendicular distance.
155
+
156
+ return self.great_circle_distance(intersection, options)
157
+
158
+ elsif line_length >= intersection.antipode.great_circle_distance(point_a, options) &&
159
+ line_length >= intersection.antipode.great_circle_distance(point_b, options)
160
+
161
+ # The *other* intersection falls on the line segment.
162
+ # Calculate the perpendicular distance.
163
+
164
+ return self.great_circle_distance(intersection.antipode, options)
165
+
166
+ else
167
+
168
+ # Neither intersection falls on the line segment.
169
+ # Calculate the distance to the closer of the line segment ends.
170
+
171
+ return [ self.great_circle_distance(point_a, options), self.great_circle_distance(point_b, options) ].min
172
+ end
173
+ end
174
+
175
+ # Supports a polyline based on either cartesian or angular coordinates. Specify which using the :basis
176
+ # option
177
+ #
178
+ # :cartesian => cartesian coordinates (x,y)
179
+ #
180
+ # otherwise lat/lng pairs are assumed
181
+ #
182
+ def great_circle_distance_from_polyline(polyline, options = {})
183
+
184
+ constructor = Proc.new do |vertex|
185
+ if options[:basis] == :cartesian
186
+ self.class.new(vertex[0], vertex[1], vertex[2])
187
+ else
188
+ self.class.from_geographic(vertex[0], vertex[1], options)
189
+ end
190
+ end
191
+
192
+ # memoize the last processed point as both array and vector objects
193
+ last_array = polyline.first
194
+ last_vector = constructor.call(last_array)
195
+
196
+ minimum_distance = 999999999999
197
+
198
+ for vertex in polyline[1..-1]
199
+
200
+ next if vertex == last_array
201
+
202
+ start_vector = last_vector
203
+ end_vector = constructor.call(vertex)
204
+
205
+ this_segment_distance = great_circle_distance_from_arc(start_vector, end_vector, options)
206
+
207
+ if(this_segment_distance < minimum_distance)
208
+ minimum_distance = this_segment_distance
209
+ end
210
+
211
+ last_array = vertex
212
+ last_vector = end_vector
213
+ end
214
+
215
+ return minimum_distance
216
+ end
217
+
218
+ # Convert self to a geographic lat/lng pair.
219
+ def to_geographic(options = {})
220
+ [latitude(options), longitude(options)]
221
+ end
222
+
223
+ protected
224
+
225
+ # Return true of point is closer to both points than the points are to each other
226
+ def within_both_radii?(point_a,point_b)
227
+ line_length = point_a.great_circle_distance(point_b)
228
+ self.great_circle_distance(point_a) < line_length && self.great_circle_distance(point_b) < line_length
229
+ end
230
+
231
+ end
232
+
233
+ end
234
+