Skip to content

Commit

Permalink
build processors for reprojection of shapefiles
Browse files Browse the repository at this point in the history
  • Loading branch information
Darren Hardy committed Mar 26, 2016
1 parent 88f0b22 commit cb8bb04
Show file tree
Hide file tree
Showing 13 changed files with 158 additions and 1 deletion.
7 changes: 6 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ env:
global:
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
before_script:
- jdk_switcher use oraclejdk8
- jdk_switcher use oraclejdk8
- gdalinfo --version
addons:
apt:
packages:
- gdal-bin
44 changes: 44 additions & 0 deletions lib/geo_concerns/processors/gdal_projection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'open-uri'

module GeoConcerns::Processors
class GdalProjection < Hydra::Derivatives::Processors::Processor
include Hydra::Derivatives::Processors::ShellBasedProcessor
attr_reader :source_path, :directives

def self.process(source_path, directives)
new(source_path, directives).reproject # XXX: clean up after ourselves
end

def initialize(source_path, directives)
fail ArgumentError unless source_path.ends_with?('.tif')

@source_path = source_path
@directives = directives

@output_filename = output_file(File.extname(source_path).gsub(/^\./, ''))
@output_directory = File.dirname(@output_filename)

@srid ||= directives.fetch(:srid, 4326)

FileUtils.mkdir_p(@output_directory) unless File.directory?(@output_directory)
end

def reproject
gdalwarp
end

# reproject via GDAL, @see http://www.gdal.org/gdalwarp.html
def gdalwarp(resample = 'bilinear')
tempfn = File.join(@output_directory, File.basename(source_path))
# reproject with gdalwarp (must uncompress here to prevent bloat)
self.class.execute "gdalwarp -q -r #{resample} -t_srs EPSG:#{@srid} #{source_path} #{tempfn} -co 'COMPRESS=NONE'"
fail "gdalwarp failed to create #{tempfn}" unless File.size?(tempfn)

# compress tempfn with gdal_translate
self.class.execute "gdal_translate -q -a_srs EPSG:#{@srid} #{tempfn} #{@output_filename} -co 'COMPRESS=LZW'"
fail "gdal_translate failed to create #{@output_filename}" unless File.size?(@output_filename)
ensure
FileUtils.rm_f(tempfn)
end
end
end
46 changes: 46 additions & 0 deletions lib/geo_concerns/processors/ogr_projection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
require 'open-uri'

module GeoConcerns::Processors
class OgrProjection < Hydra::Derivatives::Processors::Processor
include Hydra::Derivatives::Processors::ShellBasedProcessor
attr_reader :source_path, :directives

def self.process(source_path, directives)
new(source_path, directives).reproject # XXX: clean up after ourselves
end

def initialize(source_path, directives)
fail ArgumentError unless source_path.ends_with?('.shp')

@source_path = source_path
@directives = directives

@output_filename = output_file(File.extname(source_path).gsub(/^\./, ''))
@output_directory = File.dirname(@output_filename)

FileUtils.mkdir_p(@output_directory) unless File.directory?(@output_directory)
end

def reproject
ogr2ogr
normalize_prj_file
end

def prettywkt
@srid ||= directives.fetch(:srid, 4326)
@prettywkt ||= open("http://spatialreference.org/ref/epsg/#{@srid}/prettywkt/").read
end

# reproject via OGR, @see http://www.gdal.org/ogr2ogr.html
# prevent recoding using SHAPE_ENCODING environment variable
def ogr2ogr
cmd = "env SHAPE_ENCODING= ogr2ogr -q -t_srs '#{prettywkt}' '#{@output_filename}' '#{source_path}'"
self.class.execute(cmd)
end

# normalize prj file with the prettywkt
def normalize_prj_file
File.open(@output_filename.gsub(/\.shp$/, '.prj'), 'w') { |f| f.write(prettywkt) }
end
end
end
15 changes: 15 additions & 0 deletions lib/geo_concerns/processors/project_data.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module GeoConcerns::Processors
class ProjectData < Hydra::Derivatives::Processors::Processor
def process
code = directives.fetch(:format)
case code
when 'ESRI Shapefile'
OgrProjection
when 'GTiff'
GdalProjection
else
fail NotImplementedError, "Unknown driver code: #{code}"
end.process(source_path, directives)
end
end
end
7 changes: 7 additions & 0 deletions lib/geo_concerns/runners/normalize_data_derivatives.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module GeoConcerns::Runners
class NormalizeDataDerivatives < Hydra::Derivatives::Runner
def self.processor_class
GeoConcerns::Processors::NormalizeData
end
end
end
Binary file not shown.
Binary file added spec/fixtures/McKay/S_566_1914_lines.dbf
Binary file not shown.
1 change: 1 addition & 0 deletions spec/fixtures/McKay/S_566_1914_lines.prj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PROJCS["NAD_1983_10TM_AEP_Forest",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-115.0],PARAMETER["Scale_Factor",0.9992],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]
Binary file added spec/fixtures/McKay/S_566_1914_lines.sbn
Binary file not shown.
Binary file added spec/fixtures/McKay/S_566_1914_lines.sbx
Binary file not shown.
Binary file added spec/fixtures/McKay/S_566_1914_lines.shp
Binary file not shown.
Binary file added spec/fixtures/McKay/S_566_1914_lines.shx
Binary file not shown.
39 changes: 39 additions & 0 deletions spec/processors/project_data_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'spec_helper'

describe GeoConcerns::Processors::ProjectData do
let(:output_file) { double }
let(:file_name) { double }

subject { described_class.new(file_name, directives) }

before do
allow(subject).to receive(:output_file).with(file_name).and_return(output_file)
end

describe "for Shapefiles" do
let(:directives) { { format: 'ESRI Shapefile' } }
let(:file_name) { 'spec/fixtures/McKay/S_566_1914_lines.shp' }

it "will fire a Shapefile reprojection" do
expect { subject.process }.not_to raise_error
end
end

describe "for GeoTIFF" do
let(:directives) { { format: 'GTiff' } }
let(:file_name) { 'spec/fixtures/BackscatterA_8101_OffshoreBodegaHead.tif' }

it "will fire a GeoTIFF reprojection" do
expect { subject.process }.not_to raise_error
end
end

describe "for unknown formats" do
let(:directives) { { format: 'UNKNOWN' } }
let(:file_name) { 'noname' }

it "will throw an error for unknown formats" do
expect { subject.process }.to raise_error(NotImplementedError)
end
end
end

0 comments on commit cb8bb04

Please sign in to comment.