Class: Geometry::GeoVector
- Defined in:
- lib/geometry/vector/geo_vector.rb
Direct Known Subclasses
Constant Summary collapse
- @@spheroid =
nil
Instance Attribute Summary collapse
-
#geodetic_radius(spheroid = @@spheroid) ⇒ Object
Returns the value of attribute geodetic_radius.
-
#latitude(options = {}) ⇒ Object
Returns the value of attribute latitude.
-
#longitude(options = {}) ⇒ Object
Returns the value of attribute longitude.
Attributes inherited from Vector
Class Method Summary collapse
-
.from_geographic(lat, lng, options = {}) ⇒ Object
Return a 3-dimensional cartesian vector representing the given latitude and longitude.
- .from_great_circle_intersection(vector_1, vector_2, vector_3, vector_4) ⇒ Object
Instance Method Summary collapse
- #antipode ⇒ Object
- #great_circle_distance(other, options = {}) ⇒ Object
-
#great_circle_distance_from_arc(point_a, point_b, options = {}) ⇒ Object
Calculate the distance of self from a finite line segment defined by two points.
-
#great_circle_distance_from_great_circle(point_a, point_b) ⇒ Object
Calculate the distance of self from a great circle defined by two points.
-
#great_circle_distance_from_polyline(polyline, options = {}) ⇒ Object
Supports a polyline based on either cartesian or angular coordinates.
- #mean_geodetic_radius(other) ⇒ Object
-
#to_geographic(options = {}) ⇒ Object
Convert self to a geographic lat/lng pair.
Methods inherited from Vector
#==, #add, #angle, #cross, #cross_length, #cross_normal, #distance, #distance_from_line, #distance_from_line_segment, #distance_from_polyline, #divide, #dot, from_polar, #heading, #initialize, #inspect, #magnitude, #multiply, #normalize, #orthogonal?, #parallel?, #scale, #subtract
Constructor Details
This class inherits a constructor from Geometry::Vector
Instance Attribute Details
#geodetic_radius(spheroid = @@spheroid) ⇒ Object
Returns the value of attribute geodetic_radius.
52 53 54 |
# File 'lib/geometry/vector/geo_vector.rb', line 52 def geodetic_radius @geodetic_radius end |
#latitude(options = {}) ⇒ Object
Returns the value of attribute latitude.
53 54 55 |
# File 'lib/geometry/vector/geo_vector.rb', line 53 def latitude @latitude end |
#longitude(options = {}) ⇒ Object
Returns the value of attribute longitude.
54 55 56 |
# File 'lib/geometry/vector/geo_vector.rb', line 54 def longitude @longitude end |
Class Method Details
.from_geographic(lat, lng, options = {}) ⇒ Object
Return a 3-dimensional cartesian vector representing the given latitude and longitude.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/geometry/vector/geo_vector.rb', line 21 def self.from_geographic(lat, lng, = {}) spheroid = @@spheroid || [:spheroid] unless [:unit] == :radians lat = Geometry.deg_to_rad(lat) lng = Geometry.deg_to_rad(lng) end # Convert the geodetic latitude to geocentric if required geocentric_latitude = [:geocentric] ? lat : spheroid.geodetic_to_geocentric_latitude(lat, :unit => :radians) # Find the projection of the point on the equatorial plane. equatorial_plane_projection = Math.cos(geocentric_latitude) x = Math.cos(lng) * equatorial_plane_projection y = Math.sin(lng) * equatorial_plane_projection z = Math.sin(geocentric_latitude) unit_vector = self.new(x,y,z) if [:unit_vector] unit_vector else raise ArgumentError, "No spheroid defined" unless spheroid geodetic_radius = spheroid.radius_at_geodetic_latitude(lat, :unit => :radians) unit_vector.scale(geodetic_radius) end end |
.from_great_circle_intersection(vector_1, vector_2, vector_3, vector_4) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/geometry/vector/geo_vector.rb', line 7 def self.from_great_circle_intersection(vector_1,vector_2,vector_3,vector_4) normal_to_great_circle_1 = vector_1.cross_normal(vector_2) normal_to_great_circle_2 = vector_3.cross_normal(vector_4) unit_vector = normal_to_great_circle_1.cross_normal(normal_to_great_circle_2) if @@spheroid unit_vector.scale(@@spheroid.mean_radius) else unit_vector end end |
Instance Method Details
#antipode ⇒ Object
79 80 81 |
# File 'lib/geometry/vector/geo_vector.rb', line 79 def antipode scale(-1.0) end |
#great_circle_distance(other, options = {}) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/geometry/vector/geo_vector.rb', line 87 def great_circle_distance(other, = {}) angular_distance = angle(other) if @@spheroid && ![:unit_vector] if [:use_mean_geodetic_radius] return angular_distance * mean_geodetic_radius(other) else return angular_distance * @@spheroid.mean_radius end else angular_distance end end |
#great_circle_distance_from_arc(point_a, point_b, options = {}) ⇒ Object
Calculate the distance of self from a finite line segment defined by two points
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/geometry/vector/geo_vector.rb', line 128 def great_circle_distance_from_arc(point_a,point_b, = {}) # Distance from a line segment is similar to the distance from the infinte line (above) # with a modification. # # The distance from an infinitely long line calculates the shortest distance to an infintitely # long line. This is the perpendicular distance. In the case of the line segment, this perpendicular # may or may not fall on the line segment part of the more general infinte line. # # If it does, we can keep the perpendicular distance. If not, the shortest distance will be # to either of the two line segments end. Determine which. normal_to_line = point_a.cross_normal(point_b).scale(@@spheroid.mean_radius) intersection = GeoVector.from_great_circle_intersection(point_a, point_b, self, normal_to_line) # The point which intersects the two great circles is actually one of two such unique points. We # know both fall on the great circle described by the points but we need to establish whether either # fall on our line segment, i.e. between them. If so, we can take the perpendicular distance from # the intersection point. line_length = point_a.great_circle_distance(point_b, ) if line_length >= intersection.great_circle_distance(point_a, ) && line_length >= intersection.great_circle_distance(point_b, ) # The intersection falls on the line segment. # Calculate the perpendicular distance. return self.great_circle_distance(intersection, ) elsif line_length >= intersection.antipode.great_circle_distance(point_a, ) && line_length >= intersection.antipode.great_circle_distance(point_b, ) # The *other* intersection falls on the line segment. # Calculate the perpendicular distance. return self.great_circle_distance(intersection.antipode, ) else # Neither intersection falls on the line segment. # Calculate the distance to the closer of the line segment ends. return [ self.great_circle_distance(point_a, ), self.great_circle_distance(point_b, ) ].min end end |
#great_circle_distance_from_great_circle(point_a, point_b) ⇒ Object
Calculate the distance of self from a great circle defined by two points.
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/geometry/vector/geo_vector.rb', line 103 def great_circle_distance_from_great_circle(point_a,point_b) # The shortest distance from a great circle is the perpendicular distance. # Find the vector which is normal to the plane described by the (curved) line together # with the origin. normal_to_line = point_a.cross_normal(point_b).scale(@@spheroid.mean_radius) # The line between self and the normal vector is perpendicular to the line. # # Next, find the intersection between the two lines which represents the shortest distance # from self to the line. intersection = GeoVector.from_great_circle_intersection(point_a, point_b, self, normal_to_line) # There are actually two valid intersections (which are antipodes of one another) and we have # found one. # # Return the smallest distance from self to either intersection [self.great_circle_distance(intersection), self.great_circle_distance(intersection.antipode)].min end |
#great_circle_distance_from_polyline(polyline, options = {}) ⇒ Object
Supports a polyline based on either cartesian or angular coordinates. Specify which using the :basis option
:cartesian => cartesian coordinates (x,y)
otherwise lat/lng pairs are assumed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/geometry/vector/geo_vector.rb', line 182 def great_circle_distance_from_polyline(polyline, = {}) constructor = Proc.new do |vertex| if [:basis] == :cartesian self.class.new(vertex[0], vertex[1], vertex[2]) else self.class.from_geographic(vertex[0], vertex[1], ) end end # memoize the last processed point as both array and vector objects last_array = polyline.first last_vector = constructor.call(last_array) minimum_distance = 999999999999 for vertex in polyline[1..-1] next if vertex == last_array start_vector = last_vector end_vector = constructor.call(vertex) this_segment_distance = great_circle_distance_from_arc(start_vector, end_vector, ) if(this_segment_distance < minimum_distance) minimum_distance = this_segment_distance end last_array = vertex last_vector = end_vector end return minimum_distance end |
#mean_geodetic_radius(other) ⇒ Object
83 84 85 |
# File 'lib/geometry/vector/geo_vector.rb', line 83 def mean_geodetic_radius(other) (self.geodetic_radius + other.geodetic_radius) / 2.0 end |
#to_geographic(options = {}) ⇒ Object
Convert self to a geographic lat/lng pair.
219 220 221 |
# File 'lib/geometry/vector/geo_vector.rb', line 219 def to_geographic( = {}) [latitude(), longitude()] end |