Just wanted to post this in case someone else was faced with the same
problem. It''s database-specific code, worse, it''s specific to
a particular *
version* of a particular *extension* to a particular database, wires in
SQL, and uses eval on a string of data from the database!
So, you know, I''m getting coal in my stocking from DHH this year. I can
deal. (After the whole Jolt Award thing years back, though, he totally owes
me, I wanted to keep that thing so bad...)
Anyway, problem is this: I wanted to do some calculations on some
geospatial raster data, which are to be stored in a GIS-enabled database.
I''d chosen PostGIS long ago for various reasons. But even the fabulous
RGeo
gem doesn''t know from rasters, or at least not yet AFAIK. So
there''s no way
to get pixels out of the raster except one-by-one with an ST_Value query;
for a 297x582 array, a nonstarter.
Enter PostGIS 2.1 and its lovely lovely ST_DumpValues and ST_SetValues
functions. By using the connection''s select_value method, we can return
an
arbitrary SQL result as a string, in this case a 2D array coded with the
PostgreSQL convention of { and } where Ruby uses [ and ].
Likewise, connection.update can take an SQL string, and we can wad a 2D
array of values into it with a simple to_s.
So here''s the hack:
# Get and set raster band values out of PostGIS 2.1 rasters as Ruby arrays.
# This example assumes that the raster column is ''rast'' and
that the primary
# key for the table is ''rid''. Also, NULL pixels will probably
tank the getter.
# Fixing those is left as an exercise :-)
class PostGisRaster < ActiveRecord::Base
self.primary_key = ''rid''
# Grab a band of a raster out of the database and convert it to a 2D array.
Defaults to first band (1)
def self.to_a(tablename,id,band=1)
id = id.to_i
str = connection.select_value("select st_dumpvalues(rast,#{band}) from
#{tablename} where #{primary_key}=#{id}")
str.gsub!(''{'',''['')
str.gsub!(''}'','']'')
eval(str)
end
# Update a raster band (default: first band) in the database with values from
arr. Note that arr can be any
# subset of the size of the full raster. Corner is X,Y (or long,lat), with the
upper left corner as [1,1].
def self.update_raster(tablename,id,arr,band=1,corner=[1,1])
update_str = <<-END
select st_setvalues(
(select rast from #{tablename} where rid=#{id}),
#{band},#{corner[0]},#{corner[1]},
array#{arr.to_s}::double precision[][]
)
END
update_str = "update #{tablename} set rast=(#{update_str}) where
rid=#{id}"
puts "update_str: ''#{update_str}''"
connection.update(update_str)
end
end
--
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to
rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
To view this discussion on the web visit
https://groups.google.com/d/msgid/rubyonrails-talk/93370b4e-4bb3-4099-bd72-59a5bc31db2a%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.