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,7 @@
1
+ require 'geo_vectors/geo_point'
2
+ require 'geo_vectors/geo_vector'
3
+ require 'geo_vectors/vector_parser'
4
+ require 'geo_vectors/point_vector'
5
+ require 'geo_vectors/bearing_vector'
6
+ require 'geo_vectors/direction_vector'
7
+ require 'geo_vectors/geo_vectors'
@@ -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
+