geo_foo 0.0.1 → 0.0.3
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/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
|