bounding_boxes 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/bounding_boxes/base_bounding_box.rb +71 -0
- data/lib/bounding_boxes/bounding_box.rb +73 -0
- data/lib/bounding_boxes/distance.rb +38 -0
- data/lib/bounding_boxes/point_bounding_box.rb +48 -0
- data/lib/bounding_boxes/split_box.rb +10 -0
- data/lib/bounding_boxes/square_bounding_box.rb +28 -0
- data/lib/bounding_boxes/version.rb +3 -0
- data/lib/bounding_boxes.rb +3 -0
- metadata +53 -0
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
|
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: []
|