geo_foo 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/geo_foo.gemspec +5 -3
- data/lib/geo_foo.rb +1 -0
- data/lib/geo_foo/active_record.rb +24 -3
- data/lib/geo_foo/core.rb +13 -42
- data/test/helper.rb +5 -3
- data/test/models/location.rb +5 -0
- data/test/test_geo_foo.rb +66 -9
- data/test_database.yml +4 -0
- metadata +14 -5
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/geo_foo.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{geo_foo}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["agnat", "hukl"]
|
12
|
-
s.date = %q{2010-03-
|
12
|
+
s.date = %q{2010-03-16}
|
13
13
|
s.description = %q{Geo makes it easy to interact with Postgis without hacking too deep into AR. It is in a very early stage and should be considered experimental at most}
|
14
14
|
s.email = %q{contact@smyck.org}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -30,16 +30,18 @@ Gem::Specification.new do |s|
|
|
30
30
|
"lib/geo_foo/numeric.rb",
|
31
31
|
"lib/geo_foo/scope.rb",
|
32
32
|
"test/helper.rb",
|
33
|
+
"test/models/location.rb",
|
33
34
|
"test/test_geo_foo.rb",
|
34
35
|
"test_database.yml"
|
35
36
|
]
|
36
37
|
s.homepage = %q{http://github.com/hukl/geo_foo}
|
37
38
|
s.rdoc_options = ["--charset=UTF-8"]
|
38
39
|
s.require_paths = ["lib"]
|
39
|
-
s.rubygems_version = %q{1.3.
|
40
|
+
s.rubygems_version = %q{1.3.6}
|
40
41
|
s.summary = %q{An experimental and extensible Rails/Postgis library}
|
41
42
|
s.test_files = [
|
42
43
|
"test/helper.rb",
|
44
|
+
"test/models/location.rb",
|
43
45
|
"test/test_geo_foo.rb"
|
44
46
|
]
|
45
47
|
|
data/lib/geo_foo.rb
CHANGED
@@ -2,6 +2,7 @@ module GeoFoo
|
|
2
2
|
module ActiveRecord
|
3
3
|
def self.included(base)
|
4
4
|
base.extend ClassMethods
|
5
|
+
base.send(:include, InstanceMethods)
|
5
6
|
end
|
6
7
|
end
|
7
8
|
|
@@ -11,18 +12,38 @@ module GeoFoo
|
|
11
12
|
def self.within_radius lat, lon, radius
|
12
13
|
scoped(
|
13
14
|
:conditions => [
|
14
|
-
"ST_DWithin(#{GeoFoo
|
15
|
+
"ST_DWithin(#{GeoFoo.as_point(lat,lon)}, "\
|
15
16
|
"point, #{bbox_size(lat, radius)}) AND ST_Distance_Sphere(" \
|
16
|
-
"point, #{GeoFoo
|
17
|
+
"point, #{GeoFoo.as_point(lat,lon)}) < #{radius}"
|
17
18
|
]
|
18
19
|
)
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
24
|
+
# return latitude, longitude for a given id
|
25
|
+
def find_coords_by_id id
|
26
|
+
result = connection.execute(
|
27
|
+
"SELECT ST_Y(point), ST_X(point) FROM #{table_name} WHERE id = #{id}")[0]
|
28
|
+
# Intentionally return (y,x) which corresponds to (lat,lon). See as_point().
|
29
|
+
[result["st_y"].to_f, result["st_x"].to_f]
|
30
|
+
end
|
31
|
+
|
23
32
|
# XXX handle case where lat is (close to) +-90deg (poles)
|
24
33
|
def bbox_size latitude, radius
|
25
|
-
(radius.to_f / (GeoFoo::
|
34
|
+
(radius.to_f / (GeoFoo::EarthRadius * Math.cos(latitude.to_rad))).to_deg
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module InstanceMethods
|
39
|
+
|
40
|
+
def point_to_coords
|
41
|
+
result = self.class.connection.execute(
|
42
|
+
"SELECT ST_Y(point), ST_X(point) FROM #{self.class.table_name} " \
|
43
|
+
"WHERE id = #{self.id}"
|
44
|
+
)[0]
|
45
|
+
|
46
|
+
{ :latitude => result["st_y"].to_f, :longitude => result["st_x"].to_f }
|
26
47
|
end
|
27
48
|
end
|
28
49
|
end
|
data/lib/geo_foo/core.rb
CHANGED
@@ -1,23 +1,18 @@
|
|
1
1
|
module GeoFoo
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# return a postgis string representation of the given coordinates
|
14
|
-
def self.as_point lat, lon
|
15
|
-
# Intentionally use (lat,lon) and not (lon,lat), because latitude is the
|
16
|
-
# 'horizontal' coordinate.
|
17
|
-
# See: http://archives.postgresql.org/pgsql-general/2008-02/msg01393.php
|
18
|
-
"ST_GeomFromText('POINT(#{lon} #{lat})', #{SRID})"
|
19
|
-
end
|
3
|
+
SRID = 4326 # WGS-84
|
4
|
+
EarthRadius = 6370986.0 # meters (as used by postgis' ST_Distance_Sphere())
|
5
|
+
|
6
|
+
# return a postgis string representation of the given coordinates
|
7
|
+
def self.as_point lat, lon
|
8
|
+
# Intentionally use (lat,lon) and not (lon,lat), because latitude is the
|
9
|
+
# 'horizontal' coordinate.
|
10
|
+
# See: http://archives.postgresql.org/pgsql-general/2008-02/msg01393.php
|
11
|
+
"ST_GeomFromText('POINT(#{lon} #{lat})', #{SRID})"
|
12
|
+
end
|
20
13
|
|
14
|
+
module Core
|
15
|
+
|
21
16
|
# find all locations within a radius for a given location
|
22
17
|
def self.find_neighbours_by_coords lat, lon, radius=100.0
|
23
18
|
# compute an appropriate bounding box size for this latitude
|
@@ -29,31 +24,7 @@ module GeoFoo
|
|
29
24
|
"AND #{distance} < #{radius} "\
|
30
25
|
"ORDER BY #{distance}").map { |row| row["id"].to_i }
|
31
26
|
end
|
32
|
-
|
33
|
-
# return latitude, longitude for a given id
|
34
|
-
def self.find_coords_by_id id
|
35
|
-
r = (execute "SELECT ST_Y(point), ST_X(point) FROM #{TableName} "\
|
36
|
-
"WHERE id = #{id}")[0]
|
37
|
-
# Intentionally return (y,x) which corresponds to (lat,lon). See as_point().
|
38
|
-
[r["st_y"].to_f, r["st_x"].to_f]
|
39
|
-
end
|
40
|
-
|
41
|
-
# store a point in the location table. returns the points id.
|
42
|
-
def self.store_location lat, lon
|
43
|
-
(execute "INSERT INTO #{TableName} (point) VALUES (#{as_point(lat,lon)})"\
|
44
|
-
"RETURNING id").first["id"].to_i
|
45
|
-
end
|
46
|
-
|
47
|
-
# delete a location from the database
|
48
|
-
def self.delete_location id
|
49
|
-
execute "DELETE FROM #{TableName} WHERE id = #{id}"
|
50
|
-
end
|
51
|
-
|
52
|
-
# returns the number of locations currently in the database
|
53
|
-
def self.location_count
|
54
|
-
(execute "SELECT count(*) FROM #{TableName}").first["count"].to_i
|
55
|
-
end
|
56
|
-
|
27
|
+
|
57
28
|
# migration helper: create the database table
|
58
29
|
def self.create_table
|
59
30
|
execute "CREATE TABLE #{TableName} (id serial PRIMARY KEY)"
|
data/test/helper.rb
CHANGED
@@ -5,12 +5,11 @@ require 'active_support'
|
|
5
5
|
require 'active_support/test_case'
|
6
6
|
|
7
7
|
config_file = File.join(File.dirname(__FILE__), '..', 'test_database.yml')
|
8
|
-
|
9
|
-
database_config[:adapter] = 'postgresql'
|
10
|
-
ActiveRecord::Base.establish_connection database_config
|
8
|
+
ActiveRecord::Base.establish_connection( YAML.load_file config_file )
|
11
9
|
|
12
10
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
13
11
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
12
|
+
|
14
13
|
require 'geo_foo'
|
15
14
|
|
16
15
|
class ActiveSupport::TestCase
|
@@ -27,5 +26,8 @@ class ActiveSupport::TestCase
|
|
27
26
|
query(sql).first.first
|
28
27
|
end
|
29
28
|
|
29
|
+
def point_for lat, lon
|
30
|
+
execute("SELECT #{GeoFoo.as_point(lat, lon)}")[0]["st_geomfromtext"]
|
31
|
+
end
|
30
32
|
|
31
33
|
end
|
data/test/test_geo_foo.rb
CHANGED
@@ -1,25 +1,82 @@
|
|
1
|
-
require 'geo_foo/core'
|
2
1
|
require 'helper'
|
2
|
+
require 'models/location'
|
3
3
|
|
4
4
|
class TestGeoFoo < ActiveSupport::TestCase
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
|
6
|
+
def setup
|
7
|
+
query = [
|
8
|
+
"CREATE TABLE locations ( id serial PRIMARY KEY );",
|
9
|
+
"SELECT AddGeometryColumn('locations', 'point', 4326, 'POINT', 2);",
|
10
|
+
"CREATE INDEX locations_point_index ON locations USING GIST (point);"
|
11
|
+
].join
|
12
|
+
|
13
|
+
ActiveRecord::Base.connection.execute(query)
|
10
14
|
end
|
11
|
-
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
query = [
|
18
|
+
"DROP TABLE locations;",
|
19
|
+
"DELETE FROM geometry_columns WHERE f_table_name = 'locations';"
|
20
|
+
].join
|
21
|
+
ActiveRecord::Base.connection.execute(query)
|
22
|
+
end
|
23
|
+
|
12
24
|
test "postgis database is present" do
|
13
|
-
assert(query('SELECT
|
25
|
+
assert(query('SELECT postgis_full_version()'), 'postgis functions present')
|
26
|
+
assert(query('SELECT count(*) FROM geometry_columns'), 'postgis tables present')
|
27
|
+
assert(query('SELECT count(*) FROM spatial_ref_sys'), 'postgis tables present')
|
14
28
|
end
|
15
29
|
|
16
30
|
test "as_point" do
|
17
31
|
latitude = 5
|
18
32
|
longitude = 42
|
19
|
-
point = GeoFoo
|
33
|
+
point = GeoFoo.as_point latitude, longitude
|
20
34
|
assert(query("SELECT #{point}"))
|
21
35
|
assert_equal(query_scalar("SELECT ST_X(#{point})").to_i, 42)
|
22
36
|
assert_equal(query_scalar("SELECT ST_Y(#{point})").to_i, 5)
|
23
37
|
end
|
24
38
|
|
39
|
+
test "setup of Location model" do
|
40
|
+
assert_not_nil Location
|
41
|
+
end
|
42
|
+
|
43
|
+
test "creating a location" do
|
44
|
+
assert_not_nil Location.create :point => point_for( 53.0, 13.0 )
|
45
|
+
end
|
46
|
+
|
47
|
+
test "within_radius is defined" do
|
48
|
+
assert defined?(Location.within_radius), '#within_radius is not defined'
|
49
|
+
end
|
50
|
+
|
51
|
+
test "as_point is defined" do
|
52
|
+
assert defined?(GeoFoo.as_point), '#as_point is not defined'
|
53
|
+
end
|
54
|
+
|
55
|
+
test "find locations within radius" do
|
56
|
+
Location.create :point => point_for( 53.0000001, 13.0000001 )
|
57
|
+
Location.create :point => point_for( 53.0000002, 13.0000002 )
|
58
|
+
|
59
|
+
assert_equal 2, Location.within_radius(53.0000001, 13.0000001, 100.0).size
|
60
|
+
end
|
61
|
+
|
62
|
+
test "find no locations within radius" do
|
63
|
+
Location.create :point => point_for( 53.0000001, 13.0000001 )
|
64
|
+
Location.create :point => point_for( 53.0000002, 13.0000002 )
|
65
|
+
|
66
|
+
assert_equal 0, Location.within_radius(54.0, 14.0, 100.0).size
|
67
|
+
end
|
68
|
+
|
69
|
+
test "point to coords" do
|
70
|
+
location = Location.create :point => point_for( 53.1, 13.1 )
|
71
|
+
|
72
|
+
assert (53.09...53.11).include?( location.point_to_coords[:latitude] )
|
73
|
+
assert (13.09...13.11).include?( location.point_to_coords[:longitude] )
|
74
|
+
end
|
75
|
+
|
76
|
+
test "find_coords_by_id" do
|
77
|
+
Location.create :point => point_for( 53.1, 13.1 )
|
78
|
+
assert (53.09...53.11).include?( Location.find_coords_by_id(Location.last.id)[0])
|
79
|
+
assert (13.09...13.11).include?( Location.find_coords_by_id(Location.last.id)[1])
|
80
|
+
end
|
81
|
+
|
25
82
|
end
|
data/test_database.yml
CHANGED
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geo_foo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
version: 0.0.3
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- agnat
|
@@ -10,7 +15,7 @@ autorequire:
|
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
17
|
|
13
|
-
date: 2010-03-
|
18
|
+
date: 2010-03-16 00:00:00 +01:00
|
14
19
|
default_executable:
|
15
20
|
dependencies: []
|
16
21
|
|
@@ -37,6 +42,7 @@ files:
|
|
37
42
|
- lib/geo_foo/numeric.rb
|
38
43
|
- lib/geo_foo/scope.rb
|
39
44
|
- test/helper.rb
|
45
|
+
- test/models/location.rb
|
40
46
|
- test/test_geo_foo.rb
|
41
47
|
- test_database.yml
|
42
48
|
has_rdoc: true
|
@@ -52,21 +58,24 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
52
58
|
requirements:
|
53
59
|
- - ">="
|
54
60
|
- !ruby/object:Gem::Version
|
61
|
+
segments:
|
62
|
+
- 0
|
55
63
|
version: "0"
|
56
|
-
version:
|
57
64
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
65
|
requirements:
|
59
66
|
- - ">="
|
60
67
|
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
61
70
|
version: "0"
|
62
|
-
version:
|
63
71
|
requirements: []
|
64
72
|
|
65
73
|
rubyforge_project:
|
66
|
-
rubygems_version: 1.3.
|
74
|
+
rubygems_version: 1.3.6
|
67
75
|
signing_key:
|
68
76
|
specification_version: 3
|
69
77
|
summary: An experimental and extensible Rails/Postgis library
|
70
78
|
test_files:
|
71
79
|
- test/helper.rb
|
80
|
+
- test/models/location.rb
|
72
81
|
- test/test_geo_foo.rb
|