gotime-postgis_adapter 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +13 -0
- data/Gemfile.lock +31 -0
- data/History.txt +6 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +380 -0
- data/Rakefile +70 -0
- data/lib/postgis_adapter/acts_as_geom.rb +43 -0
- data/lib/postgis_adapter/common_spatial_adapter.rb +105 -0
- data/lib/postgis_adapter/functions/bbox.rb +130 -0
- data/lib/postgis_adapter/functions/class.rb +67 -0
- data/lib/postgis_adapter/functions/common.rb +921 -0
- data/lib/postgis_adapter/functions.rb +174 -0
- data/lib/postgis_adapter/railtie.rb +7 -0
- data/lib/postgis_adapter.rb +446 -0
- data/postgis_adapter.gemspec +19 -0
- data/rails/init.rb +28 -0
- data/spec/db/models_postgis.rb +65 -0
- data/spec/db/schema_postgis.rb +98 -0
- data/spec/postgis_adapter/acts_as_geom_spec.rb +30 -0
- data/spec/postgis_adapter/common_spatial_adapter_spec.rb +254 -0
- data/spec/postgis_adapter/functions/bbox_spec.rb +45 -0
- data/spec/postgis_adapter/functions/class_spec.rb +79 -0
- data/spec/postgis_adapter/functions/common_spec.rb +428 -0
- data/spec/postgis_adapter/functions_spec.rb +60 -0
- data/spec/postgis_adapter_spec.rb +238 -0
- data/spec/spec_helper.rb +45 -0
- metadata +93 -0
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
gem "pg"
|
4
|
+
gem "nofxx-georuby"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "rspec", "~> 2.3.0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "rcov", ">= 0"
|
12
|
+
gem "autotest"
|
13
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
ZenTest (4.5.0)
|
5
|
+
autotest (4.4.6)
|
6
|
+
ZenTest (>= 4.4.1)
|
7
|
+
diff-lcs (1.1.2)
|
8
|
+
json_pure (1.4.6)
|
9
|
+
nofxx-georuby (1.9.0)
|
10
|
+
json_pure (>= 1.4.6)
|
11
|
+
pg (0.10.1)
|
12
|
+
rcov (0.9.9)
|
13
|
+
rspec (2.3.0)
|
14
|
+
rspec-core (~> 2.3.0)
|
15
|
+
rspec-expectations (~> 2.3.0)
|
16
|
+
rspec-mocks (~> 2.3.0)
|
17
|
+
rspec-core (2.3.1)
|
18
|
+
rspec-expectations (2.3.0)
|
19
|
+
diff-lcs (~> 1.1.2)
|
20
|
+
rspec-mocks (2.3.0)
|
21
|
+
|
22
|
+
PLATFORMS
|
23
|
+
ruby
|
24
|
+
|
25
|
+
DEPENDENCIES
|
26
|
+
autotest
|
27
|
+
bundler (~> 1.0.0)
|
28
|
+
nofxx-georuby
|
29
|
+
pg
|
30
|
+
rcov
|
31
|
+
rspec (~> 2.3.0)
|
data/History.txt
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Spatial Adapter Copyright (c) 2006 Guilhem Vellut <guilhem.vellut+georuby@gmail.com>
|
2
|
+
PostGis Adapter Functions (c) 2008 Marcos Piccinini <nofxx>
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,380 @@
|
|
1
|
+
= PostgisAdapter
|
2
|
+
|
3
|
+
A plugin for ActiveRecord which manages the PostGIS geometric columns
|
4
|
+
in a transparent way (that is like the other base data type columns).
|
5
|
+
It also provides a way to manage these columns in migrations.
|
6
|
+
|
7
|
+
This fork adds handy methods to make geometrical calculations on postgis.
|
8
|
+
Based on http://georuby.rubyforge.org Spatial Adapter
|
9
|
+
|
10
|
+
RDocs - http://docs.github.com/nofxx/postgis_adapter
|
11
|
+
Postgis Online reference - http://postgis.refractions.net
|
12
|
+
Postgis Manual - http://postgis.refractions.net/documentation/manual-svn
|
13
|
+
|
14
|
+
|
15
|
+
== Install
|
16
|
+
|
17
|
+
If you are using Spatial Adapter, *remove it first*.
|
18
|
+
|
19
|
+
gem install postgis_adapter
|
20
|
+
|
21
|
+
|
22
|
+
=== Dependencies
|
23
|
+
|
24
|
+
- georuby gem
|
25
|
+
- postgres 8.3+
|
26
|
+
- postgis 1.3+
|
27
|
+
|
28
|
+
|
29
|
+
=== Rails 3+
|
30
|
+
|
31
|
+
Add dependency to Gemfile:
|
32
|
+
|
33
|
+
gem "postgis_adapter"
|
34
|
+
|
35
|
+
|
36
|
+
Or, to use latest from repository:
|
37
|
+
|
38
|
+
gem "postgis_adapter", :git => 'git://github.com/nofxx/postgis_adapter.git'
|
39
|
+
|
40
|
+
|
41
|
+
=== Rails 2
|
42
|
+
|
43
|
+
gem install postgis_adapter -v 0.7.8
|
44
|
+
|
45
|
+
|
46
|
+
== How to Use
|
47
|
+
|
48
|
+
Geometric columns in your ActiveRecord models now appear just like
|
49
|
+
any other column of other basic data types. They can also be dumped
|
50
|
+
in ruby schema mode and loaded in migrations the same way as columns
|
51
|
+
of basic types.
|
52
|
+
|
53
|
+
|
54
|
+
=== Example App
|
55
|
+
|
56
|
+
Simple rails app to demonstrate, check it out:
|
57
|
+
|
58
|
+
http://github.com/nofxx/postgis_example
|
59
|
+
|
60
|
+
|
61
|
+
=== Model
|
62
|
+
|
63
|
+
class TablePoint < ActiveRecord::Base
|
64
|
+
end
|
65
|
+
|
66
|
+
That was easy! As you see, there is no need to declare a column as geometric.
|
67
|
+
The plugin will get this information by itself.
|
68
|
+
|
69
|
+
Here is an example of PostGIS row creation and access, using the
|
70
|
+
model and the table defined above :
|
71
|
+
|
72
|
+
pt = TablePoint.new(:data => "Hello!",:geom => Point.from_x_y(1,2))
|
73
|
+
pt.save
|
74
|
+
pt = TablePoint.first
|
75
|
+
puts pt.geom.x
|
76
|
+
=> 1
|
77
|
+
|
78
|
+
|
79
|
+
== PostGIS Functions
|
80
|
+
|
81
|
+
Here are this fork additions. To use it:
|
82
|
+
|
83
|
+
acts_as_geom [column_name] => [geom_type]
|
84
|
+
|
85
|
+
|
86
|
+
Examples:
|
87
|
+
|
88
|
+
class POI < ActiveRecord::Base
|
89
|
+
acts_as_geom :geom => :point
|
90
|
+
end
|
91
|
+
|
92
|
+
class Street < ActiveRecord::Base
|
93
|
+
acts_as_geom :line => :line_string
|
94
|
+
end
|
95
|
+
|
96
|
+
...
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
== Play!
|
101
|
+
|
102
|
+
@place = Poi.new( :geom => Point.from_x_y(10,20) )
|
103
|
+
@park = Park.new( :area => **Polygon** )
|
104
|
+
@street = Street.new( :line => **LineString** )
|
105
|
+
|
106
|
+
@place.inside?(@park)
|
107
|
+
=> true
|
108
|
+
|
109
|
+
@place.in_bounds?(@park, 0.5) # margin
|
110
|
+
=> false
|
111
|
+
|
112
|
+
@place.outside?(@park)
|
113
|
+
@street.crosses?(@park)
|
114
|
+
@area.contains?(@place)
|
115
|
+
...
|
116
|
+
|
117
|
+
|
118
|
+
=== Polygons:
|
119
|
+
|
120
|
+
@park.area
|
121
|
+
=> 1345
|
122
|
+
|
123
|
+
@park.contains?(@point)
|
124
|
+
=> true
|
125
|
+
|
126
|
+
@park.overlaps?(@other_park)
|
127
|
+
=> false
|
128
|
+
|
129
|
+
Supports transform (useful to transform SRID to UTM for area in Km^2)
|
130
|
+
|
131
|
+
@park.area(SRID)
|
132
|
+
=> Area with new SRID
|
133
|
+
|
134
|
+
|
135
|
+
=== LineStrings:
|
136
|
+
|
137
|
+
@street_east.intersects?(@street_west)
|
138
|
+
=> false
|
139
|
+
|
140
|
+
@street_central.length
|
141
|
+
=> 4508.53636
|
142
|
+
|
143
|
+
@street.length_spheroid
|
144
|
+
=> 4.40853636
|
145
|
+
|
146
|
+
|
147
|
+
=== Class Methods
|
148
|
+
|
149
|
+
City.close_to(@point)
|
150
|
+
=> [Array of cities in order by distance...
|
151
|
+
|
152
|
+
Street.close_to(@point)
|
153
|
+
=> [Array streets in order by distance...
|
154
|
+
|
155
|
+
Country.contain(@point)
|
156
|
+
=> The Conutry that contains the point
|
157
|
+
|
158
|
+
Area.contains(@point)
|
159
|
+
=> [Array of areas contains the point...
|
160
|
+
|
161
|
+
|
162
|
+
=== BBox Support
|
163
|
+
|
164
|
+
@area.strictly_left_of? @point
|
165
|
+
|
166
|
+
@area.overlaps_or_above? @street
|
167
|
+
|
168
|
+
...
|
169
|
+
|
170
|
+
completely_contained_by?
|
171
|
+
completely_contains?
|
172
|
+
overlaps_or_above?
|
173
|
+
overlaps_or_below?
|
174
|
+
overlaps_or_left_of?
|
175
|
+
overlaps_or_right_of?
|
176
|
+
strictly_above?
|
177
|
+
strictly_below?
|
178
|
+
strictly_left_of?
|
179
|
+
strictly_right_of?
|
180
|
+
interacts_with?
|
181
|
+
binary_equal?
|
182
|
+
same_as?
|
183
|
+
|
184
|
+
|
185
|
+
Or use a (almost) PostGIS like notation:
|
186
|
+
|
187
|
+
@area.bbox "<<", @point
|
188
|
+
|
189
|
+
@area.bbox "|>>", @point
|
190
|
+
|
191
|
+
@area.bbox "@", @park
|
192
|
+
|
193
|
+
|
194
|
+
=== Warning
|
195
|
+
|
196
|
+
*To be fixed:*
|
197
|
+
|
198
|
+
This only supports one geom column per model. Still looking for the best way to
|
199
|
+
implement a multi geom.
|
200
|
+
|
201
|
+
http://nofxx.lighthouseapp.com/projects/20712/tickets/3-multiple-geoms-in-model
|
202
|
+
|
203
|
+
|
204
|
+
=== Find_by
|
205
|
+
|
206
|
+
find_by_*column* has been redefined when column is of a geometric type.
|
207
|
+
Instead of using the Rails default '=' operator, for which I can't see
|
208
|
+
a definition for MySql spatial datatypes and which performs a bounding
|
209
|
+
box equality test in PostGIS, it uses a bounding box intersection:
|
210
|
+
&& in PostGIS and MBRIntersects in MySQL, which can both make use
|
211
|
+
of a spatial index if one is present to speed up the queries.
|
212
|
+
You could use this query, for example, if you need to display data
|
213
|
+
from the database: You would want only the geometries which are in
|
214
|
+
the screen rectangle and you could use a bounding box query for that.
|
215
|
+
Since this is a common case, it is the default. You have 2 ways to use
|
216
|
+
the find_by_*geom_column*: Either by passing a geometric object directly,
|
217
|
+
or passing an array with the 2 opposite corners of a bounding box
|
218
|
+
(with 2 or 3 coordinates depending of the dimension of the data).
|
219
|
+
|
220
|
+
Park.find_by_geom(LineString.from_coordinates([[1.4,5.6],[2.7,8.9],[1.6,5.6]]))
|
221
|
+
|
222
|
+
or
|
223
|
+
|
224
|
+
Park.find_by_geom([[3,5.6],[19.98,5.9]])
|
225
|
+
|
226
|
+
In PostGIS, since you can only use operations with geometries with the same SRID, you can add a third element representing the SRID of the bounding box to the array. It is by default set to -1:
|
227
|
+
|
228
|
+
Park.find_by_geom([[3,5.6],[19.98,5.9],123])
|
229
|
+
|
230
|
+
|
231
|
+
|
232
|
+
== Database Tools
|
233
|
+
|
234
|
+
=== Migrations
|
235
|
+
|
236
|
+
Here is an example of code for the creation of a table with a
|
237
|
+
geometric column in PostGIS, along with the addition of a spatial
|
238
|
+
index on the column :
|
239
|
+
|
240
|
+
ActiveRecord::Schema.define do
|
241
|
+
create_table :places do |t|
|
242
|
+
t.string :name
|
243
|
+
t.point :geom, :srid => 4326, :with_z => true, :null => false
|
244
|
+
|
245
|
+
t.timestamps
|
246
|
+
end
|
247
|
+
|
248
|
+
add_index :places, :geom, :spatial => true
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
Types:
|
253
|
+
|
254
|
+
point
|
255
|
+
polygon
|
256
|
+
line_string
|
257
|
+
multi_point
|
258
|
+
multi_polygon
|
259
|
+
multi_line_string
|
260
|
+
geometry
|
261
|
+
geometry_collection
|
262
|
+
|
263
|
+
|
264
|
+
=== PostGIS Helper Scripts
|
265
|
+
|
266
|
+
Optional, this will create postgis enabled database automatically for you.
|
267
|
+
|
268
|
+
Helpers to create postgis template database. At time of writing,
|
269
|
+
postgis.sql and spatial_ref_sys.sql are used.
|
270
|
+
|
271
|
+
|
272
|
+
==== System wide
|
273
|
+
|
274
|
+
|
275
|
+
Find where your OS put those sql files and:
|
276
|
+
|
277
|
+
rake postgis:template path/to/sqls/folder
|
278
|
+
|
279
|
+
|
280
|
+
==== Vendorize
|
281
|
+
|
282
|
+
Place the following scripts in a folder named 'spatial' under the 'db' folder; For example:
|
283
|
+
|
284
|
+
RAILS_ROOT/db/spatial/lwpostgis.sql
|
285
|
+
RAILS_ROOT/db/spatial/spatial_ref_sys
|
286
|
+
|
287
|
+
These will be used when creating the Test database when running the Rake Test tasks.
|
288
|
+
These scripts should have been installed when the PostGIS libraries were installed.
|
289
|
+
Online reference: http://postgis.refractions.net/
|
290
|
+
|
291
|
+
|
292
|
+
=== Fixtures
|
293
|
+
|
294
|
+
If you use fixtures for your unit tests, at some point,
|
295
|
+
you will want to input a geometry. You could transform your
|
296
|
+
geometries to a form suitable for YAML yourself everytime but
|
297
|
+
the spatial adapter provides a method to do it for you: +to_yaml+.
|
298
|
+
It works for both MySQL and PostGIS (although the string returned
|
299
|
+
is different for each database). You would use it like this, if
|
300
|
+
the geometric column is a point:
|
301
|
+
|
302
|
+
fixture:
|
303
|
+
id: 1
|
304
|
+
data: HELLO
|
305
|
+
geom: <%= Point.from_x_y(123.5,321.9).to_yaml %>
|
306
|
+
|
307
|
+
|
308
|
+
=== Annotate
|
309
|
+
|
310
|
+
If you are using annotate_models, check out this fork which adds geometrical annotations for PostgisAdapter and SpatialAdapter:
|
311
|
+
|
312
|
+
http://github.com/nofxx/annotate_models
|
313
|
+
|
314
|
+
|
315
|
+
== Geometric data types
|
316
|
+
|
317
|
+
Ruby geometric datatypes are currently made available only through
|
318
|
+
the GeoRuby library (http://georuby.rubyforge.org): This is where the
|
319
|
+
*Point.from_x_y* in the example above comes from. It is a goal
|
320
|
+
of a future release of the Spatial Adapter to support additional
|
321
|
+
geometric datatype libraries, such as Ruby/GEOS, as long as they
|
322
|
+
can support reading and writing of EWKB.
|
323
|
+
|
324
|
+
|
325
|
+
|
326
|
+
=== Warning
|
327
|
+
|
328
|
+
- Since ActiveRecord seems to keep only the string values directly
|
329
|
+
returned from the database, it translates from these to the correct
|
330
|
+
types everytime an attribute is read, which is probably ok for simple
|
331
|
+
types, but might be less than efficient for geometries, since the EWKB
|
332
|
+
string has to be parsed everytime. Also it means you cannot modify the
|
333
|
+
geometry object returned from an attribute directly :
|
334
|
+
|
335
|
+
place = Place.first
|
336
|
+
place.the_geom.y=123456.7
|
337
|
+
|
338
|
+
- Since the translation to a geometry is performed everytime the_geom
|
339
|
+
is read, the change to y will not be saved! You would have to do
|
340
|
+
something like this :
|
341
|
+
|
342
|
+
place = Place.first
|
343
|
+
the_geom = place.the_geom
|
344
|
+
the_geom.y=123456.7
|
345
|
+
place.the_geom = the_geom
|
346
|
+
|
347
|
+
|
348
|
+
== Postgis Adapter
|
349
|
+
|
350
|
+
Marcos Piccinini (nofxx)
|
351
|
+
Ying Tsen Hong (tsenying)
|
352
|
+
Simon Tokumine (tokumine)
|
353
|
+
Fernando Blat (ferblape)
|
354
|
+
Shoaib Burq (sabman)
|
355
|
+
|
356
|
+
(in order of appearance)
|
357
|
+
|
358
|
+
|
359
|
+
== License
|
360
|
+
|
361
|
+
Spatial Adapter for Rails is released under the MIT license.
|
362
|
+
Postgis Adapter is released under the MIT license.
|
363
|
+
|
364
|
+
|
365
|
+
== Support
|
366
|
+
|
367
|
+
Tested using activerecord 3+ / postgresql 8.5+ / postgis 1.5+ / linux / osx
|
368
|
+
|
369
|
+
Any questions, enhancement proposals, bug notifications or corrections:
|
370
|
+
|
371
|
+
|
372
|
+
=== PostgisAdapter
|
373
|
+
|
374
|
+
http://github.com/nofxx/postgis_adapter/issues
|
375
|
+
|
376
|
+
|
377
|
+
=== SpatialAdapter
|
378
|
+
|
379
|
+
http://georuby.rubyforge.org
|
380
|
+
guilhem.vellut+georuby@gmail.com.
|
data/Rakefile
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
#require 'spec/rake/spectask'
|
6
|
+
|
7
|
+
CLEAN.include('**/*.gem')
|
8
|
+
|
9
|
+
namespace :gem do
|
10
|
+
desc "Create the postgis_adapter gem"
|
11
|
+
task :create => [:clean] do
|
12
|
+
spec = eval(IO.read('postgis_adapter.gemspec'))
|
13
|
+
Gem::Builder.new(spec).build
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Install the postgis_adapter gem"
|
17
|
+
task :install => [:create] do
|
18
|
+
file = Dir['*.gem'].first
|
19
|
+
sh "gem install #{file}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
# spec.libs << 'lib' << 'spec'
|
25
|
+
# spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
# end
|
27
|
+
|
28
|
+
# Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
# spec.libs << 'lib' << 'spec'
|
30
|
+
# spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
# spec.rcov = true
|
32
|
+
# end
|
33
|
+
|
34
|
+
Rake::RDocTask.new do |rdoc|
|
35
|
+
version = File.exist?('VERSION') ? File.read('VERSION').chomp : ""
|
36
|
+
rdoc.rdoc_dir = 'rdoc'
|
37
|
+
rdoc.title = "postgis_adapter #{version}"
|
38
|
+
rdoc.rdoc_files.include('README*')
|
39
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
40
|
+
end
|
41
|
+
|
42
|
+
task :default => :spec
|
43
|
+
|
44
|
+
#
|
45
|
+
# Reek & Roodi
|
46
|
+
#
|
47
|
+
begin
|
48
|
+
require 'reek/rake_task'
|
49
|
+
Reek::RakeTask.new do |t|
|
50
|
+
t.fail_on_error = true
|
51
|
+
t.verbose = false
|
52
|
+
t.source_files = 'lib/**/*.rb'
|
53
|
+
end
|
54
|
+
rescue LoadError
|
55
|
+
task :reek do
|
56
|
+
abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
begin
|
61
|
+
require 'roodi'
|
62
|
+
require 'roodi_task'
|
63
|
+
RoodiTask.new do |t|
|
64
|
+
t.verbose = false
|
65
|
+
end
|
66
|
+
rescue LoadError
|
67
|
+
task :roodi do
|
68
|
+
abort "Roodi is not available. In order to run roodi, you must: sudo gem install roodi"
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# PostGIS Adapter
|
3
|
+
#
|
4
|
+
# http://github.com/nofxx/postgis_adapter
|
5
|
+
#
|
6
|
+
module PostgisAdapter
|
7
|
+
module Functions
|
8
|
+
def self.included(base)
|
9
|
+
base.send :extend, ClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
# has_geom :db_field => :geom_type
|
15
|
+
# Examples:
|
16
|
+
#
|
17
|
+
# has_geom :data => :point
|
18
|
+
# has_geom :geom => :line_string
|
19
|
+
# has_geom :geom => :polygon
|
20
|
+
#
|
21
|
+
def has_geom(*geom)
|
22
|
+
cattr_accessor :postgis_geoms
|
23
|
+
self.postgis_geoms = geom[0] # {:columns => column
|
24
|
+
send :include, case geom[0].values[0]
|
25
|
+
when :point then PointFunctions
|
26
|
+
when :polygon then PolygonFunctions
|
27
|
+
when :line_string, :multi_line_string then LineStringFunctions
|
28
|
+
when :multi_polygon then MultiPolygonFunctions
|
29
|
+
end unless geom[0].kind_of? Symbol
|
30
|
+
end
|
31
|
+
alias :acts_as_geom :has_geom
|
32
|
+
|
33
|
+
def get_geom_type(column)
|
34
|
+
self.postgis_geoms.values[0] rescue nil
|
35
|
+
# self.columns.select { |c| c.name == column.to_s }[0].geometry_type
|
36
|
+
# rescue ActiveRecord::StatementInvalid => e
|
37
|
+
# nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
ActiveRecord::Base.send :include, PostgisAdapter::Functions
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#
|
2
|
+
# PostGIS Adapter
|
3
|
+
#
|
4
|
+
# Common Spatial Adapter for ActiveRecord
|
5
|
+
#
|
6
|
+
# Code from
|
7
|
+
# http://georuby.rubyforge.org Spatial Adapter
|
8
|
+
#
|
9
|
+
|
10
|
+
#Addition of a flag indicating if the index is spatial
|
11
|
+
ActiveRecord::ConnectionAdapters::IndexDefinition.class_eval do
|
12
|
+
attr_accessor :spatial
|
13
|
+
|
14
|
+
def initialize(table, name, unique, spatial,columns)
|
15
|
+
super(table,name,unique,columns)
|
16
|
+
@spatial = spatial
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
module SpatialAdapter
|
22
|
+
#Translation of geometric data types
|
23
|
+
def geometry_data_types
|
24
|
+
{
|
25
|
+
:point => { :name => "POINT" },
|
26
|
+
:line_string => { :name => "LINESTRING" },
|
27
|
+
:polygon => { :name => "POLYGON" },
|
28
|
+
:geometry_collection => { :name => "GEOMETRYCOLLECTION" },
|
29
|
+
:multi_point => { :name => "MULTIPOINT" },
|
30
|
+
:multi_line_string => { :name => "MULTILINESTRING" },
|
31
|
+
:multi_polygon => { :name => "MULTIPOLYGON" },
|
32
|
+
:geometry => { :name => "GEOMETRY"}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
#using a mixin instead of subclassing Column since each adapter can have a specific subclass of Column
|
40
|
+
module SpatialColumn
|
41
|
+
attr_reader :geometry_type, :srid, :with_z, :with_m
|
42
|
+
|
43
|
+
def initialize(name, default, sql_type = nil, null = true,srid=-1,with_z=false,with_m=false)
|
44
|
+
super(name,default,sql_type,null)
|
45
|
+
@geometry_type = geometry_simplified_type(@sql_type)
|
46
|
+
@srid = srid
|
47
|
+
@with_z = with_z
|
48
|
+
@with_m = with_m
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
#Redefines type_cast to add support for geometries
|
53
|
+
def type_cast(value)
|
54
|
+
return nil if value.nil?
|
55
|
+
case type
|
56
|
+
when :geometry then self.class.string_to_geometry(value)
|
57
|
+
else super
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
#Redefines type_cast_code to add support for geometries.
|
62
|
+
#
|
63
|
+
#WARNING : Since ActiveRecord keeps only the string values directly returned from the database, it translates from these to the correct types everytime an attribute is read (using the code returned by this method), which is probably ok for simple types, but might be less than efficient for geometries. Also you cannot modify the geometry object returned directly or your change will not be saved.
|
64
|
+
def type_cast_code(var_name)
|
65
|
+
case type
|
66
|
+
when :geometry then "#{self.class.name}.string_to_geometry(#{var_name})"
|
67
|
+
else super
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
#Redefines klass to add support for geometries
|
73
|
+
def klass
|
74
|
+
case type
|
75
|
+
when :geometry then GeoRuby::SimpleFeatures::Geometry
|
76
|
+
else super
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
#Redefines the simplified_type method to add behaviour for when a column is of type geometry
|
83
|
+
def simplified_type(field_type)
|
84
|
+
case field_type
|
85
|
+
when /geometry|point|linestring|polygon|multipoint|multilinestring|multipolygon|geometrycollection/i then :geometry
|
86
|
+
else super
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
#less simlpified geometric type to be use in migrations
|
91
|
+
def geometry_simplified_type(field_type)
|
92
|
+
case field_type
|
93
|
+
when /^point$/i then :point
|
94
|
+
when /^linestring$/i then :line_string
|
95
|
+
when /^polygon$/i then :polygon
|
96
|
+
when /^geometry$/i then :geometry
|
97
|
+
when /multipoint/i then :multi_point
|
98
|
+
when /multilinestring/i then :multi_line_string
|
99
|
+
when /multipolygon/i then :multi_polygon
|
100
|
+
when /geometrycollection/i then :geometry_collection
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
end
|