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
@@ -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
|
+
|