class GeoRuby::Shp4r::ShpTransaction
An object returned from GeoRuby::Shp4r::ShpFile#transaction. Buffers updates to a Shapefile
Attributes
rollbacked[R]
Public Class Methods
new(shp, dbf)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 343 def initialize(shp, dbf) @deleted = Hash.new @added = Array.new @shp = shp @dbf = dbf end
Public Instance Methods
add(record)
click to toggle source
add a ShpRecord at the end
# File lib/geo_ruby/shp4r/shp.rb, line 363 def add(record) record_type = to_shp_type(record.geometry) raise IncompatibleGeometryException.new("Incompatible type") unless record_type==@shp.shp_type @added << record end
commit()
click to toggle source
updates the physical files
# File lib/geo_ruby/shp4r/shp.rb, line 370 def commit @shp.close @shp_r = open(@shp.file_root + ".shp", "rb") @dbf_r = open(@shp.file_root + ".dbf", "rb") @shp_io = open(@shp.file_root + ".shp.tmp.shp", "wb") @shx_io = open(@shp.file_root + ".shx.tmp.shx", "wb") @dbf_io = open(@shp.file_root + ".dbf.tmp.dbf", "wb") index = commit_delete min_x,max_x,min_y,max_y,min_z,max_z,min_m,max_m = commit_add(index) commit_finalize(min_x,max_x,min_y,max_y,min_z,max_z,min_m,max_m) @shp_r.close @dbf_r.close @dbf_io.close @shp_io.close @shx_io.close FileUtils.move(@shp.file_root + ".shp.tmp.shp", @shp.file_root + ".shp") FileUtils.move(@shp.file_root + ".shx.tmp.shx", @shp.file_root + ".shx") FileUtils.move(@shp.file_root + ".dbf.tmp.dbf", @shp.file_root + ".dbf") @deleted = Hash.new @added = Array.new @shp.reload! end
delete(i)
click to toggle source
delete a record. Does not take into account the records added in the current transaction
# File lib/geo_ruby/shp4r/shp.rb, line 351 def delete(i) raise UnexistantRecordException.new("Invalid index : #{i}") if @shp.record_count <= i @deleted[i] = true end
rollback()
click to toggle source
prevents the udpate from taking place
# File lib/geo_ruby/shp4r/shp.rb, line 396 def rollback @deleted = Hash.new @added = Array.new @rollbacked = true end
update(i, record)
click to toggle source
Update a record. In effect just a delete followed by an add.
# File lib/geo_ruby/shp4r/shp.rb, line 357 def update(i, record) delete(i) add(record) end
Private Instance Methods
build_multi_point(geometry,str)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 672 def build_multi_point(geometry,str) str << [geometry.length].pack("V") geometry.each do |point| str << [point.x,point.y].pack("E2") end str end
build_multi_point_zm(geometry,zm,range,str)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 680 def build_multi_point_zm(geometry,zm,range,str) str << range.pack("E2") geometry.each do |point| str << [point.instance_variable_get(zm)].pack("E") end str end
build_polygon(geometry,str)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 627 def build_polygon(geometry,str) if geometry.is_a? GeoRuby::SimpleFeatures::Polygon str << [geometry.length,geometry.inject(0) {|l, lr| l + lr.length}].pack("V2") str << geometry.inject([0]) {|a,lr| a << (a.last + lr.length)}.pack("V#{geometry.length}") #last element of the previous array is dropped geometry.each do |lr| lr.each do |point| str << [point.x,point.y].pack("E2") end end else #multipolygon num_rings = geometry.inject(0) {|l, poly| l + poly.length} str << [num_rings, geometry.inject(0) {|l, poly| l + poly.inject(0) {|l2,lr| l2 + lr.length} }].pack("V2") str << geometry.inject([0]) {|a,poly| poly.inject(a) {|a2, lr| a2 << (a2.last + lr.length)}}.pack("V#{num_rings}") #last element of the previous array is dropped geometry.each do |poly| poly.each do |lr| lr.each do |point| str << [point.x,point.y].pack("E2") end end end end str end
build_polygon_zm(geometry,zm,range,str)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 652 def build_polygon_zm(geometry,zm,range,str) str << range.pack("E2") if geometry.is_a? GeoRuby::SimpleFeatures::Polygon geometry.each do |lr| lr.each do |point| str << [point.instance_variable_get(zm)].pack("E") end end else geometry.each do |poly| poly.each do |lr| lr.each do |point| str << [point.instance_variable_get(zm)].pack("E") end end end end str end
build_polyline(geometry,str)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 591 def build_polyline(geometry,str) if geometry.is_a? GeoRuby::SimpleFeatures::LineString str << [1,geometry.length,0].pack("V3") geometry.each do |point| str << [point.x,point.y].pack("E2") end else #multilinestring str << [geometry.length,geometry.inject(0) {|l, ls| l + ls.length}].pack("V2") str << geometry.inject([0]) {|a,ls| a << (a.last + ls.length)}.pack("V#{geometry.length}") #last element of the previous array is dropped geometry.each do |ls| ls.each do |point| str << [point.x,point.y].pack("E2") end end end str end
build_polyline_zm(geometry,zm,range,str)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 610 def build_polyline_zm(geometry,zm,range,str) str << range.pack("E2") if geometry.is_a? GeoRuby::SimpleFeatures::LineString geometry.each do |point| str << [point.instance_variable_get(zm)].pack("E") end else #multilinestring geometry.each do |ls| ls.each do |point| str << [point.instance_variable_get(zm)].pack("E") end end end str end
build_shp_geometry(geometry)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 526 def build_shp_geometry(geometry) m_range = nil answer = case @shp.shp_type when ShpType::POINT bbox = geometry.bounding_box [geometry.x,geometry.y].pack("E2") when ShpType::POLYLINE str,bbox = create_bbox(geometry) build_polyline(geometry,str) when ShpType::POLYGON str,bbox = create_bbox(geometry) build_polygon(geometry,str) when ShpType::MULTIPOINT str,bbox = create_bbox(geometry) build_multi_point(geometry,str) when ShpType::POINTZ bbox = geometry.bounding_box [geometry.x,geometry.y,geometry.z,geometry.m].pack("E4") when ShpType::POLYLINEZ str,bbox = create_bbox(geometry) m_range = geometry.m_range build_polyline(geometry,str) build_polyline_zm(geometry,:@z,[bbox[0].z,bbox[1].z],str) build_polyline_zm(geometry,:@m,m_range,str) when ShpType::POLYGONZ str,bbox = create_bbox(geometry) m_range = geometry.m_range build_polygon(geometry,str) build_polygon_zm(geometry,:@z,[bbox[0].z,bbox[1].z],str) build_polygon_zm(geometry,:@m,m_range,str) when ShpType::MULTIPOINTZ str,bbox = create_bbox(geometry) m_range = geometry.m_range build_multi_point(geometry,str) build_multi_point_zm(geometry,:@z,[bbox[0].z,bbox[1].z],str) build_multi_point_zm(geometry,:@m,m_range,str) when ShpType::POINTM bbox = geometry.bounding_box [geometry.x,geometry.y,geometry.m].pack("E3") when ShpType::POLYLINEM str,bbox = create_bbox(geometry) m_range = geometry.m_range build_polyline(geometry,str) build_polyline_zm(geometry,:@m,m_range,str) when ShpType::POLYGONM str,bbox = create_bbox(geometry) m_range = geometry.m_range build_polygon(geometry,str) build_polygon_zm(geometry,:@m,m_range,str) when ShpType::MULTIPOINTM str,bbox = create_bbox(geometry) m_range = geometry.m_range build_multi_point(geometry,str) build_multi_point_zm(geometry,:@m,m_range,str) end m_range ||= [0,0] [answer,bbox[0].x,bbox[1].x,bbox[0].y,bbox[1].y,bbox[0].z || 0, bbox[1].z || 0, m_range[0], m_range[1]] end
commit_add(index)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 430 def commit_add(index) max_x, min_x, max_y, min_y,max_z,min_z,max_m,min_m = @shp.xmax,@shp.xmin,@shp.ymax,@shp.ymin,@shp.zmax,@shp.zmin,@shp.mmax,@shp.mmin @added.each do |record| @dbf_io << ['20'].pack('H2') @dbf.fields.each do |field| data = record.data[field.name] str = if field.type == 'D' sprintf("%04i%02i%02i",data.year,data.month,data.mday) elsif field.type == 'L' if data "T" else "F" end else data.to_s end @dbf_io << [str].pack("A#{field.length}") end shp_str,min_xp,max_xp,min_yp,max_yp,min_zp,max_zp,min_mp,max_mp = build_shp_geometry(record.geometry) max_x = max_xp if max_xp > max_x min_x = min_xp if min_xp < min_x max_y = max_yp if max_yp > max_y min_y = min_yp if min_yp < min_y max_z = max_zp if max_zp > max_z min_z = min_zp if min_zp < min_z max_m = max_mp if max_mp > max_m min_m = min_mp if min_mp < min_m length = (shp_str.length/2 + 2).to_i #num of 16-bit words; geom type is included (+2) @shx_io << [(@shp_io.pos/2).to_i,length].pack("N2") @shp_io << [index,length,@shp.shp_type].pack("N2V") @shp_io << shp_str index += 1 end @shp_io.flush @shx_io.flush @dbf_io.flush [min_x,max_x,min_y,max_y,min_z,max_z,min_m,max_m] end
commit_delete()
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 471 def commit_delete @shp_r.rewind header = @shp_r.read(100) @shp_io << header @shx_io << header index = 1 while(!@shp_r.eof?) icur,length = @shp_r.read(8).unpack("N2") unless(@deleted[icur-1]) @shx_io << [(@shp_io.pos/2).to_i,length].pack("N2") @shp_io << [index,length].pack("N2") @shp_io << @shp_r.read(length * 2) index += 1 else @shp_r.seek(length * 2,IO::SEEK_CUR) end end @shp_io.flush @shx_io.flush @dbf_r.rewind @dbf_io << @dbf_r.read(@dbf.header_length) icur = 0 while(!@dbf_r.eof?) unless(@deleted[icur]) @dbf_io << @dbf_r.read(@dbf.record_length) else @dbf_r.seek(@dbf.record_length,IO::SEEK_CUR) end icur += 1 end @dbf_io.flush index end
commit_finalize(min_x,max_x,min_y,max_y,min_z,max_z,min_m,max_m)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 506 def commit_finalize(min_x,max_x,min_y,max_y,min_z,max_z,min_m,max_m) #update size in shp and dbf + extent and num records in dbf @shp_io.seek(0,IO::SEEK_END) shp_size = @shp_io.pos / 2 @shx_io.seek(0,IO::SEEK_END) shx_size= @shx_io.pos / 2 @shp_io.seek(24) @shp_io.write([shp_size].pack("N")) @shx_io.seek(24) @shx_io.write([shx_size].pack("N")) @shp_io.seek(36) @shx_io.seek(36) str = [min_x,min_y,max_x,max_y,min_z,max_z,min_m,max_m].pack("E8") @shp_io.write(str) @shx_io.write(str) @dbf_io.seek(4) @dbf_io.write([@dbf.record_count + @added.length - @deleted.length].pack("V")) end
create_bbox(geometry)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 586 def create_bbox(geometry) bbox = geometry.bounding_box [[bbox[0].x,bbox[0].y,bbox[1].x,bbox[1].y].pack("E4"),bbox] end
to_shp_type(geom)
click to toggle source
# File lib/geo_ruby/shp4r/shp.rb, line 404 def to_shp_type(geom) root = if geom.is_a? GeoRuby::SimpleFeatures::Point "POINT" elsif geom.is_a? GeoRuby::SimpleFeatures::LineString "POLYLINE" elsif geom.is_a? GeoRuby::SimpleFeatures::Polygon "POLYGON" elsif geom.is_a? GeoRuby::SimpleFeatures::MultiPoint "MULTIPOINT" elsif geom.is_a? GeoRuby::SimpleFeatures::MultiLineString "POLYLINE" elsif geom.is_a? GeoRuby::SimpleFeatures::MultiPolygon "POLYGON" else false end return false if !root if geom.with_z root = root + "Z" elsif geom.with_m root = root + "M" end eval "ShpType::" + root end