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