geo_vectors 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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
+