Class: NSWTopo::Shapefile::Layer
- Inherits:
-
Object
- Object
- NSWTopo::Shapefile::Layer
- Defined in:
- lib/nswtopo/gis/shapefile.rb
Constant Summary collapse
- NoLayerError =
Class.new RuntimeError
Instance Method Summary collapse
- #counts ⇒ Object
- #features ⇒ Object
- #info ⇒ Object
-
#initialize(source, layer: nil, where: nil, fields: nil, sql: nil, geometry: nil, projection: nil) ⇒ Layer
constructor
A new instance of Layer.
Constructor Details
#initialize(source, layer: nil, where: nil, fields: nil, sql: nil, geometry: nil, projection: nil) ⇒ Layer
Returns a new instance of Layer.
40 41 42 |
# File 'lib/nswtopo/gis/shapefile.rb', line 40 def initialize(source, layer: nil, where: nil, fields: nil, sql: nil, geometry: nil, projection: nil) @source, @layer, @where, @fields, @sql, @geometry, @projection = source, layer, where, fields, sql, geometry, projection end |
Instance Method Details
#counts ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/nswtopo/gis/shapefile.rb', line 60 def counts raise NoLayerError, "no layer name provided" unless @layer count = ?_ * @fields.map(&:size).max + "count" where = %Q[WHERE (%s)] % [*@where].join(") AND (") if @where field_list = %Q["%s"] % @fields.join('", "') sql = <<~SQL % [field_list, count, @layer, where, field_list] SELECT %s, count(*) AS "%s" FROM "%s" %s GROUP BY %s SQL json = OS.ogr2ogr *%w[-f GeoJSON -lco RFC7946=NO -dialect sqlite -sql], sql, "/vsistdout/", @source.path JSON.parse(json)["features"].map do |feature| feature["properties"] end.map do |properties| [properties.slice(*@fields), properties[count]] end rescue OS::Error => error raise unless /no such column: (.*)$/ === error. raise "invalid field: #{$1}" end |
#features ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/nswtopo/gis/shapefile.rb', line 44 def features raise "can't specify both SQL and where clause" if @sql && @where raise "can't specify both SQL and layer name" if @sql && @layer raise "no layer name or SQL specified" unless @layer || @sql sql = ["-sql", sql] if @sql where = ["-where", "(" << Array(@where).join(") AND (") << ")"] if @where srs = ["-t_srs", @projection] if @projection spat = ["-spat", *@geometry.bounds.transpose.flatten, "-spat_srs", @geometry.projection] if @geometry misc = %w[-mapFieldType Date=Integer,DateTime=Integer -dim XY] json = OS.ogr2ogr *(sql || where), *srs, *spat, *misc, *%w[-f GeoJSON -lco RFC7946=NO /vsistdout/], @source.path, *@layer GeoJSON::Collection.load json, **{projection: @projection}.compact rescue OS::Error => error raise unless /Couldn't fetch requested layer (.*)!/ === error. raise "no such layer: #{$1}" end |
#info ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/nswtopo/gis/shapefile.rb', line 82 def info raise NoLayerError, "no layer name provided" unless @layer info = OS.ogrinfo *%w[-ro -so -noextent], @source.path, @layer geom_type = info.match(/^Geometry: (.*)$/)&.[](1)&.delete(?\s) count = info.match(/^Feature Count: (\d+)$/)&.[](1) fields = info.scan(/^(.*): (.*?) \(\d+\.\d+\)$/).to_h wkt = info.each_line.slice_after(/^Layer SRS WKT:/).drop(1).first&.slice_before(/^\S/)&.first&.join epsg = OS.gdalsrsinfo("-o", "epsg", wkt)[/\d+/] if wkt and !wkt["unknown"] { name: @layer, geometry: geom_type, EPSG: epsg, features: count, fields: (fields unless fields.empty?) }.compact rescue OS::Error => error raise unless /Couldn't fetch requested layer (.*)!/ === error. raise "no such layer: #{$1}" end |