bounding_boxes 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ab6c2d3842feb74dd9f4f1e4ec7532b115e7fbbc
4
+ data.tar.gz: 6bad38f93433df5758fcb78262b20966faa35a17
5
+ SHA512:
6
+ metadata.gz: 4a412ca4f2918b55f504eb708c0ea471d760699469d4bf82a5f2f351561436ad736008f6f38c1dc3117d63b37742333d5c778971fdb7a503b7d06c4b0acabb10
7
+ data.tar.gz: 96d975c4535ff44c0fca9558e6bce1c6e620c375a47495cc3477d4dc718f604d5a789eb449cee77c8afdcf3d9797e6bc4e1fcea0dcf763b7d3811a9335860576
@@ -0,0 +1,71 @@
1
+ module BB
2
+ class BaseBoundingBox
3
+ attr_accessor :max, :min, :preferred_units
4
+
5
+ def initialize(lat1, long1, lat2, long2, units)
6
+ @min = {latitude: lat1, longitude: long1}
7
+ @max = {latitude: lat2, longitude: long2}
8
+ @preferred_units = units
9
+ end
10
+
11
+ def side_length
12
+ self.send("side_length_#{preferred_units}".to_sym)
13
+ end
14
+
15
+ def width(units = @preferred_units)
16
+ BB.send("distance_#{units}".to_sym, {latitude: @max[:latitude],
17
+ longitude: @max[:longitude]},
18
+ {latitude: @max[:latitude],
19
+ longitude: @min[:longitude]})
20
+ end
21
+
22
+ def height(units = @preferred_units)
23
+ BB.send("distance_#{units}".to_sym, {latitude: @max[:latitude],
24
+ longitude: @max[:longitude]},
25
+ {latitude: @min[:latitude],
26
+ longitude: @max[:longitude]})
27
+ end
28
+
29
+ def min_lat
30
+ @min[:latitude]
31
+ end
32
+
33
+ def min_long
34
+ @min[:longitude]
35
+ end
36
+
37
+ def max_lat
38
+ @max[:latitude]
39
+ end
40
+
41
+ def max_long
42
+ @max[:longitude]
43
+ end
44
+
45
+ def fetch(property)
46
+ raise KeyError unless self.respond_to?(property)
47
+ self.send(property)
48
+ end
49
+
50
+ def method_missing(name, *args)
51
+ attribute = name.to_s
52
+ if attribute =~ /(width_)(km|kilometers)/
53
+ width(:kilometers)
54
+ elsif attribute =~ /(width_)(mi|mil|miles)/
55
+ width(:miles)
56
+ elsif attribute =~ /(height_)(km|kilometers)/
57
+ height(:kilometers)
58
+ elsif attribute =~ /(height_)(mi|mil|miles)/
59
+ height(:miles)
60
+ elsif attribute =~ /(min|minimum)_(lat|latitude)/
61
+ min_lat
62
+ elsif attribute =~ /(min|minimum)_(lon|long|longitude)/
63
+ min_long
64
+ elsif attribute =~ /(max|maximum)_(lat|latitude)/
65
+ max_lat
66
+ elsif attribute =~ /(max|maximum)_(lon|long|longitude)/
67
+ max_long
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,73 @@
1
+ module BB
2
+ #can create any type of bounding box and
3
+ #will be able to split it into an array of bounding boxes
4
+ class BoundingBox < BaseBoundingBox
5
+ attr_accessor :box
6
+ def initialize(options = {})
7
+ if options.has_key?(:radius)
8
+ build_point_bounding_box(options)
9
+ elsif options.has_key?(:side_length)
10
+ build_square_bounding_box(options)
11
+ elsif options.size == 5 && options.key_present?(:units)
12
+ build_base_bounding_box(options)
13
+ end
14
+ end
15
+
16
+ def split_geo(max_size)
17
+ raise "split size greater than width or height" unless self.width > max_size && self.height > max_size
18
+ rows = (self.height / max_size).to_i
19
+ columns = (self.width / max_size).to_i
20
+
21
+ split_width = self.width / columns
22
+ split_height = self.height / rows
23
+
24
+ temp_array = []
25
+ temp_lat = self.min_lat
26
+ temp_long = self.min_long
27
+
28
+ (rows - 1).times do |row_num|
29
+ (columns - 1).times do |column_num|
30
+ temp_array << BB::SquareBoundingBox.new(temp_lat,
31
+ temp_long,
32
+ "#{split_width}#{self.preferred_units}" )
33
+ temp_long = temp_array.last.max_long
34
+ end
35
+ temp_lat = temp_array.last.max_lat
36
+ temp_long = self.min_long
37
+ end
38
+ temp_array
39
+ end
40
+
41
+ private
42
+ def set_max_min
43
+ @max = @box.max
44
+ @min = @box.min
45
+ @preferred_units = @box.preferred_units
46
+ end
47
+
48
+ def build_point_bounding_box(options)
49
+ @box = BB::PointBoundingBox.new(options.fetch(:latitude),
50
+ options.fetch(:longitude),
51
+ options.fetch(:radius))
52
+ set_max_min
53
+ end
54
+
55
+ def build_square_bounding_box(options)
56
+ @box = BB::SquareBoundingBox.new(options.fetch(:latitude),
57
+ options.fetch(:longitude),
58
+ options.fetch(:side_length))
59
+ set_max_min
60
+ end
61
+
62
+ def build_base_bounding_box(options)
63
+ @box = BB::BaseBoundingBox.new(options.fetch(:lat1),
64
+ options.fetch(:long1),
65
+ options.fetch(:lat2),
66
+ options.fetch(:long2),
67
+ options.fetch(:units))
68
+ set_max_min
69
+ end
70
+
71
+
72
+ end
73
+ end
@@ -0,0 +1,38 @@
1
+ module BB
2
+ def self.distance_kilometers(point1, point2)
3
+ lat1 = BB::degrees_to_radians(point1.fetch(:latitude))
4
+ long1 = BB::degrees_to_radians(point1.fetch(:longitude))
5
+ lat2 = BB::degrees_to_radians(point2.fetch(:latitude))
6
+ long2 = BB::degrees_to_radians(point2.fetch(:longitude))
7
+
8
+ (Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(long1 - long2)) * 6371)
9
+ end
10
+
11
+ def self.distance_km(point1, point2)
12
+ BB.distance_kilometers(point1, point2)
13
+ end
14
+
15
+ def self.distance_miles(point1, point2)
16
+ BB.kilometers_to_miles(BB.distance_kilometers(point1, point2))
17
+ end
18
+
19
+ def self.distance_mi(point1, point2)
20
+ BB.distance_miles(point1, point2)
21
+ end
22
+
23
+ def self.degrees_to_radians(number)
24
+ number * Math::PI / 180
25
+ end
26
+
27
+ def self.radians_to_degrees(number)
28
+ number * 180 / Math::PI
29
+ end
30
+
31
+ def self.kilometers_to_miles(number)
32
+ number * 0.621371
33
+ end
34
+
35
+ def self.miles_to_kilometers(number)
36
+ number * 1.60934
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ module BB
2
+ #creates a bounding box that contains a circle
3
+ #with center of lat, long and radius of radius
4
+ #should be called as PointBoundingBox.new(lat, long, "radius<km || mi>")
5
+ class PointBoundingBox < BaseBoundingBox
6
+ def initialize(lat, long, radius)
7
+ @input = {latitude: lat, longitude: long, radius: radius}
8
+ @input_radius = parse_radius
9
+ @input_lat = parse_lat
10
+ @input_long = parse_long
11
+ @max = fetch_max
12
+ @min = fetch_min
13
+ end
14
+
15
+ private
16
+ def parse_radius
17
+ parsed = @input.fetch(:radius).scan(/\d+\.?\d*|km|mi/)
18
+ @preferred_units = parsed[1] || "mi"
19
+ if @units == "km" then parsed[0].to_f else BB.miles_to_kilometers(parsed[0].to_f) end
20
+ end
21
+
22
+ def parse_lat
23
+ BB.degrees_to_radians(@input.fetch(:latitude))
24
+ end
25
+
26
+ def parse_long
27
+ BB.degrees_to_radians(@input.fetch(:longitude))
28
+ end
29
+
30
+ def fetch_max
31
+ {latitude: BB.radians_to_degrees(@input_lat + delta_lat),
32
+ longitude: BB.radians_to_degrees(@input_long + delta_long)}
33
+ end
34
+
35
+ def fetch_min
36
+ {latitude: BB.radians_to_degrees(@input_lat - delta_lat),
37
+ longitude: BB.radians_to_degrees(@input_long - delta_long)}
38
+ end
39
+
40
+ def delta_lat
41
+ @input_radius / 6371
42
+ end
43
+
44
+ def delta_long
45
+ Math.asin(Math.sin(delta_lat)/Math.cos(@input_lat))
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,10 @@
1
+ module BB
2
+ def self.split_box(box, length_of_side)
3
+ parsed = length_of_side.to_s.scan(/\d+|km|mi/)
4
+ split_length = parsed[0].to_f
5
+ units = parsed[1]
6
+ raise "box width smaller than split" unless box.send("side_length_#{units}".to_sym) > split_length
7
+
8
+
9
+ end
10
+ end
@@ -0,0 +1,28 @@
1
+ module BB
2
+ #creates a square bounding box sides equal to side_length
3
+ #and southwest corner equal to lat/long
4
+ class SquareBoundingBox < BaseBoundingBox
5
+ def initialize(lat, long, side_length)
6
+ @side_length = parse_side_length(side_length)
7
+ @lat = lat
8
+ @long = long
9
+ @min = fetch_min
10
+ @max = fetch_max
11
+ end
12
+
13
+ private
14
+ def parse_side_length(side_length)
15
+ parsed = side_length.scan(/\d+|mi|km/)
16
+ @preferred_units = parsed[1] || "mi"
17
+ parsed[0].to_f
18
+ end
19
+
20
+ def fetch_min
21
+ {latitude: @lat, longitude: @long}
22
+ end
23
+
24
+ def fetch_max
25
+ BB::PointBoundingBox.new(@lat, @long, "#{@side_length}#{@preferred_units}").max
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module BB
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,3 @@
1
+ Dir[File.dirname(__FILE__) + "/bounding_boxes/*.rb"].each do |file|
2
+ require file
3
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bounding_boxes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tyler Morgan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-23 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: a gem to convert point_radius geolocations to bounding boxes and split
14
+ them into smaller boxes
15
+ email:
16
+ - tylermorgan86@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/bounding_boxes.rb
22
+ - lib/bounding_boxes/base_bounding_box.rb
23
+ - lib/bounding_boxes/bounding_box.rb
24
+ - lib/bounding_boxes/distance.rb
25
+ - lib/bounding_boxes/point_bounding_box.rb
26
+ - lib/bounding_boxes/split_box.rb
27
+ - lib/bounding_boxes/square_bounding_box.rb
28
+ - lib/bounding_boxes/version.rb
29
+ homepage: https://github.com/tylermorgan86/bounding_boxes
30
+ licenses:
31
+ - MIT
32
+ metadata: {}
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 2.2.1
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: geolocation bounding boxes
53
+ test_files: []