geo_works-derivatives 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +22 -0
  5. data/.travis.yml +21 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE.txt +15 -0
  8. data/README.md +63 -0
  9. data/Rakefile +7 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/config/simpler_tiles.yml +24 -0
  13. data/geo_works-derivatives.gemspec +42 -0
  14. data/lib/geo_works/derivatives/config.rb +78 -0
  15. data/lib/geo_works/derivatives/processors/base_geo_processor.rb +92 -0
  16. data/lib/geo_works/derivatives/processors/gdal.rb +72 -0
  17. data/lib/geo_works/derivatives/processors/image.rb +67 -0
  18. data/lib/geo_works/derivatives/processors/ogr.rb +22 -0
  19. data/lib/geo_works/derivatives/processors/raster/aig.rb +43 -0
  20. data/lib/geo_works/derivatives/processors/raster/base.rb +44 -0
  21. data/lib/geo_works/derivatives/processors/raster/dem.rb +32 -0
  22. data/lib/geo_works/derivatives/processors/raster/info.rb +69 -0
  23. data/lib/geo_works/derivatives/processors/raster.rb +34 -0
  24. data/lib/geo_works/derivatives/processors/rendering.rb +82 -0
  25. data/lib/geo_works/derivatives/processors/vector/base.rb +47 -0
  26. data/lib/geo_works/derivatives/processors/vector/info.rb +89 -0
  27. data/lib/geo_works/derivatives/processors/vector/shapefile.rb +23 -0
  28. data/lib/geo_works/derivatives/processors/vector.rb +31 -0
  29. data/lib/geo_works/derivatives/processors/zip.rb +32 -0
  30. data/lib/geo_works/derivatives/processors.rb +15 -0
  31. data/lib/geo_works/derivatives/runners/raster_derivatives.rb +12 -0
  32. data/lib/geo_works/derivatives/runners/vector_derivatives.rb +12 -0
  33. data/lib/geo_works/derivatives/runners.rb +9 -0
  34. data/lib/geo_works/derivatives/version.rb +6 -0
  35. data/lib/geo_works/derivatives.rb +12 -0
  36. metadata +188 -0
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Processors
5
+ module Raster
6
+ class Base < Hydra::Derivatives::Processors::Processor
7
+ include Hydra::Derivatives::Processors::ShellBasedProcessor
8
+ include GeoWorks::Derivatives::Processors::BaseGeoProcessor
9
+ include GeoWorks::Derivatives::Processors::Image
10
+ include GeoWorks::Derivatives::Processors::Gdal
11
+
12
+ def self.encode(path, options, output_file)
13
+ case options[:label]
14
+ when :thumbnail
15
+ encode_raster(path, output_file, options)
16
+ when :display_raster
17
+ reproject_raster(path, output_file, options)
18
+ end
19
+ end
20
+
21
+ # Set of commands to run to encode the raster thumbnail.
22
+ # @return [Array] set of command name symbols
23
+ def self.encode_queue
24
+ [:translate, :convert, :trim, :center]
25
+ end
26
+
27
+ # Set of commands to run to reproject the raster.
28
+ # @return [Array] set of command name symbols
29
+ def self.reproject_queue
30
+ [:warp, :cloud_optimized_geotiff]
31
+ end
32
+
33
+ def self.encode_raster(in_path, out_path, options)
34
+ run_commands(in_path, out_path, encode_queue, options)
35
+ end
36
+
37
+ def self.reproject_raster(in_path, out_path, options)
38
+ run_commands(in_path, out_path, reproject_queue, options)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Processors
5
+ module Raster
6
+ class Dem < GeoWorks::Derivatives::Processors::Raster::Base
7
+ # Set of commands to run to encode the DEM thumbnail.
8
+ # @return [Array] set of command name symbols
9
+ def self.encode_queue
10
+ [:hillshade, :convert, :trim, :center]
11
+ end
12
+
13
+ # Set of commands to run to reproject the DEM.
14
+ # @return [Array] set of command name symbols
15
+ def self.reproject_queue
16
+ [:hillshade, :warp, :compress]
17
+ end
18
+
19
+ # Executes a gdal hillshade command. Calculates hillshade
20
+ # on a raster that contains elevation data.
21
+ # @param in_path [String] file input path
22
+ # @param out_path [String] processor output file path
23
+ # @param options [Hash] creation options
24
+ def self.hillshade(in_path, out_path, _options)
25
+ execute "gdaldem hillshade -q "\
26
+ "-of GTiff \"#{in_path}\" #{out_path}"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Processors
5
+ module Raster
6
+ class Info
7
+ attr_accessor :doc
8
+ attr_writer :min_max, :size
9
+
10
+ def initialize(path)
11
+ @doc = gdalinfo(path)
12
+ end
13
+
14
+ # Returns the gdal driver name
15
+ # @return [String] driver name
16
+ def driver
17
+ @driver = driver_name
18
+ end
19
+
20
+ # Returns the min and max values for a raster.
21
+ # @return [String] computed min and max values
22
+ def min_max
23
+ @min_max ||= raster_min_max
24
+ end
25
+
26
+ # Returns the raster size.
27
+ # @return [Array] raster size
28
+ def size
29
+ @size ||= raster_size
30
+ end
31
+
32
+ private
33
+
34
+ # Given an output string from the gdalinfo command, returns
35
+ # the gdal driver used to read dataset.
36
+ # @return [String] gdal driver name
37
+ def driver_name
38
+ match = /(?<=Driver:\s).*?(?=\s)/.match(doc)
39
+ match ? match[0] : ''
40
+ end
41
+
42
+ # Runs the gdalinfo command and returns the result as a string.
43
+ # @param path [String] path to raster file
44
+ # @return [String] output of gdalinfo
45
+ def gdalinfo(path)
46
+ stdout, _stderr, _status = Open3.capture3("gdalinfo -mm #{path}")
47
+ stdout
48
+ end
49
+
50
+ # Given an output string from the gdalinfo command, returns
51
+ # a formatted string for the computed min and max values.
52
+ # @return [String] computed min and max values
53
+ def raster_min_max
54
+ match = %r{(?<=Computed Min/Max=).*?(?=\s)}.match(doc)
55
+ match ? match[0].tr(',', ' ') : ''
56
+ end
57
+
58
+ # Given an output string from the gdalinfo command, returns
59
+ # an array containing the raster width and height as strings.
60
+ # @return [String] raster size
61
+ def raster_size
62
+ match = /(?<=Size is ).*/.match(doc)
63
+ match ? match[0].tr(',', '') : ''
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Processors
5
+ module Raster
6
+ require 'geo_works/derivatives/processors/raster/base'
7
+ require 'geo_works/derivatives/processors/raster/aig'
8
+ require 'geo_works/derivatives/processors/raster/dem'
9
+ require 'geo_works/derivatives/processors/raster/info'
10
+
11
+ class Processor < Hydra::Derivatives::Processors::Processor
12
+ def process
13
+ raster_processor_class.new(source_path,
14
+ directives,
15
+ output_file_service: output_file_service).process
16
+ end
17
+
18
+ # Returns a raster processor class based on mime type passed in the directives object.
19
+ # @return raster processing class
20
+ def raster_processor_class
21
+ case directives.fetch(:input_format)
22
+ when 'text/plain; gdal-format=USGSDEM'
23
+ GeoWorks::Derivatives::Processors::Raster::Dem
24
+ when 'application/octet-stream; gdal-format=AIG'
25
+ GeoWorks::Derivatives::Processors::Raster::Aig
26
+ else
27
+ GeoWorks::Derivatives::Processors::Raster::Base
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+ require 'simpler_tiles'
3
+
4
+ module GeoWorks
5
+ module Derivatives
6
+ module Processors
7
+ module Rendering
8
+ extend ActiveSupport::Concern
9
+ included do
10
+ # Renders a thumbnail from a vector dataset.
11
+ # @param in_path [String] file input path
12
+ # @param out_path [String] processor output file path
13
+ # @param options [Hash] creation options
14
+ def self.vector_thumbnail(in_path, out_path, options)
15
+ map = GeoWorks::Derivatives::Processors::Rendering.simple_tiles_map(in_path, options)
16
+ File.open(out_path, 'wb') { |f| f.write map.to_png }
17
+ end
18
+ end
19
+
20
+ class << self
21
+ # Builds a simple tiles map from a shapefile.
22
+ # @param in_path [String] file input path
23
+ # @param options [Hash] creation
24
+ # @return [SimplerTiles::Map] simple tiles map
25
+ def simple_tiles_map(in_path, options)
26
+ assign_rendering_options(in_path, options)
27
+ size = rendering_size(options)
28
+ SimplerTiles::Map.new do |m|
29
+ m.srs = 'EPSG:4326'
30
+ m.bgcolor = GeoWorks::Derivatives::Config.rendering_config.bg_color
31
+ m.width = size[0]
32
+ m.height = size[1]
33
+ m.set_bounds(*simple_tiles_bounds(options))
34
+ add_shapefile_layer(in_path, m)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # Adds a shapefile layer to a simple tiles map.
41
+ # @param in_path [String] file input path
42
+ # @param options [Hash] creation options
43
+ def add_shapefile_layer(in_path, map)
44
+ Dir.glob("#{in_path}/*.shp").each do |shp|
45
+ map.layer shp do |l|
46
+ l.query %(select * from "#{File.basename shp, '.shp'}") do |q|
47
+ q.styles GeoWorks::Derivatives::Config.rendering_config.to_h
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ # Re-orders options bounds for use with a simple tiles map.
54
+ # @param options [Hash] creation options
55
+ # @return [Array] simple tiles map bounds
56
+ def simple_tiles_bounds(options)
57
+ [options[:bounds][:east],
58
+ options[:bounds][:north],
59
+ options[:bounds][:west],
60
+ options[:bounds][:south]]
61
+ end
62
+
63
+ # Transforms the size directive into an array.
64
+ # @param options [Hash] creation options
65
+ # @return [Array] derivative size
66
+ def rendering_size(options)
67
+ options[:output_size].split(' ').map(&:to_i)
68
+ end
69
+
70
+ # Assigns new values from the vector info command to the creation options hash.
71
+ # @param in_path [String] file input path
72
+ # @param options [Hash] creation options
73
+ def assign_rendering_options(in_path, options)
74
+ vector_info = GeoWorks::Derivatives::Processors::Vector::Info.new(in_path)
75
+ options[:name] = vector_info.name
76
+ options[:bounds] = vector_info.bounds
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Processors
5
+ module Vector
6
+ class Base < Hydra::Derivatives::Processors::Processor
7
+ include Hydra::Derivatives::Processors::ShellBasedProcessor
8
+ include GeoWorks::Derivatives::Processors::BaseGeoProcessor
9
+ include GeoWorks::Derivatives::Processors::Image
10
+ include GeoWorks::Derivatives::Processors::Ogr
11
+ include GeoWorks::Derivatives::Processors::Gdal
12
+ include GeoWorks::Derivatives::Processors::Rendering
13
+ include GeoWorks::Derivatives::Processors::Zip
14
+
15
+ def self.encode(path, options, output_file)
16
+ case options[:label]
17
+ when :thumbnail
18
+ encode_vector(path, output_file, options)
19
+ when :display_vector
20
+ reproject_vector(path, output_file, options)
21
+ end
22
+ end
23
+
24
+ # Set of commands to run to encode the vector thumbnail.
25
+ # @return [Array] set of command name symbols
26
+ def self.encode_queue
27
+ [:reproject, :vector_thumbnail, :trim, :center]
28
+ end
29
+
30
+ # Set of commands to run to reproject the vector.
31
+ # @return [Array] set of command name symbols
32
+ def self.reproject_queue
33
+ [:reproject, :zip]
34
+ end
35
+
36
+ def self.encode_vector(in_path, out_path, options)
37
+ run_commands(in_path, out_path, encode_queue, options)
38
+ end
39
+
40
+ def self.reproject_vector(in_path, out_path, options)
41
+ run_commands(in_path, out_path, reproject_queue, options)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Processors
5
+ module Vector
6
+ class Info
7
+ attr_accessor :doc
8
+ attr_writer :name, :driver
9
+
10
+ def initialize(path)
11
+ @doc = ogrinfo(path)
12
+ end
13
+
14
+ # Returns the vector dataset name
15
+ # @return [String] dataset name
16
+ def name
17
+ @name = vector_name
18
+ end
19
+
20
+ # Returns the ogr driver name
21
+ # @return [String] driver name
22
+ def driver
23
+ @driver = driver_name
24
+ end
25
+
26
+ # Returns vector geometry type
27
+ # @return [String] geom
28
+ def geom
29
+ @geom = vector_geom
30
+ end
31
+
32
+ # Returns vector bounds
33
+ # @return [String] bounds
34
+ def bounds
35
+ @bounds = vector_bounds
36
+ end
37
+
38
+ private
39
+
40
+ # Runs the ogrinfo command and returns the result as a string.
41
+ # @param path [String] path to vector file or shapefile directory
42
+ # @return [String] output of ogrinfo
43
+ def ogrinfo(path)
44
+ stdout, _stderr, _status = Open3.capture3("ogrinfo -ro -so -al #{path}")
45
+ stdout
46
+ end
47
+
48
+ # Given an output string from the ogrinfo command, returns
49
+ # the vector dataset name.
50
+ # @return [String] vector dataset name
51
+ def vector_name
52
+ match = /(?<=Layer name:\s).*?(?=\n)/.match(doc)
53
+ match ? match[0] : ''
54
+ end
55
+
56
+ # Given an output string from the ogrinfo command, returns
57
+ # the ogr driver used to read dataset.
58
+ # @return [String] ogr driver name
59
+ def driver_name
60
+ match = /(?<=driver\s`).*?(?=')/.match(doc)
61
+ match ? match[0] : ''
62
+ end
63
+
64
+ # Given an output string from the ogrinfo command, returns
65
+ # the vector geometry type.
66
+ # @return [String] vector geom
67
+ def vector_geom
68
+ match = /(?<=Geometry:\s).*?(?=\n)/.match(doc)
69
+ geom = match ? match[0] : ''
70
+ # Transform OGR-style 'Line String' into GeoJSON 'Line'
71
+ geom == 'Line String' ? 'Line' : geom
72
+ end
73
+
74
+ # Given an output string from the ogrinfo command, returns
75
+ # the vector bounding box.
76
+ # @return [Hash] vector bounds
77
+ def vector_bounds
78
+ match = /(?<=Extent:\s).*?(?=\n)/.match(doc)
79
+ extent = match ? match[0] : ''
80
+
81
+ # remove parens and spaces, split into array, and assign elements to variables
82
+ w, s, e, n = extent.delete(' ').gsub(')-(', ',').delete('(').delete(')').split(',')
83
+ { north: n.to_f, east: e.to_f, south: s.to_f, west: w.to_f }
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Processors
5
+ module Vector
6
+ class Shapefile < GeoWorks::Derivatives::Processors::Vector::Base
7
+ include GeoWorks::Derivatives::Processors::Zip
8
+
9
+ def self.encode(path, options, output_file)
10
+ unzip(path, output_file) do |zip_path|
11
+ case options[:label]
12
+ when :thumbnail
13
+ encode_vector(zip_path, output_file, options)
14
+ when :display_vector
15
+ reproject_vector(zip_path, output_file, options)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Processors
5
+ module Vector
6
+ require 'geo_works/derivatives/processors/vector/base'
7
+ require 'geo_works/derivatives/processors/vector/info'
8
+ require 'geo_works/derivatives/processors/vector/shapefile'
9
+
10
+ class Processor < Hydra::Derivatives::Processors::Processor
11
+ def process
12
+ vector_processor_class.new(source_path,
13
+ directives,
14
+ output_file_service: output_file_service).process
15
+ end
16
+
17
+ # Returns a vector processor class based on mime type passed in the directives object.
18
+ # @return vector processing class
19
+ def vector_processor_class
20
+ case directives.fetch(:input_format)
21
+ when 'application/zip; ogr-format="ESRI Shapefile"'
22
+ GeoWorks::Derivatives::Processors::Vector::Shapefile
23
+ else
24
+ GeoWorks::Derivatives::Processors::Vector::Base
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Processors
5
+ module Zip
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ # Unzips a file, invokes a block, and then deletes the unzipped file(s).
10
+ # Use to wrap processor methods for geo file formats that
11
+ # are zipped before uploading.
12
+ # @param in_path [String] file input path
13
+ # @param output_file [String] processor output file path
14
+ def self.unzip(in_path, output_file, _options = {})
15
+ basename = File.basename(output_file, File.extname(output_file))
16
+ zip_out_path = "#{File.dirname(output_file)}/#{basename}_out"
17
+ execute "unzip -qq -j -d \"#{zip_out_path}\" \"#{in_path}\""
18
+ yield zip_out_path
19
+ FileUtils.rm_rf(zip_out_path)
20
+ end
21
+
22
+ # Zips a file or directory.
23
+ # @param in_path [String] file input path
24
+ # @param output_file [String] output zip file
25
+ def self.zip(in_path, output_file, _options = {})
26
+ execute "zip -j -qq -r \"#{output_file}\" \"#{in_path}\""
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Processors
5
+ require 'geo_works/derivatives/processors/base_geo_processor'
6
+ require 'geo_works/derivatives/processors/gdal'
7
+ require 'geo_works/derivatives/processors/image'
8
+ require 'geo_works/derivatives/processors/ogr'
9
+ require 'geo_works/derivatives/processors/rendering'
10
+ require 'geo_works/derivatives/processors/zip'
11
+ require 'geo_works/derivatives/processors/raster'
12
+ require 'geo_works/derivatives/processors/vector'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Runners
5
+ class RasterDerivatives < Hydra::Derivatives::Runner
6
+ def self.processor_class
7
+ GeoWorks::Derivatives::Processors::Raster::Processor
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Runners
5
+ class VectorDerivatives < Hydra::Derivatives::Runner
6
+ def self.processor_class
7
+ GeoWorks::Derivatives::Processors::Vector::Processor
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ module Runners
5
+ require 'geo_works/derivatives/runners/raster_derivatives'
6
+ require 'geo_works/derivatives/runners/vector_derivatives'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ module GeoWorks
3
+ module Derivatives
4
+ VERSION = "0.4.0"
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ require 'geo_works/derivatives/version'
3
+ require 'hydra/derivatives'
4
+ require 'mime/types'
5
+
6
+ module GeoWorks
7
+ module Derivatives
8
+ require 'geo_works/derivatives/config'
9
+ require 'geo_works/derivatives/processors'
10
+ require 'geo_works/derivatives/runners'
11
+ end
12
+ end