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.
Files changed (47) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Distance calc notes.txt +64 -0
  4. data/Gemfile +14 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.textile +178 -0
  7. data/Rakefile +53 -0
  8. data/VERSION +1 -0
  9. data/geo_vectors.gemspec +115 -0
  10. data/lib/geo_vectors.rb +7 -0
  11. data/lib/geo_vectors/bearing_vector.rb +87 -0
  12. data/lib/geo_vectors/core_ext.rb +54 -0
  13. data/lib/geo_vectors/direction_vector.rb +59 -0
  14. data/lib/geo_vectors/geo_point.rb +33 -0
  15. data/lib/geo_vectors/geo_vector.rb +56 -0
  16. data/lib/geo_vectors/geo_vectors.rb +92 -0
  17. data/lib/geo_vectors/point_vector.rb +85 -0
  18. data/lib/geo_vectors/point_vector/point_ops.rb +23 -0
  19. data/lib/geo_vectors/point_vector/vector_ops.rb +38 -0
  20. data/lib/geo_vectors/util.rb +3 -0
  21. data/lib/geo_vectors/util/calc.rb +89 -0
  22. data/lib/geo_vectors/util/geo_direction.rb +101 -0
  23. data/lib/geo_vectors/util/geo_distance.rb +135 -0
  24. data/lib/geo_vectors/util/geo_units.rb +53 -0
  25. data/lib/geo_vectors/vector_parser.rb +54 -0
  26. data/spec/geo_vectors/API proposal guide.txt +142 -0
  27. data/spec/geo_vectors/bearing_vector/add_vector_spec.rb +30 -0
  28. data/spec/geo_vectors/bearing_vector/random_spec.rb +18 -0
  29. data/spec/geo_vectors/bearing_vector_spec.rb +34 -0
  30. data/spec/geo_vectors/direction_vector/add_vector_spec.rb +30 -0
  31. data/spec/geo_vectors/direction_vector/point_add_spec.rb +0 -0
  32. data/spec/geo_vectors/direction_vector/random_spec.rb +16 -0
  33. data/spec/geo_vectors/direction_vector/subtract_vector_spec.rb +0 -0
  34. data/spec/geo_vectors/direction_vector_spec.rb +27 -0
  35. data/spec/geo_vectors/geo_vectors_spec.rb +108 -0
  36. data/spec/geo_vectors/point_vector/add_vector_spec.rb +135 -0
  37. data/spec/geo_vectors/point_vector/initializer_spec.rb +82 -0
  38. data/spec/geo_vectors/point_vector/point_add_spec.rb +45 -0
  39. data/spec/geo_vectors/point_vector/random_spec.rb +17 -0
  40. data/spec/geo_vectors/point_vector/scale_vector_spec.rb +52 -0
  41. data/spec/geo_vectors/point_vector/subtract_vector_spec.rb +80 -0
  42. data/spec/geo_vectors/point_vector_spec.rb +111 -0
  43. data/spec/geo_vectors/util/geo_direction_spec.rb +74 -0
  44. data/spec/geo_vectors/util/geo_distance_spec.rb +70 -0
  45. data/spec/geo_vectors/util/geo_units_spec.rb +23 -0
  46. data/spec/spec_helper.rb +7 -0
  47. metadata +218 -0
