geo_vectors 0.5.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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Distance calc notes.txt +64 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +20 -0
- data/README.textile +178 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/geo_vectors.gemspec +115 -0
- data/lib/geo_vectors.rb +7 -0
- data/lib/geo_vectors/bearing_vector.rb +87 -0
- data/lib/geo_vectors/core_ext.rb +54 -0
- data/lib/geo_vectors/direction_vector.rb +59 -0
- data/lib/geo_vectors/geo_point.rb +33 -0
- data/lib/geo_vectors/geo_vector.rb +56 -0
- data/lib/geo_vectors/geo_vectors.rb +92 -0
- data/lib/geo_vectors/point_vector.rb +85 -0
- data/lib/geo_vectors/point_vector/point_ops.rb +23 -0
- data/lib/geo_vectors/point_vector/vector_ops.rb +38 -0
- data/lib/geo_vectors/util.rb +3 -0
- data/lib/geo_vectors/util/calc.rb +89 -0
- data/lib/geo_vectors/util/geo_direction.rb +101 -0
- data/lib/geo_vectors/util/geo_distance.rb +135 -0
- data/lib/geo_vectors/util/geo_units.rb +53 -0
- data/lib/geo_vectors/vector_parser.rb +54 -0
- data/spec/geo_vectors/API proposal guide.txt +142 -0
- data/spec/geo_vectors/bearing_vector/add_vector_spec.rb +30 -0
- data/spec/geo_vectors/bearing_vector/random_spec.rb +18 -0
- data/spec/geo_vectors/bearing_vector_spec.rb +34 -0
- data/spec/geo_vectors/direction_vector/add_vector_spec.rb +30 -0
- data/spec/geo_vectors/direction_vector/point_add_spec.rb +0 -0
- data/spec/geo_vectors/direction_vector/random_spec.rb +16 -0
- data/spec/geo_vectors/direction_vector/subtract_vector_spec.rb +0 -0
- data/spec/geo_vectors/direction_vector_spec.rb +27 -0
- data/spec/geo_vectors/geo_vectors_spec.rb +108 -0
- data/spec/geo_vectors/point_vector/add_vector_spec.rb +135 -0
- data/spec/geo_vectors/point_vector/initializer_spec.rb +82 -0
- data/spec/geo_vectors/point_vector/point_add_spec.rb +45 -0
- data/spec/geo_vectors/point_vector/random_spec.rb +17 -0
- data/spec/geo_vectors/point_vector/scale_vector_spec.rb +52 -0
- data/spec/geo_vectors/point_vector/subtract_vector_spec.rb +80 -0
- data/spec/geo_vectors/point_vector_spec.rb +111 -0
- data/spec/geo_vectors/util/geo_direction_spec.rb +74 -0
- data/spec/geo_vectors/util/geo_distance_spec.rb +70 -0
- data/spec/geo_vectors/util/geo_units_spec.rb +23 -0
- data/spec/spec_helper.rb +7 -0
- metadata +218 -0
data/lib/geo_vectors.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'geo_vectors/geo_vector'
|
2
|
+
|
3
|
+
class BearingVector < GeoVector
|
4
|
+
include GeoDistance::Extract
|
5
|
+
include GeoUnits::Converter
|
6
|
+
|
7
|
+
attr_reader :bearing
|
8
|
+
attr_reader :distance
|
9
|
+
|
10
|
+
# should be Distance objects!
|
11
|
+
def initialize dist, bearing
|
12
|
+
dist, bearing = [bearing, dist] if bearing.kind_of? GeoDistance
|
13
|
+
self.bearing = bearing
|
14
|
+
self.distance = dist
|
15
|
+
end
|
16
|
+
|
17
|
+
def direction
|
18
|
+
begin
|
19
|
+
bearing_to_dir bearing
|
20
|
+
rescue
|
21
|
+
bearing
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def random_vector
|
26
|
+
BearingVector.new distance.random, random_bearing
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_to_point! point
|
30
|
+
dest_point = point.destination_point bearing, distance.in_kms
|
31
|
+
point.lat = dest_point.lat
|
32
|
+
point.lng = dest_point.lng
|
33
|
+
point
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_to_point point
|
37
|
+
self.dup.add_to_point! point
|
38
|
+
end
|
39
|
+
|
40
|
+
# normalize to within 0-360 degrees
|
41
|
+
def bearing= brng
|
42
|
+
@bearing = brng.normalize_degrees
|
43
|
+
end
|
44
|
+
|
45
|
+
def distance= dist
|
46
|
+
@distance = extract_distance dist
|
47
|
+
end
|
48
|
+
|
49
|
+
def reverse
|
50
|
+
self.dup.reverse!
|
51
|
+
end
|
52
|
+
|
53
|
+
def reverse!
|
54
|
+
reverse_bearing!
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def scale! scale
|
59
|
+
@distance = distance * scale
|
60
|
+
end
|
61
|
+
|
62
|
+
def unit
|
63
|
+
distance.unit
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
"#{distance}, bearing: #{bearing} degrees"
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
def reverse_bearing!
|
73
|
+
shift = case bearing
|
74
|
+
when 0
|
75
|
+
0
|
76
|
+
when -360..0
|
77
|
+
180
|
78
|
+
when 0..360
|
79
|
+
-180
|
80
|
+
end
|
81
|
+
self.bearing = bearing + shift
|
82
|
+
end
|
83
|
+
|
84
|
+
def random_bearing
|
85
|
+
rand(360 * 100) / 100
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'geo_vectors/util/geo_distance'
|
2
|
+
|
3
|
+
class Fixnum
|
4
|
+
include GeoDistance::Unit
|
5
|
+
end
|
6
|
+
|
7
|
+
class Float
|
8
|
+
include GeoDistance::Unit
|
9
|
+
end
|
10
|
+
|
11
|
+
class GeoVector
|
12
|
+
module Macros
|
13
|
+
def point_vector
|
14
|
+
PointVector.new self.geo_point
|
15
|
+
end
|
16
|
+
alias_method :vector, :point_vector
|
17
|
+
alias_method :geo_vector, :point_vector
|
18
|
+
alias_method :p_vector, :point_vector
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class GeoPoint
|
23
|
+
include ::GeoVector::Macros
|
24
|
+
end
|
25
|
+
|
26
|
+
class Hash
|
27
|
+
include GeoVector::Macros
|
28
|
+
end
|
29
|
+
|
30
|
+
class String
|
31
|
+
include GeoVector::Macros
|
32
|
+
end
|
33
|
+
|
34
|
+
class Array
|
35
|
+
include GeoVector::Macros
|
36
|
+
|
37
|
+
def b_vector
|
38
|
+
raise ArgumentException, "To create a BearingVector, the Array must contain at least 2 elements, one for bearing and oen for distance" if !(size >= 2)
|
39
|
+
BearingVector.new self[0], self[1]
|
40
|
+
end
|
41
|
+
alias_method :bearing_vector, :b_vector
|
42
|
+
|
43
|
+
def d_vector
|
44
|
+
raise ArgumentException, "To create a DirectionVector, the Array must contain at least 2 elements, one for bearing and oen for distance" if !(size >= 2)
|
45
|
+
raise ArgumentException, "The second element in the Array must be a Symbol defining the direction of the vector" if !self[1].kind_of?(Symbol)
|
46
|
+
DirectionVector.new self[0], self[1]
|
47
|
+
end
|
48
|
+
alias_method :direction_vector, :d_vector
|
49
|
+
|
50
|
+
def to_point
|
51
|
+
geo_point
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'geo_vectors/geo_vector'
|
2
|
+
|
3
|
+
class DirectionVector < GeoVector
|
4
|
+
include GeoDistance::Extract
|
5
|
+
include GeoDirection
|
6
|
+
|
7
|
+
attr_reader :direction # direction symbol :N, :S, :SW, etc.
|
8
|
+
attr_reader :distance # GeoDistance object
|
9
|
+
|
10
|
+
def initialize dist, dir
|
11
|
+
dist, dir = [dir, dist] if dir.kind_of? GeoDistance
|
12
|
+
@distance = extract_distance dist
|
13
|
+
@direction = get_valid_direction dir
|
14
|
+
end
|
15
|
+
|
16
|
+
def random_vector
|
17
|
+
DirectionVector.new distance.random, random_direction
|
18
|
+
end
|
19
|
+
|
20
|
+
def direction= dir
|
21
|
+
@direction = get_valid_direction dir
|
22
|
+
end
|
23
|
+
|
24
|
+
def distance= dist
|
25
|
+
@distance = extract_distance dist
|
26
|
+
end
|
27
|
+
|
28
|
+
def scale! scale
|
29
|
+
@distance *= scale
|
30
|
+
end
|
31
|
+
|
32
|
+
def unit
|
33
|
+
distance.unit
|
34
|
+
end
|
35
|
+
|
36
|
+
def as_bearing_vector
|
37
|
+
to_bearing_vector direction, distance
|
38
|
+
end
|
39
|
+
|
40
|
+
def as_point_vector
|
41
|
+
to_point_vector direction, distance
|
42
|
+
end
|
43
|
+
|
44
|
+
# return new point from adding vector to point
|
45
|
+
def add_to_point point
|
46
|
+
vec = as_bearing_vector
|
47
|
+
point.destination_point vec.bearing, vec.distance.in_kms
|
48
|
+
end
|
49
|
+
|
50
|
+
# add vector directly to point (destructive update)
|
51
|
+
def add_to_point! point
|
52
|
+
vec = as_bearing_vector
|
53
|
+
dest = point.destination_point vec.bearing, vec.distance.in_kms
|
54
|
+
point.lat = dest.lat
|
55
|
+
point.lng = dest.lng
|
56
|
+
point
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class GeoPoint
|
2
|
+
include GeoCalc
|
3
|
+
|
4
|
+
def + *args
|
5
|
+
self.dup.add! *args
|
6
|
+
end
|
7
|
+
alias_method :add, :+
|
8
|
+
alias_method :<<, :+
|
9
|
+
|
10
|
+
def add! *args
|
11
|
+
vec = GeoVector::Parser.create_vector *args
|
12
|
+
vec.add_to_point! self
|
13
|
+
end
|
14
|
+
|
15
|
+
def - *args
|
16
|
+
self.dup.sub! *args
|
17
|
+
end
|
18
|
+
alias_method :sub, :-
|
19
|
+
|
20
|
+
def sub! *args
|
21
|
+
vec = GeoVector::Parser.create_vector *args
|
22
|
+
vec.sub_from_point! self
|
23
|
+
end
|
24
|
+
|
25
|
+
def vector
|
26
|
+
to_lat_lng.vector
|
27
|
+
end
|
28
|
+
|
29
|
+
def geo_point
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'geo_calc'
|
2
|
+
require 'geo_vectors/core_ext'
|
3
|
+
require 'geo_vectors/util'
|
4
|
+
|
5
|
+
# A Vector consists of info that can transform a point into a destination point given some operation on that info
|
6
|
+
class GeoVector
|
7
|
+
attr_reader :unit
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@unit = :degrees
|
11
|
+
end
|
12
|
+
|
13
|
+
def add! vector
|
14
|
+
raise '#add! method must be implemented by including class'
|
15
|
+
end
|
16
|
+
|
17
|
+
def scale! scalar
|
18
|
+
raise '#scale! method must be implemented by including class'
|
19
|
+
end
|
20
|
+
|
21
|
+
def direction
|
22
|
+
raise '#distance method must be implemented by including class'
|
23
|
+
end
|
24
|
+
|
25
|
+
def distance
|
26
|
+
raise '#distance method must be implemented by including class'
|
27
|
+
end
|
28
|
+
|
29
|
+
def add vector
|
30
|
+
self.dup.add! vector
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :<<, :add
|
34
|
+
alias_method :+, :add
|
35
|
+
|
36
|
+
def sub! vector
|
37
|
+
add! vector.reverse
|
38
|
+
end
|
39
|
+
|
40
|
+
def sub vector
|
41
|
+
self.dup.sub vector
|
42
|
+
end
|
43
|
+
alias_method :-, :sub
|
44
|
+
|
45
|
+
def scale scalar
|
46
|
+
self.dup.scale! scalar
|
47
|
+
end
|
48
|
+
alias_method :*, :scale
|
49
|
+
alias_method :enhance, :*
|
50
|
+
alias_method :grow_by, :*
|
51
|
+
|
52
|
+
def / scalar
|
53
|
+
scale (1.0 / scalar)
|
54
|
+
end
|
55
|
+
alias_method :reduce, :/
|
56
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Operations that apply on a collection of GeoVector
|
2
|
+
class GeoVectors < Array
|
3
|
+
include Enumerable
|
4
|
+
# include GeoVector
|
5
|
+
attr_reader :vectors
|
6
|
+
|
7
|
+
def initialize *vectors
|
8
|
+
self.vectors = vectors
|
9
|
+
end
|
10
|
+
|
11
|
+
def vectors= *vectors
|
12
|
+
vectors = vectors.flatten
|
13
|
+
raise ArgumentError, "GeoVectors can only contain GeoVector instances" if !vectors.only_kinds_of? GeoVector
|
14
|
+
@vectors = vectors
|
15
|
+
end
|
16
|
+
|
17
|
+
# iterate each and call direction
|
18
|
+
def directions
|
19
|
+
vectors.map {|v| v.direction }
|
20
|
+
end
|
21
|
+
|
22
|
+
def distances
|
23
|
+
vectors.map {|v| v.distance }
|
24
|
+
end
|
25
|
+
|
26
|
+
def each &block
|
27
|
+
vectors.each { |v| yield v }
|
28
|
+
end
|
29
|
+
|
30
|
+
# return new point from adding vector to point
|
31
|
+
def add_to_point point
|
32
|
+
add_to_point! point.dup
|
33
|
+
end
|
34
|
+
|
35
|
+
# add vector directly to point (destructive update)
|
36
|
+
def add_to_point! point
|
37
|
+
vectors.each do |v|
|
38
|
+
point.add! v
|
39
|
+
end
|
40
|
+
point
|
41
|
+
end
|
42
|
+
|
43
|
+
def sub_from_point point
|
44
|
+
reverse_directions.add_to_point point
|
45
|
+
end
|
46
|
+
|
47
|
+
def sub_from_point! point
|
48
|
+
reverse_directions.add_to_point! point
|
49
|
+
end
|
50
|
+
|
51
|
+
def scale! scalar
|
52
|
+
each {|v| v.scale! scalar }
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def scale scalar
|
57
|
+
self.dup.scale! scalar
|
58
|
+
end
|
59
|
+
alias_method :*, :scale
|
60
|
+
alias_method :enhance, :*
|
61
|
+
alias_method :grow_by, :*
|
62
|
+
|
63
|
+
def / scalar
|
64
|
+
scale (1.0 / scalar)
|
65
|
+
end
|
66
|
+
alias_method :reduce, :/
|
67
|
+
|
68
|
+
|
69
|
+
def reverse_directions
|
70
|
+
vectors.each do |v|
|
71
|
+
v.reverse!
|
72
|
+
end
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s
|
77
|
+
vectors.inject([]) do |res, v|
|
78
|
+
res << v.to_s
|
79
|
+
res
|
80
|
+
end.join(' ; ')
|
81
|
+
end
|
82
|
+
|
83
|
+
protected
|
84
|
+
|
85
|
+
def check_valid!
|
86
|
+
raise "Only works for an Array of GeoVector" if !valid?
|
87
|
+
end
|
88
|
+
|
89
|
+
def valid?
|
90
|
+
kind_of?(Array) && only_kinds_of?(GeoVector)
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'geo_vectors/geo_vector'
|
2
|
+
require 'sugar-high/kind_of'
|
3
|
+
require 'proxy_party'
|
4
|
+
require 'geo_vectors/point_vector/vector_ops'
|
5
|
+
require 'geo_vectors/point_vector/point_ops'
|
6
|
+
|
7
|
+
class PointVector < GeoVector
|
8
|
+
include GeoCalc
|
9
|
+
include VectorOps
|
10
|
+
include PointOps
|
11
|
+
|
12
|
+
attr_accessor :point
|
13
|
+
proxy :point
|
14
|
+
|
15
|
+
def initialize *args
|
16
|
+
if args[0].kind_of?(GeoPoint) && args.size == 1
|
17
|
+
@point = args[0]
|
18
|
+
else
|
19
|
+
args = normalize_points(args[0], args[1]) if args.only_kinds_of?(GeoPoint) && args.size == 2
|
20
|
+
@point = GeoPoint.new *args
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def direction
|
25
|
+
brng = bearing
|
26
|
+
begin
|
27
|
+
bearing_to_dir brng
|
28
|
+
rescue
|
29
|
+
brng
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def bearing
|
34
|
+
origin.bearing_to(point).to_precision(2).to_f
|
35
|
+
end
|
36
|
+
|
37
|
+
def point= *args
|
38
|
+
@point = GeoPoint.new *args
|
39
|
+
end
|
40
|
+
|
41
|
+
def length unit = :kms
|
42
|
+
origin.distance_to(point)
|
43
|
+
end
|
44
|
+
|
45
|
+
def distance unit = :kms
|
46
|
+
origin.distance_to(point).send unit
|
47
|
+
end
|
48
|
+
|
49
|
+
def x; lng; end
|
50
|
+
def y; lat; end
|
51
|
+
|
52
|
+
def scale! scalar
|
53
|
+
self.lat = self.lat * scalar
|
54
|
+
self.lng = self.lng * scalar
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def reverse
|
59
|
+
self.dup.reverse!
|
60
|
+
end
|
61
|
+
|
62
|
+
def reverse!
|
63
|
+
self.point.reverse_point!
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def normalize_points p1, p2
|
70
|
+
lng, lat = [ delta_lat(p1, p2), delta_lng(p1, p2) ]
|
71
|
+
end
|
72
|
+
|
73
|
+
def delta_lat p1, p2
|
74
|
+
p2.lat - p1.lat
|
75
|
+
end
|
76
|
+
|
77
|
+
def delta_lng p1, p2
|
78
|
+
p2.lng - p1.lng
|
79
|
+
end
|
80
|
+
|
81
|
+
def origin
|
82
|
+
[0, 0].geo_point
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|