@@ -0,0 +1,54 @@
1
+ class GeoVector
2
+ module Parser
3
+ module ClassMethods
4
+ def create_vector *args
5
+ first_arg = args[0]
6
+ first_arg.any_kind_of?(GeoVector, GeoVectors) ? first_arg : parse_vector(*args)
7
+ end
8
+
9
+ def parse_vector *args
10
+ res = [:point, :bearing, :direction, :multiple].map {|type| send parser(type), *args }.compact.first
11
+ raise ArgumentError, "No GeoVector could be created from arguments: #{args}" if !res
12
+ res
13
+ end
14
+
15
+ def parser type
16
+ "parse_#{type}_vector"
17
+ end
18
+
19
+ def parse_multiple_vector *args
20
+ begin
21
+ GeoVectors.new *args
22
+ rescue
23
+ nil
24
+ end
25
+ end
26
+
27
+ def parse_point_vector *args
28
+ begin
29
+ PointVector.new *args
30
+ rescue
31
+ nil
32
+ end
33
+ end
34
+
35
+ def parse_bearing_vector *args
36
+ begin
37
+ BearingVector.new *args
38
+ rescue
39
+ nil
40
+ end
41
+ end
42
+
43
+ def parse_direction_vector *args
44
+ begin
45
+ DirectionVector.new *args
46
+ rescue
47
+ nil
48
+ end
49
+ end
50
+ end
51
+
52
+ extend ClassMethods
53
+ end
54
+ end
@@ -0,0 +1,142 @@
1
+ h2. Intro
2
+
3
+ A GeoVector can be any of:
4
+
5
+ 1) *bearing vector* - bearing (direction in degrees) and a distance
6
+ 2) *direction vector* - direction (:N, :NW, :NE, :S, :SE, :SW, :E, :W) and a distance
7
+ 3) *point vector* - number of degrees due east/west (+ or -) and a distance due north/south (+ or -)
8
+
9
+ Note that a direction vector is always converted to a bearing vector when added to a point
10
+
11
+ A GeoVector can be applied to a GeoPoint (see geo_calc) or to another GeoVector.
12
+ When multiple vectors are added together, the sum becomes a GeoVectors object.
13
+ If a GeoVectors object is applied, the vectors are simply applied in turn.
14
+
15
+ h2. Quick start (Usage guide)
16
+
17
+ The following gives a quick overview for how to use the GeoVector API.
18
+
19
+ _Note: This is suggested functionality._
20
+
21
+ I plan to use my recently published _geo_calc_ gem as the base for the functionality described here.
22
+ I need a major cleanup up of the current code...
23
+
24
+ h3. Addition
25
+
26
+ Vectors can be added to form a new Vector, using the simple formula vec = v1 + v2 = (v1.x + v2.y, v1.x + v2.y)
27
+
28
+ h3. Vector on Vector addition
29
+
30
+ If both vectors are point vectors, the result is simply a new point vector
31
+
32
+ <pre>
33
+ v1 = [1, 3].vector
34
+ v2 = [-2, 2].vector
35
+ vec = v1 + v2
36
+ vec.unit.should == :degrees
37
+ vec.lat.should == -1
38
+ vec.lng.should == 5
39
+
40
+ # alternative addition operators
41
+ vec = v1 << v2
42
+ </pre>
43
+
44
+ h3. Vector subtraction
45
+
46
+ <pre>
47
+ v1 = [1, 3].vector
48
+ v2 = [2, 1].vector
49
+ vec = v1 - v2 # here v2 inversed (scaled by -1) and then added
50
+ vec.lat.should == -1
51
+ vec.lng.should == 2
52
+ </pre>
53
+
54
+ h3. Vector scaling
55
+
56
+ <pre>
57
+ v1 = [1, 3].vector
58
+ vec = v1 * 2
59
+ vec.lat.should == 2
60
+ vec.lng.should == 6
61
+ </pre>
62
+
63
+ Scale a bearing vector
64
+
65
+ <pre>
66
+ v1 = [32, 3.km].vector
67
+ vec = v1 * 2
68
+ vec.bearing.should == 32
69
+ vec.distance.should == 6.km
70
+ </pre>
71
+
72
+
73
+ Using division operator / for inverse scaling
74
+
75
+ <pre>
76
+ v1 = [4, 2].vector
77
+ vec = v1 / 2
78
+ vec.lat.should == 2
79
+ vec.lng.should == 1
80
+ </pre>
81
+
82
+ h3. GeoVectors
83
+
84
+ Adding a point Vector to a bearing Vector
85
+
86
+ If the vectors are of different type, a GeoVectors object is created
87
+ containing both vectors. A GeoVectors is a composite vector.
88
+
89
+ <pre>
90
+ p1 = [1, -1]
91
+
92
+ v1 = [1, 3].vector # point Vector
93
+
94
+ # 32 deg bearing, 2.km
95
+ v2 = [32, 2.km].vector # bearing Vector
96
+ v2.bearing.should == 32
97
+ v2.distance.should == 2.km
98
+
99
+ vec = v1 + v2 # create a GeoVectors object
100
+ vec.should be_a(GeoVectors)
101
+ vec.vectors.size.should == 2 # should contain 2 vectors
102
+
103
+ # Adding more vectors to the GeoVectors object
104
+ vec.vectors << v3
105
+ vec << v4
106
+
107
+ p2 = p1 + vec # Add GeoVectors to the point
108
+ </pre>
109
+
110
+ h3. Vector on Point addition
111
+
112
+ Add a point Vector to a GeoPoint
113
+
114
+ <pre>
115
+ p1 = [1, 3].geo_point
116
+ vec = [-2, 2].vector
117
+ p2 = p1 + vec
118
+ p2.lat.should == -1
119
+ p2.lng.should == 5
120
+ </pre>
121
+
122
+ Add an inverse point Vector (subtract) to a GeoPoint
123
+
124
+ <pre>
125
+ p1 = [1, 3].geo_point
126
+ vec = [2, 1].vector
127
+ p2 = p1 - vec
128
+ p2.lat.should == -1
129
+ p2.lng.should == 2
130
+ </pre>
131
+
132
+ Add a bearing Vector to a GeoPoint
133
+
134
+ <pre>
135
+ p1 = [1, 3].geo_point
136
+
137
+ # 32 deg bearing, 2.km
138
+ vec = [32, 2.km].vector
139
+
140
+ # use #destination_point from 'geo_calc' project
141
+ p2 = p1 + vec
142
+ </pre>
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe BearingVector do
4
+ context 'Bearing Vector: 2 km at 32 degrees and a GeoPoint at (1,3)' do
5
+ let(:vector) { BearingVector.new 32, 2.km }
6
+ let(:point) { GeoPoint.new 1, 3 }
7
+
8
+ describe '#+' do
9
+ it 'should add Bearing Vector to point' do
10
+ p2 = point + vector
11
+ p2.should_not == point
12
+ end
13
+ end
14
+
15
+ describe '#add (alias to +)' do
16
+ it 'should add Bearing Vector to point' do
17
+ p2 = point.add(vector)
18
+ p2.should_not == point
19
+ end
20
+ end
21
+
22
+ describe '#add! changes point' do
23
+ it 'should add Bearing Vector directly to point' do
24
+ old_point = point.dup
25
+ point.add!(vector)
26
+ old_point.lat.should_not == point.lat
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe GeoVector do
4
+ describe 'Random module' do
5
+ context 'Bearing vector 4.km at 52 deg' do
6
+ describe '#random_vector' do
7
+ let (:vec) { vec = [4.km, 52].b_vector }
8
+
9
+ it 'should return a random vector of up to 4.kms with any bearing' do
10
+ rvec = vec.random_vector
11
+ rvec.distance.in_kms.should be_between(0, 4)
12
+ puts "random bearing: #{rvec.bearing}"
13
+ rvec.bearing.should be_between(0, 360)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe BearingVector do
4
+ describe '#initialize' do
5
+ it 'should create Bearing Vector from distance and degrees' do
6
+ v = BearingVector.new 2.km, 32
7
+ v.should be_a BearingVector
8
+ v.distance.should == 2.km
9
+ v.bearing.should == 32
10
+ end
11
+
12
+ it 'should create Bearing Vector from degrees and distance' do
13
+ v = BearingVector.new 32, 2.km
14
+ v.distance.should == 2.km
15
+ v.bearing.should == 32
16
+ end
17
+
18
+ it 'should create Bearing Vector from 2 numbers, assuming first arg is distance in :kms' do
19
+ v = BearingVector.new 2, 32
20
+ v.distance.should == 2.km
21
+ v.bearing.should == 32
22
+ end
23
+
24
+ it 'should NOT create Bearing Vector from 1 argument' do
25
+ lambda {BearingVector.new 2}.should raise_error
26
+ end
27
+ end
28
+
29
+ describe '#to_s' do
30
+ it 'should print distance and bearing' do
31
+ BearingVector.new(2, 32).to_s.should match /distance: 2 kms, bearing: 32 degrees/
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe DirectionVector do
4
+ context 'Direction Vector: 2 km North and a GeoPoint at (1,3)' do
5
+ let(:vector) { DirectionVector.new 2.km, :north }
6
+ let(:point) { GeoPoint.new 1, 3 }
7
+
8
+ describe '#+' do
9
+ it 'should add Direction Vector to point' do
10
+ p2 = point + vector
11
+ p2.should_not == point
12
+ end
13
+ end
14
+
15
+ describe '#add (alias to +)' do
16
+ it 'should add Direction Vector to point' do
17
+ p2 = point.add(vector)
18
+ p2.should_not == point
19
+ end
20
+ end
21
+
22
+ describe '#add! changes point' do
23
+ it 'should add Direction Vector directly to point' do
24
+ old_point = point.dup
25
+ point.add!(vector)
26
+ old_point.lat.should_not == point.lat
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe GeoVector do
4
+ describe 'Random module' do
5
+ context 'Direction vector 4.km North' do
6
+ describe '#random_vector' do
7
+ let (:vec) { vec = [4.km, :north].d_vector }
8
+
9
+ it 'should return a random vector of up to 4.kms in any direction' do
10
+ rvec = vec.random_vector
11
+ rvec.distance.in_kms.should be_between(0, 4)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe DirectionVector do
4
+ describe '#initialize' do
5
+ it 'should create Direction Vector from distance and direction' do
6
+ v = DirectionVector.new 2.km, :north
7
+ v.distance.should == 2.km
8
+ v.direction.should == :N
9
+ end
10
+
11
+ it 'should create Direction Vector from degrees and distance' do
12
+ v = DirectionVector.new :north, 2.km
13
+ v.distance.should == 2.km
14
+ v.direction.should == :N
15
+ end
16
+
17
+ it 'should create Direction Vector from number and direction, assuming number is distance in :kms' do
18
+ v = DirectionVector.new 2, :north
19
+ v.distance.should == 2.km
20
+ v.direction.should == :N
21
+ end
22
+
23
+ it 'should NOT create Direction Vector from 1 argument' do
24
+ lambda {DirectionVector.new 1}.should raise_error
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe GeoVectors do
4
+ context 'an GeoVectors containing a PointVector v1, and a BearingVector v2' do
5
+ let (:v1) { [1, 2].vector }
6
+ let (:v2) { [30, 4.km].b_vector }
7
+ let (:vecs) { GeoVectors.new v1, v2 }
8
+ let (:point) { [3, 4].geo_point }
9
+
10
+ describe '#vectors' do
11
+ it 'should return the instances of GeoVector added' do
12
+ vecs.vectors.first.should == v1
13
+ vecs.vectors.last.should == v2
14
+ end
15
+ end
16
+
17
+ describe '#to_s' do
18
+ it 'should return vector seperated with ;' do
19
+ vecs.to_s.should match /;/
20
+ end
21
+ end
22
+
23
+ describe '#each' do
24
+ it 'should return each vector' do
25
+ vecs.each do |v|
26
+ v.should be_a GeoVector
27
+ end
28
+ end
29
+ end
30
+
31
+ describe '#map' do
32
+ it 'should return each vector' do
33
+ x = vecs.vectors.map do |v|
34
+ v.to_s
35
+ end.join('#')
36
+ x.should match /#/
37
+ end
38
+ end
39
+
40
+
41
+ describe '#directions' do
42
+ it 'should return directions of all vectors' do
43
+ dirs = vecs.directions
44
+ dirs.should include(30)
45
+ dirs.size.should == 2
46
+ end
47
+ end
48
+
49
+ describe '#distances' do
50
+ it 'should return distances of all vectors' do
51
+ dists = vecs.distances
52
+ dists.should include(4.km)
53
+ dists.size.should == 2
54
+ end
55
+ end
56
+
57
+ describe '#scale' do
58
+ it 'should return distances of all vectors' do
59
+ big_vecs = vecs.scale 2
60
+ big_vecs.vectors.first.lat.should == 2
61
+ end
62
+ end
63
+
64
+ describe '#scale' do
65
+ it 'should return distances of all vectors' do
66
+ vecs2 = vecs.dup
67
+ vecs2.reduce 2
68
+ vecs2.vectors.first.lat.should == 0.5
69
+ end
70
+ end
71
+
72
+
73
+ describe 'Addition' do
74
+ describe '#add' do
75
+ it 'should add vector to a point' do
76
+ p2 = point.add vecs
77
+ p2.lat.should > point.lat
78
+ end
79
+ end
80
+
81
+ describe '#+' do
82
+ it 'should add vector to a point' do
83
+ old_lat = point.lat
84
+ p2 = point + vecs
85
+ p2.lat.should > point.lat
86
+ end
87
+ end
88
+ end
89
+
90
+ describe 'Subtraction' do
91
+ describe '#sub' do
92
+ it 'should subtract vector from point' do
93
+ p2 = point.sub(vecs)
94
+ p2.lat.should < point.lat
95
+ end
96
+ end
97
+
98
+ describe '#-' do
99
+ it 'should subtract vector from point' do
100
+ old_lat = point.lat
101
+ p2 = point - vecs
102
+ p2.lat.should < point.lat
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+