ffi-gdal 1.0.0.beta5 → 1.0.0.beta6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +7 -3
- data/.rubocop.yml +7 -0
- data/.ruby-version +1 -0
- data/Gemfile +1 -1
- data/History.md +143 -1
- data/README.md +5 -11
- data/Rakefile +2 -60
- data/TODO.md +10 -0
- data/examples/geometries.rb +4 -6
- data/examples/gridding.rb +99 -98
- data/examples/ogr_layer_to_layer.rb +0 -2
- data/examples/raster_erasing.rb +47 -0
- data/examples/remove_small_polygons.rb +62 -0
- data/examples/testing_gdal.rb +0 -3
- data/examples/warping.rb +140 -0
- data/ffi-gdal.gemspec +5 -2
- data/lib/ext/error_symbols.rb +1 -1
- data/lib/ext/ffi_library_function_checks.rb +3 -2
- data/lib/ext/float_ext.rb +2 -2
- data/lib/ext/narray_ext.rb +1 -1
- data/lib/ext/numeric_as_data_type.rb +1 -1
- data/lib/ext/to_bool.rb +2 -2
- data/lib/ffi/cpl/conv.rb +1 -3
- data/lib/ffi/cpl/error.rb +0 -3
- data/lib/ffi/cpl/minixml.rb +17 -21
- data/lib/ffi/cpl/progress.rb +27 -0
- data/lib/ffi/cpl/string.rb +0 -8
- data/lib/ffi/cpl/vsi.rb +0 -1
- data/lib/ffi/cpl/xml_node.rb +0 -1
- data/lib/ffi/cpl.rb +15 -0
- data/lib/ffi/gdal/alg.rb +72 -54
- data/lib/ffi/gdal/gdal.rb +669 -672
- data/lib/ffi/gdal/grid.rb +141 -24
- data/lib/ffi/gdal/grid_data_metrics_options.rb +1 -1
- data/lib/ffi/gdal/grid_moving_average_options.rb +1 -1
- data/lib/ffi/gdal/matching.rb +0 -2
- data/lib/ffi/gdal/transformer_info.rb +1 -1
- data/lib/ffi/gdal/version.rb +1 -1
- data/lib/ffi/gdal/vrt.rb +0 -2
- data/lib/ffi/gdal/warp_options.rb +12 -14
- data/lib/ffi/gdal/warper.rb +61 -6
- data/lib/ffi/gdal.rb +18 -3
- data/lib/ffi/ogr/api.rb +10 -21
- data/lib/ffi/ogr/core.rb +9 -12
- data/lib/ffi/ogr/featurestyle.rb +0 -5
- data/lib/ffi/ogr/geocoding.rb +0 -1
- data/lib/ffi/ogr/srs_api.rb +0 -4
- data/lib/ffi/ogr/style_value.rb +1 -2
- data/lib/ffi/ogr.rb +15 -12
- data/lib/ffi-gdal.rb +5 -3
- data/lib/gdal/color_entry.rb +1 -0
- data/lib/gdal/color_interpretation.rb +2 -2
- data/lib/gdal/color_table.rb +14 -14
- data/lib/gdal/color_table_mixins/extensions.rb +4 -4
- data/lib/gdal/cpl_error_handler.rb +12 -14
- data/lib/gdal/data_type.rb +13 -12
- data/lib/gdal/dataset.rb +170 -94
- data/lib/gdal/dataset_mixins/algorithm_methods.rb +47 -21
- data/lib/gdal/dataset_mixins/extensions.rb +32 -61
- data/lib/gdal/dataset_mixins/matching.rb +0 -2
- data/lib/gdal/dataset_mixins/warp_methods.rb +42 -0
- data/lib/gdal/driver.rb +62 -47
- data/lib/gdal/driver_mixins/extensions.rb +2 -7
- data/lib/gdal/environment_methods.rb +13 -10
- data/lib/gdal/exceptions.rb +24 -2
- data/lib/gdal/geo_transform.rb +10 -16
- data/lib/gdal/geo_transform_mixins/extensions.rb +58 -3
- data/lib/gdal/grid.rb +62 -109
- data/lib/gdal/{grid_types → grid_algorithms}/data_metrics_base.rb +1 -3
- data/lib/gdal/{grid_types → grid_algorithms}/inverse_distance_to_a_power.rb +2 -4
- data/lib/gdal/{grid_types → grid_algorithms}/metric_average_distance.rb +2 -2
- data/lib/gdal/{grid_types → grid_algorithms}/metric_average_distance_pts.rb +2 -2
- data/lib/gdal/{grid_types → grid_algorithms}/metric_count.rb +2 -2
- data/lib/gdal/{grid_types → grid_algorithms}/metric_maximum.rb +2 -2
- data/lib/gdal/{grid_types → grid_algorithms}/metric_minimum.rb +2 -2
- data/lib/gdal/{grid_types → grid_algorithms}/metric_range.rb +2 -2
- data/lib/gdal/{grid_types → grid_algorithms}/moving_average.rb +2 -4
- data/lib/gdal/{grid_types → grid_algorithms}/nearest_neighbor.rb +2 -4
- data/lib/gdal/grid_algorithms.rb +22 -0
- data/lib/gdal/gridder/point_extracting.rb +89 -0
- data/lib/gdal/gridder.rb +294 -0
- data/lib/gdal/gridder_options.rb +273 -0
- data/lib/gdal/internal_helpers.rb +132 -23
- data/lib/gdal/major_object.rb +13 -10
- data/lib/gdal/merger.rb +130 -0
- data/lib/gdal/options.rb +3 -2
- data/lib/gdal/raster_attribute_table.rb +74 -51
- data/lib/gdal/raster_attribute_table_mixins/extensions.rb +21 -3
- data/lib/gdal/raster_band.rb +139 -167
- data/lib/gdal/raster_band_classifier.rb +19 -18
- data/lib/gdal/raster_band_mixins/algorithm_extensions.rb +107 -0
- data/lib/gdal/raster_band_mixins/algorithm_methods.rb +79 -40
- data/lib/gdal/raster_band_mixins/coloring_extensions.rb +84 -0
- data/lib/gdal/raster_band_mixins/extensions.rb +34 -169
- data/lib/gdal/raster_band_mixins/io_extensions.rb +180 -0
- data/lib/gdal/rpc_info.rb +1 -2
- data/lib/gdal/transformer.rb +1 -6
- data/lib/gdal/transformers/approximate_transformer.rb +0 -4
- data/lib/gdal/transformers/base_general_image_projection_transformer.rb +0 -6
- data/lib/gdal/transformers/gcp_transformer.rb +2 -6
- data/lib/gdal/transformers/general_image_projection_transformer.rb +8 -7
- data/lib/gdal/transformers/general_image_projection_transformer2.rb +1 -1
- data/lib/gdal/transformers/geolocation_transformer.rb +0 -4
- data/lib/gdal/transformers/reprojection_transformer.rb +0 -8
- data/lib/gdal/transformers/rpc_transformer.rb +0 -4
- data/lib/gdal/transformers/tps_transformer.rb +1 -3
- data/lib/gdal/version_info.rb +7 -8
- data/lib/gdal/virtual_dataset.rb +2 -4
- data/lib/gdal/warp_operation.rb +17 -14
- data/lib/gdal/warp_options.rb +132 -0
- data/lib/gdal.rb +41 -2
- data/lib/ogr/coordinate_transformation.rb +79 -32
- data/lib/ogr/data_source.rb +17 -14
- data/lib/ogr/data_source_extensions.rb +1 -5
- data/lib/ogr/driver.rb +11 -14
- data/lib/ogr/envelope.rb +1 -1
- data/lib/ogr/envelope_extensions.rb +23 -6
- data/lib/ogr/error_handling.rb +3 -3
- data/lib/ogr/exceptions.rb +6 -0
- data/lib/ogr/feature.rb +25 -38
- data/lib/ogr/feature_definition.rb +6 -8
- data/lib/ogr/feature_definition_extensions.rb +2 -6
- data/lib/ogr/feature_extensions.rb +71 -41
- data/lib/ogr/field.rb +16 -15
- data/lib/ogr/field_definition.rb +4 -4
- data/lib/ogr/geocoder.rb +5 -5
- data/lib/ogr/geometries/geometry_collection.rb +4 -1
- data/lib/ogr/geometries/geometry_collection_25d.rb +12 -0
- data/lib/ogr/geometries/line_string.rb +30 -8
- data/lib/ogr/geometries/line_string_25d.rb +21 -0
- data/lib/ogr/geometries/linear_ring.rb +10 -1
- data/lib/ogr/geometries/multi_line_string.rb +2 -1
- data/lib/ogr/geometries/multi_line_string_25d.rb +13 -0
- data/lib/ogr/geometries/multi_point.rb +2 -1
- data/lib/ogr/geometries/multi_point_25d.rb +14 -0
- data/lib/ogr/geometries/multi_polygon.rb +3 -2
- data/lib/ogr/geometries/multi_polygon_25d.rb +13 -0
- data/lib/ogr/geometries/point.rb +20 -23
- data/lib/ogr/geometries/point_25d.rb +48 -0
- data/lib/ogr/geometries/polygon.rb +4 -1
- data/lib/ogr/geometries/polygon_25d.rb +14 -0
- data/lib/ogr/geometry.rb +125 -93
- data/lib/ogr/geometry_field_definition.rb +7 -5
- data/lib/ogr/geometry_mixins/container_mixins.rb +23 -0
- data/lib/ogr/geometry_mixins/extensions.rb +111 -0
- data/lib/ogr/geometry_types/container.rb +10 -3
- data/lib/ogr/geometry_types/curve.rb +68 -23
- data/lib/ogr/geometry_types/surface.rb +0 -9
- data/lib/ogr/internal_helpers.rb +3 -3
- data/lib/ogr/layer.rb +4 -5
- data/lib/ogr/layer_mixins/extensions.rb +242 -17
- data/lib/ogr/layer_mixins/ogr_feature_methods.rb +11 -11
- data/lib/ogr/layer_mixins/ogr_field_methods.rb +6 -11
- data/lib/ogr/layer_mixins/ogr_layer_method_methods.rb +18 -18
- data/lib/ogr/layer_mixins/ogr_query_filter_methods.rb +0 -2
- data/lib/ogr/layer_mixins/ogr_sql_methods.rb +1 -1
- data/lib/ogr/spatial_reference.rb +12 -37
- data/lib/ogr/spatial_reference_mixins/coordinate_system_getter_setters.rb +53 -55
- data/lib/ogr/spatial_reference_mixins/exporters.rb +18 -49
- data/lib/ogr/spatial_reference_mixins/parameter_getter_setters.rb +10 -29
- data/lib/ogr/style_table.rb +2 -2
- data/lib/ogr/style_table_extensions.rb +3 -1
- data/lib/ogr/style_tool.rb +8 -14
- data/lib/ogr.rb +39 -1
- data/spec/ffi-gdal_spec.rb +18 -1
- data/spec/integration/gdal/color_table_info_spec.rb +49 -33
- data/spec/integration/gdal/dataset_info_spec.rb +294 -45
- data/spec/integration/gdal/driver_info_spec.rb +139 -31
- data/spec/integration/gdal/geo_transform_info_spec.rb +197 -26
- data/spec/integration/gdal/gridder_spec.rb +329 -0
- data/spec/integration/gdal/raster_attribute_table_info_spec.rb +216 -11
- data/spec/integration/gdal/raster_band_algorithms_spec.rb +33 -0
- data/spec/integration/gdal/raster_band_info_spec.rb +240 -271
- data/spec/integration/ogr/layer_spec.rb +3 -1
- data/spec/spec_helper.rb +15 -6
- data/spec/support/images/osgeo/gdal/data/hfa/float-rle.img +0 -0
- data/spec/support/images/osgeo/geotiff/GeogToWGS84GeoKey/GeogToWGS84GeoKey5.lgo +31 -0
- data/spec/support/images/osgeo/geotiff/GeogToWGS84GeoKey/GeogToWGS84GeoKey5.tif +0 -0
- data/spec/support/images/osgeo/geotiff/GeogToWGS84GeoKey/GeogToWGS84GeoKey5.tif.msk +0 -0
- data/spec/support/images/osgeo/geotiff/GeogToWGS84GeoKey/GeogToWGS84GeoKey5.txt +10 -0
- data/spec/support/images/osgeo/geotiff/gdal_eg/cea.tif +0 -0
- data/spec/support/images/osgeo/geotiff/gdal_eg/cea.txt +84 -0
- data/spec/support/images/osgeo/geotiff/zi_imaging/image0.lgo +45 -0
- data/spec/support/images/osgeo/geotiff/zi_imaging/image0.tif +0 -0
- data/spec/support/integration_help.rb +32 -2
- data/spec/support/shared_examples/gdal/major_object_examples.rb +0 -6
- data/spec/support/shared_examples/ogr/a_geometry.rb +1 -1
- data/spec/unit/ffi/gdal_spec.rb +1 -1
- data/spec/unit/gdal/color_entry_spec.rb +1 -0
- data/spec/unit/gdal/color_interpretation_spec.rb +1 -0
- data/spec/unit/gdal/dataset_spec.rb +53 -2
- data/spec/unit/gdal/geo_transform_mixins/extensions_spec.rb +67 -0
- data/spec/unit/gdal/geo_transform_spec.rb +1 -1
- data/spec/unit/gdal/grid_spec.rb +83 -0
- data/spec/unit/gdal/gridder/point_extracting_spec.rb +99 -0
- data/spec/unit/gdal/gridder_options_spec.rb +183 -0
- data/spec/unit/gdal/gridder_spec.rb +140 -0
- data/spec/unit/gdal/internal_helpers_spec.rb +166 -2
- data/spec/unit/gdal/major_object_spec.rb +2 -0
- data/spec/unit/gdal/options_spec.rb +1 -0
- data/spec/unit/gdal/raster_band_classifier_spec.rb +70 -12
- data/spec/unit/gdal/raster_band_mixins/extensions_spec.rb +71 -0
- data/spec/unit/gdal/raster_band_mixins/io_extensions_spec.rb +133 -0
- data/spec/unit/gdal/raster_band_spec.rb +1 -0
- data/spec/unit/gdal/rpc_info_spec.rb +1 -0
- data/spec/unit/gdal/version_info_spec.rb +2 -0
- data/spec/unit/gdal/warp_operation_spec.rb +1 -0
- data/spec/unit/ogr/coordinate_transformation_spec.rb +102 -0
- data/spec/unit/ogr/data_source_spec.rb +12 -0
- data/spec/unit/ogr/feature_extensions_spec.rb +88 -0
- data/spec/unit/ogr/feature_spec.rb +30 -46
- data/spec/unit/ogr/geometries/geometry_collection_25d_spec.rb +23 -0
- data/spec/unit/ogr/geometries/geometry_collection_spec.rb +3 -3
- data/spec/unit/ogr/geometries/line_string_25d_spec.rb +23 -0
- data/spec/unit/ogr/geometries/line_string_spec.rb +2 -2
- data/spec/unit/ogr/geometries/linear_ring_spec.rb +2 -2
- data/spec/unit/ogr/geometries/multi_line_string_25d_spec.rb +23 -0
- data/spec/unit/ogr/geometries/multi_point_25d_spec.rb +23 -0
- data/spec/unit/ogr/geometries/multi_polygon_25d_spec.rb +23 -0
- data/spec/unit/ogr/geometries/point_25d_spec.rb +23 -0
- data/spec/unit/ogr/geometries/point_spec.rb +14 -24
- data/spec/unit/ogr/geometries/polygon_25d_spec.rb +23 -0
- data/spec/unit/ogr/geometries/polygon_spec.rb +1 -1
- data/spec/unit/ogr/geometry_field_definition_spec.rb +1 -1
- data/spec/unit/ogr/geometry_spec.rb +196 -30
- data/spec/unit/ogr/internal_helpers_spec.rb +20 -9
- data/spec/unit/ogr/layer_mixins/ogr_feature_methods_spec.rb +14 -6
- data/spec/unit/ogr/spatial_reference_mixins/exporters_spec.rb +9 -1
- data/spec/unit/ogr/spatial_reference_mixins/parameter_getter_setters_spec.rb +2 -1
- data/spec/unit/ogr/style_table_spec.rb +1 -1
- data/tmp/.keep +0 -0
- metadata +121 -19
- data/examples/points.txt +0 -127
- data/lib/gdal/grid_types.rb +0 -22
- data/lib/ogr/geometries/point_extensions.rb +0 -32
- data/lib/ogr/geometry_extensions.rb +0 -59
data/lib/gdal/gridder.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
require 'narray'
|
2
|
+
require_relative '../gdal'
|
3
|
+
require_relative 'gridder_options'
|
4
|
+
require_relative 'gridder/point_extracting'
|
5
|
+
require_relative 'options'
|
6
|
+
require_relative '../ogr'
|
7
|
+
|
8
|
+
module GDAL
|
9
|
+
# Somewhat analogous to the gdal_grid utility.
|
10
|
+
class Gridder
|
11
|
+
include PointExtracting
|
12
|
+
include GDAL::Logger
|
13
|
+
|
14
|
+
DESIRED_BUFFER_SIZE = 16 * 1024 * 1024
|
15
|
+
|
16
|
+
# Object used by for doing the actual grid work.
|
17
|
+
#
|
18
|
+
# @!attribute [r] grid
|
19
|
+
# @return [GDAL::Grid]
|
20
|
+
attr_reader :grid
|
21
|
+
|
22
|
+
# @param source_layer [OGR::Layer] The layer from which to use points and
|
23
|
+
# spatial reference for interpolating. Alternatively, use +points+ to give
|
24
|
+
# specific point values for gridding.
|
25
|
+
# @param dest_file_name [String] The path to output the gridded raster to.
|
26
|
+
# @param gridder_options [GDAL::GridderOptions]
|
27
|
+
# @param points [Array<Array<Float>>] A 2D array of (x, y, z) points to use
|
28
|
+
# for gridding. Used for when you don't want to use all points from
|
29
|
+
# +source_layer+.
|
30
|
+
def initialize(source_layer, dest_file_name, gridder_options, points: nil)
|
31
|
+
@source_layer = source_layer
|
32
|
+
@dest_file_name = dest_file_name
|
33
|
+
@options = gridder_options
|
34
|
+
|
35
|
+
@points = points
|
36
|
+
@x_min = nil
|
37
|
+
@x_max = nil
|
38
|
+
@y_min = nil
|
39
|
+
@y_max = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
# Does all of the things: gathers points from the associated Layer,
|
43
|
+
# processes the points according to associated GridderOptions, grids the
|
44
|
+
# points, and writes out the newly gridder raster.
|
45
|
+
def grid!
|
46
|
+
dataset = build_dataset(@options.output_driver,
|
47
|
+
@dest_file_name,
|
48
|
+
@options.output_data_type,
|
49
|
+
@options.output_creation_options)
|
50
|
+
|
51
|
+
grid_and_write(dataset.raster_band(1), dataset.geo_transform)
|
52
|
+
|
53
|
+
if @options.algorithm_options[:no_data_value]
|
54
|
+
dataset.raster_band(1).no_data_value = @options.algorithm_options[:no_data_value]
|
55
|
+
end
|
56
|
+
|
57
|
+
dataset.close
|
58
|
+
end
|
59
|
+
|
60
|
+
#--------------------------------------------------------------------------
|
61
|
+
# PRIVATES
|
62
|
+
#--------------------------------------------------------------------------
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# Builds the Dataset to use for writing gridded raster data to.
|
67
|
+
#
|
68
|
+
# @param driver [GDAL::Driver]
|
69
|
+
# @param dest_file_name [String]
|
70
|
+
# @param data_type [FFI::GDAL::GDAL::DataType]
|
71
|
+
# @param creation_options [Hash]
|
72
|
+
# @return [GDAL::Dataset]
|
73
|
+
def build_dataset(driver, dest_file_name, data_type, creation_options = {})
|
74
|
+
dataset = driver.create_dataset(dest_file_name,
|
75
|
+
output_width,
|
76
|
+
output_height,
|
77
|
+
data_type: data_type,
|
78
|
+
**creation_options)
|
79
|
+
|
80
|
+
dataset.projection = build_output_spatial_reference
|
81
|
+
dataset.geo_transform = build_output_geo_transform
|
82
|
+
|
83
|
+
dataset
|
84
|
+
end
|
85
|
+
|
86
|
+
# Tries to get WKT of a spatial reference to use for the output dataset.
|
87
|
+
# First it tries to use {GDAL::GridderOptions#output_projection}, then tries
|
88
|
+
# the associated source layers {OGR::Layer#spatial_reference}.
|
89
|
+
#
|
90
|
+
# @return [String, nil] WKT of the spatial reference to use; +nil+ if none
|
91
|
+
# is found to use.
|
92
|
+
def build_output_spatial_reference
|
93
|
+
spatial_ref = @options.output_projection || @source_layer.spatial_reference
|
94
|
+
|
95
|
+
unless spatial_ref
|
96
|
+
log 'No spatial reference specified'
|
97
|
+
return
|
98
|
+
end
|
99
|
+
|
100
|
+
spatial_ref.to_wkt
|
101
|
+
end
|
102
|
+
|
103
|
+
# If @options.output_y_extent and/or @options.output_x_extent are set, it
|
104
|
+
# uses those and @options.output_size to build a {GDAL::GeoTransform} to be
|
105
|
+
# used with the output {GDAL::Dataset}.
|
106
|
+
#
|
107
|
+
# @return [GDAL::GeoTransform]
|
108
|
+
def build_output_geo_transform
|
109
|
+
envelope = OGR::Envelope.new
|
110
|
+
|
111
|
+
envelope.x_min = x_min
|
112
|
+
envelope.x_max = x_max
|
113
|
+
envelope.y_min = y_min
|
114
|
+
envelope.y_max = y_max
|
115
|
+
|
116
|
+
GDAL::GeoTransform.new_from_envelope(envelope, output_width, output_height)
|
117
|
+
end
|
118
|
+
|
119
|
+
# The x_min value to be used for the gridder and output raster.
|
120
|
+
#
|
121
|
+
# @return [Float]
|
122
|
+
def x_min
|
123
|
+
@x_min ||= @options.output_x_extent.fetch(:min) { @source_layer.extent.x_min }
|
124
|
+
end
|
125
|
+
|
126
|
+
# The x_max value to be used for the gridder and output raster.
|
127
|
+
#
|
128
|
+
# @return [Float]
|
129
|
+
def x_max
|
130
|
+
@x_max ||= @options.output_x_extent.fetch(:max) { @source_layer.extent.x_max }
|
131
|
+
end
|
132
|
+
|
133
|
+
# The y_min value to be used for the gridder and output raster.
|
134
|
+
#
|
135
|
+
# @return [Float]
|
136
|
+
def y_min
|
137
|
+
@y_min ||= @options.output_y_extent.fetch(:min) { @source_layer.extent.y_min }
|
138
|
+
end
|
139
|
+
|
140
|
+
# The y_max value to be used for the gridder and output raster.
|
141
|
+
#
|
142
|
+
# @return [Float]
|
143
|
+
def y_max
|
144
|
+
@y_max ||= @options.output_y_extent.fetch(:max) { @source_layer.extent.y_max }
|
145
|
+
end
|
146
|
+
|
147
|
+
# @return [Fixnum]
|
148
|
+
def output_width
|
149
|
+
@options.output_size[:width]
|
150
|
+
end
|
151
|
+
|
152
|
+
# @return [Fixnum]
|
153
|
+
def output_height
|
154
|
+
@options.output_size[:height]
|
155
|
+
end
|
156
|
+
|
157
|
+
# Figures out the proper block sizes to use for iterating over layer pixels,
|
158
|
+
# gridding them, and writing them to the raster file.
|
159
|
+
#
|
160
|
+
# @param raster_band_block_size [Fixnum]
|
161
|
+
def each_block(raster_band_block_size)
|
162
|
+
data_type_size = @options.output_data_type_size
|
163
|
+
block_size = build_block_sizes(raster_band_block_size, data_type_size)
|
164
|
+
log "Work buffer: #{block_size[:x]} * #{block_size[:y]}"
|
165
|
+
|
166
|
+
block_number = 0
|
167
|
+
block_count = build_block_count(block_size[:x], block_size[:y], output_width, output_height)
|
168
|
+
log "Block count: #{block_count}"
|
169
|
+
|
170
|
+
0.step(output_height - 1, block_size[:y]).each do |y_offset|
|
171
|
+
0.step(output_width - 1, block_size[:x]).each do |x_offset|
|
172
|
+
yield block_number, block_count, block_size, x_offset, y_offset
|
173
|
+
block_number += 1
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Iterates through each block of data, grids it, then writes it to the
|
179
|
+
# output raster.
|
180
|
+
#
|
181
|
+
# @param raster_band [GDAL::RasterBand]
|
182
|
+
# @param geo_transform [GDAL::GeoTransform]
|
183
|
+
def grid_and_write(raster_band, geo_transform)
|
184
|
+
data_ptr = GDAL._pointer_from_data_type(@options.output_data_type, output_width * output_height)
|
185
|
+
each_block(raster_band.block_size) do |block_number, block_count, block_size, x_offset, y_offset|
|
186
|
+
scaled_progress_ptr = nil
|
187
|
+
progress_arg = nil
|
188
|
+
|
189
|
+
if @options.progress_formatter
|
190
|
+
scaled_progress_ptr = build_scaled_progress_pointer(block_number, block_count)
|
191
|
+
progress_arg = FFI::CPL::Progress::ScaledProgress
|
192
|
+
end
|
193
|
+
|
194
|
+
x_request = build_data_request_size(block_size[:x], x_offset, output_width)
|
195
|
+
y_request = build_data_request_size(block_size[:y], y_offset, output_height)
|
196
|
+
output_size = { x: x_request, y: y_request }
|
197
|
+
|
198
|
+
grid_x_min, grid_x_max = build_grid_extents(x_min, geo_transform.pixel_width, x_offset, x_request)
|
199
|
+
grid_y_min, grid_y_max = build_grid_extents(y_min, geo_transform.pixel_height, y_offset, y_request)
|
200
|
+
extents = { x_min: grid_x_min, x_max: grid_x_max, y_min: grid_y_min, y_max: grid_y_max }
|
201
|
+
|
202
|
+
@options.grid.create(points, extents, data_ptr, output_size,
|
203
|
+
progress_arg, scaled_progress_ptr)
|
204
|
+
|
205
|
+
raster_band.raster_io('w', data_ptr, x_offset: x_offset, y_offset: y_offset,
|
206
|
+
x_size: x_request, y_size: y_request,
|
207
|
+
buffer_x_size: x_request, buffer_y_size: y_request)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# @param raster_band_block_size [Hash{x: Fixnum, y: Fixnum}]
|
212
|
+
# @param data_type_size [Fixnum]
|
213
|
+
# @return [Hash{x: Fixnum, y: Fixnum}]
|
214
|
+
def build_block_sizes(raster_band_block_size, data_type_size)
|
215
|
+
block_x_size = raster_band_block_size[:x]
|
216
|
+
block_y_size = raster_band_block_size[:y]
|
217
|
+
|
218
|
+
if block_x_size.to_i < output_width && block_y_size.to_i < output_height &&
|
219
|
+
block_x_size.to_i < DESIRED_BUFFER_SIZE / (block_y_size * data_type_size)
|
220
|
+
new_block_x_size = DESIRED_BUFFER_SIZE / (block_y_size * data_type_size)
|
221
|
+
block_x_size = (new_block_x_size / block_x_size) * block_x_size
|
222
|
+
|
223
|
+
block_x_size = output_width if block_x_size.to_i > output_width
|
224
|
+
elsif block_x_size.to_i == output_width && block_y_size.to_i < output_height &&
|
225
|
+
block_y_size.to_i < DESIRED_BUFFER_SIZE / (output_width * data_type_size)
|
226
|
+
new_block_y_size = DESIRED_BUFFER_SIZE / (output_width * data_type_size)
|
227
|
+
block_y_size = (new_block_y_size / block_y_size) * block_y_size
|
228
|
+
|
229
|
+
block_y_size = output_height if block_y_size.to_i > output_height
|
230
|
+
end
|
231
|
+
|
232
|
+
{ x: block_x_size.freeze, y: block_y_size.freeze }
|
233
|
+
end
|
234
|
+
|
235
|
+
# Builds a pointer to a GDALScaledProgress function. This is used in
|
236
|
+
# conjunction with the @options.progress_function to be able to display
|
237
|
+
# progress across grid+rasterize iterations. Without this, the user would
|
238
|
+
# only get progress for each time through a block, not for all of the
|
239
|
+
# blocks.
|
240
|
+
#
|
241
|
+
# @see http://gdal.sourcearchive.com/documentation/1.7.2/gdal_8h_904fbbb050e16c9d0ac028dc5113ef27.html
|
242
|
+
# @param block_number [Fixnum]
|
243
|
+
# @param block_count [Fixnum]
|
244
|
+
# @return [FFI::Pointer]
|
245
|
+
def build_scaled_progress_pointer(block_number, block_count)
|
246
|
+
return unless @options.progress_formatter
|
247
|
+
|
248
|
+
FFI::CPL::Progress.GDALCreateScaledProgress(
|
249
|
+
block_number.to_f / block_count,
|
250
|
+
(block_number + 1).to_f / block_count,
|
251
|
+
@options.progress_formatter,
|
252
|
+
nil)
|
253
|
+
end
|
254
|
+
|
255
|
+
# Determines how large of a chunk of data to grid and rasterize.
|
256
|
+
#
|
257
|
+
# @param block_size [Fixnum]
|
258
|
+
# @param raster_border [Fixnum]
|
259
|
+
# @return [Fixnum]
|
260
|
+
def build_data_request_size(block_size, offset, raster_border)
|
261
|
+
request = block_size
|
262
|
+
|
263
|
+
if offset + request > raster_border
|
264
|
+
raster_border - offset
|
265
|
+
else
|
266
|
+
request
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# @param min [Float]
|
271
|
+
# @param pixel_size [Float]
|
272
|
+
# @param offset [Float]
|
273
|
+
# @param request_size [Fixnum]
|
274
|
+
# @return [Array<Fixnum, Fixnum>] The min and max values based on the given
|
275
|
+
# parameters.
|
276
|
+
def build_grid_extents(min, pixel_size, offset, request_size)
|
277
|
+
grid_min = min + pixel_size * offset
|
278
|
+
grid_max = min + pixel_size * (offset + request_size)
|
279
|
+
|
280
|
+
[grid_min, grid_max]
|
281
|
+
end
|
282
|
+
|
283
|
+
# @param block_x_size [Fixnum]
|
284
|
+
# @param block_y_size [Fixnum]
|
285
|
+
# @param raster_width [Fixnum]
|
286
|
+
# @param raster_height [Fixnum]
|
287
|
+
# @return [Fixnum] The total number of blocks that should be iterated
|
288
|
+
# through during the grid+rasterize process.
|
289
|
+
def build_block_count(block_x_size, block_y_size, raster_width, raster_height)
|
290
|
+
((raster_width + block_x_size - 1) / block_x_size) *
|
291
|
+
((raster_height + block_y_size - 1) / block_y_size)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
require_relative 'grid'
|
2
|
+
require_relative 'options'
|
3
|
+
require_relative '../ogr'
|
4
|
+
|
5
|
+
module GDAL
|
6
|
+
# Object to be used with a {GDAL::Gridder}.
|
7
|
+
class GridderOptions
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
# Name of field attribute to extract from each feature to use for Z values.
|
11
|
+
#
|
12
|
+
# @!attribute [rw] input_field_name
|
13
|
+
# @return [String]
|
14
|
+
attr_accessor :input_field_name
|
15
|
+
|
16
|
+
# Custom progress output Proc, passed on to {GDAL::Grid#create}. This must
|
17
|
+
# follow semantics imposed by +FFI::GDAL::GDAL.ProgressFunc+.
|
18
|
+
#
|
19
|
+
# This option doesn't exist in gdal_grid; you only get their output format
|
20
|
+
# or no output at all (using +-q+).
|
21
|
+
#
|
22
|
+
# @!attribute [rw] progress_formatter
|
23
|
+
# @return [Proc]
|
24
|
+
attr_accessor :progress_formatter
|
25
|
+
|
26
|
+
# Use for filtering out input points; any input points from the layer that
|
27
|
+
# fall within this boundary will be excluded from the gridding process.
|
28
|
+
# Note that this does not clip the output raster.
|
29
|
+
#
|
30
|
+
# Replaces gdal_grid's +-clipsrc+ option.
|
31
|
+
#
|
32
|
+
# @!attribute [rw] input_clipping_geometry
|
33
|
+
# @return [OGR::Geometry]
|
34
|
+
attr_reader :input_clipping_geometry
|
35
|
+
|
36
|
+
# Driver-specific options to pass to the {GDAL::Driver} when creating the
|
37
|
+
# raster. Check out GDAL documentation for the driver you're specifying
|
38
|
+
# (specified here through {#output_format}) to see what options you have
|
39
|
+
# available.
|
40
|
+
#
|
41
|
+
# Correlates to gdal_grid option +-co+.
|
42
|
+
#
|
43
|
+
# @!attribute output_creation_options
|
44
|
+
# @return [Hash]
|
45
|
+
attr_reader :output_creation_options
|
46
|
+
|
47
|
+
# The {GDAL::Driver} name to use for creating the output raster.
|
48
|
+
#
|
49
|
+
# Correlates to gdal_grid option +-of+.
|
50
|
+
#
|
51
|
+
# @!attribute [rw] output_format
|
52
|
+
# @return [String]
|
53
|
+
attr_reader :output_format
|
54
|
+
|
55
|
+
# The minimum and maximum X coordinates for the output raster.
|
56
|
+
#
|
57
|
+
# Correlates to gdal_grid option +-txe+.
|
58
|
+
#
|
59
|
+
# @!attribute [rw] output_x_extent
|
60
|
+
# @return [Hash{min: Number, max: Number}]
|
61
|
+
attr_reader :output_x_extent
|
62
|
+
|
63
|
+
# The minimum and maximum Y coordinates for the output raster.
|
64
|
+
#
|
65
|
+
# Correlates to gdal_grid option +-tye+.
|
66
|
+
#
|
67
|
+
# @!attribute [rw] output_y_extent
|
68
|
+
# @return [Hash{min: Number, max: Number}]
|
69
|
+
attr_reader :output_y_extent
|
70
|
+
|
71
|
+
# The SpatialReference to use for the output raster's {GDAL::Dataset#projection}.
|
72
|
+
# If one isn't given, the {GDAL::Gridder} will try to use the one from the
|
73
|
+
# source layer.
|
74
|
+
#
|
75
|
+
# Correlates to gdal_grid option +-a_srs+.
|
76
|
+
#
|
77
|
+
# @!attribute [rw] output_projection
|
78
|
+
# @return [OGR::SpatialReference]
|
79
|
+
attr_reader :output_projection
|
80
|
+
|
81
|
+
# Dimensions to output the raster in.
|
82
|
+
#
|
83
|
+
# Correlates to gdal_grid option +-outsize+.
|
84
|
+
#
|
85
|
+
# @overload output_size
|
86
|
+
# @overload output_size=(width_height_array)
|
87
|
+
# Sets the output Hash using a 2-element Array.
|
88
|
+
# @param width_height_array [Array<Float>]
|
89
|
+
# A 2-element Array specifying the width and height of the output raster.
|
90
|
+
# @overload output_size=(width_height_hash)
|
91
|
+
# Sets the output Hash using a similar input Hash.
|
92
|
+
# @param width_height_hash [Hash{width => Number, height => Number}]
|
93
|
+
# A Hash with :width and :height keys, specifying the width and height
|
94
|
+
# of the output raster.
|
95
|
+
# @return [Hash{width: Number, height: Number}]
|
96
|
+
attr_reader :output_size
|
97
|
+
|
98
|
+
# Data type of the output raster values.
|
99
|
+
#
|
100
|
+
# Correlates to gdal_grid option +-ot+.
|
101
|
+
#
|
102
|
+
# @!attribute [rw] output_data_type
|
103
|
+
# @return [FFI::GDAL::GDAL::DataType]
|
104
|
+
attr_reader :output_data_type
|
105
|
+
|
106
|
+
# Object used by the {GDAL::Gridder} for doing the actual grid work.
|
107
|
+
#
|
108
|
+
# @!attribute [r] grid
|
109
|
+
# @return [GDAL::Grid]
|
110
|
+
attr_reader :grid
|
111
|
+
|
112
|
+
# Object used by the {GDAL::Gridder} for doing the actual grid work.
|
113
|
+
#
|
114
|
+
# @!method algorithm_options
|
115
|
+
# @return [FFI::Struct] One of the FFI::GDAL grid algorithm Options objects.
|
116
|
+
def_delegator :@grid, :algorithm_options, :algorithm_options
|
117
|
+
|
118
|
+
# @param algorithm_type [Symbol] One of {FFI::GDAL::Alg::GridAlgorithm}.
|
119
|
+
def initialize(algorithm_type)
|
120
|
+
# Options with defaults
|
121
|
+
@output_data_type = :GDT_Float64
|
122
|
+
@output_format = 'GTiff'
|
123
|
+
@output_size = { width: 256, height: 256 }
|
124
|
+
|
125
|
+
# Options without defaults
|
126
|
+
@input_clipping_geometry = nil
|
127
|
+
@output_x_extent = {}
|
128
|
+
@output_y_extent = {}
|
129
|
+
@output_projection = nil
|
130
|
+
@output_creation_options = {}
|
131
|
+
@progress_formatter = nil
|
132
|
+
|
133
|
+
@grid = GDAL::Grid.new(algorithm_type, data_type: @output_data_type)
|
134
|
+
end
|
135
|
+
|
136
|
+
# @param geometry [OGR::Geometry]
|
137
|
+
# @return [OGR::Geometry]
|
138
|
+
def input_clipping_geometry=(geometry)
|
139
|
+
unless geometry.is_a?(OGR::Geometry)
|
140
|
+
raise OGR::InvalidGeometry,
|
141
|
+
"Clipping geometry must be a OGR::Geometry type, but was a #{geometry.class}"
|
142
|
+
end
|
143
|
+
|
144
|
+
@input_clipping_geometry = geometry
|
145
|
+
end
|
146
|
+
|
147
|
+
# @param type [Symbol] Must be one of FFI::GDAL::GDAL::DataType.
|
148
|
+
def output_data_type=(type)
|
149
|
+
data_types = FFI::GDAL::GDAL::DataType.symbols
|
150
|
+
|
151
|
+
unless data_types.include?(type)
|
152
|
+
raise GDAL::InvalidDataType,
|
153
|
+
"output_data_type must be one of #{data_types} but was #{type}"
|
154
|
+
end
|
155
|
+
|
156
|
+
@grid.data_type = @output_data_type = type
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [Fixnum]
|
160
|
+
def output_data_type_size
|
161
|
+
GDAL::DataType.size(@output_data_type) / 8
|
162
|
+
end
|
163
|
+
|
164
|
+
# @param format [String] Must be one of GDAL::Driver.short_names.
|
165
|
+
def output_format=(format)
|
166
|
+
driver_names = GDAL::Driver.short_names
|
167
|
+
|
168
|
+
unless driver_names.include?(format)
|
169
|
+
raise GDAL::InvalidDriverName,
|
170
|
+
"output_form must be one of #{driver_names} but was #{format}"
|
171
|
+
end
|
172
|
+
|
173
|
+
@output_format = format
|
174
|
+
end
|
175
|
+
|
176
|
+
# The {GDAL::Driver}, based on {#output_format} to use for creating the
|
177
|
+
# output raster.
|
178
|
+
#
|
179
|
+
# @return [GDAL::Driver]
|
180
|
+
def output_driver
|
181
|
+
@output_driver ||= GDAL::Driver.by_name(@output_format)
|
182
|
+
end
|
183
|
+
|
184
|
+
# @param min_max [Array<Fixnum>, Hash{min => Number, max => Number}]
|
185
|
+
def output_x_extent=(min_max)
|
186
|
+
min, max = extract_min_max(min_max, :min, :max)
|
187
|
+
|
188
|
+
@output_x_extent = { min: min, max: max }
|
189
|
+
end
|
190
|
+
|
191
|
+
# @param min_max [Array<Fixnum>, Hash{min => Number, max => Number}]
|
192
|
+
def output_y_extent=(min_max)
|
193
|
+
min, max = extract_min_max(min_max, :min, :max)
|
194
|
+
|
195
|
+
@output_y_extent = { min: min, max: max }
|
196
|
+
end
|
197
|
+
|
198
|
+
# @param width_height [Array<Float>, Hash{width => Number, height => Number}]
|
199
|
+
# Either a 2-element Array or a Hash with :width and :height keys,
|
200
|
+
# specifying the width and height of the output raster.
|
201
|
+
def output_size=(width_height)
|
202
|
+
width, height = extract_min_max(width_height, :width, :height)
|
203
|
+
|
204
|
+
@output_size = { width: width, height: height }
|
205
|
+
end
|
206
|
+
|
207
|
+
# Set to use a different SRID for the output raster. Defaults to use the
|
208
|
+
# same as the source Layer.
|
209
|
+
#
|
210
|
+
# @param spatial_reference [OGR::SpatialReference]
|
211
|
+
def output_projection=(spatial_reference)
|
212
|
+
unless spatial_reference.is_a?(OGR::SpatialReference)
|
213
|
+
raise OGR::InvalidSpatialReference,
|
214
|
+
"output_projection must be an OGR::SpatialReference but was a #{spatial_reference.class}"
|
215
|
+
end
|
216
|
+
|
217
|
+
@output_projection = spatial_reference
|
218
|
+
end
|
219
|
+
|
220
|
+
# @param options_hash [Hash]
|
221
|
+
def output_creation_options=(**options_hash)
|
222
|
+
return if options_hash.empty?
|
223
|
+
|
224
|
+
@output_creation_options = options_hash
|
225
|
+
end
|
226
|
+
|
227
|
+
private
|
228
|
+
|
229
|
+
# Extracts a min and max value from either a 2-element Array or a Hash with
|
230
|
+
# :min and :max keys.
|
231
|
+
#
|
232
|
+
# @param content [Array, Hash]
|
233
|
+
# @param min_name [Symbol]
|
234
|
+
# @param max_name [Symbol]
|
235
|
+
# @return [Array<Number>]
|
236
|
+
def extract_min_max(content, min_name, max_name)
|
237
|
+
case content
|
238
|
+
when Array
|
239
|
+
extract_min_max_from_array(content, min_name, max_name)
|
240
|
+
when Hash
|
241
|
+
extract_min_max_from_hash(content, min_name, max_name)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# @param content [Array, Hash]
|
246
|
+
# @param min_name [Symbol]
|
247
|
+
# @param max_name [Symbol]
|
248
|
+
# @return [Array<Number>]
|
249
|
+
def extract_min_max_from_array(content, min_name, max_name)
|
250
|
+
unless content.length == 2
|
251
|
+
raise ArgumentError,
|
252
|
+
"Please supply only 2 elements, one for #{min_name}, one for #{max_name}"
|
253
|
+
end
|
254
|
+
|
255
|
+
[content[0], content[1]]
|
256
|
+
end
|
257
|
+
|
258
|
+
# @param content [Array, Hash]
|
259
|
+
# @param min_name [Symbol]
|
260
|
+
# @param max_name [Symbol]
|
261
|
+
# @return [Array<Number>]
|
262
|
+
def extract_min_max_from_hash(content, min_name, max_name)
|
263
|
+
valid_keys = [min_name, max_name]
|
264
|
+
actual_keys = content.keys
|
265
|
+
|
266
|
+
unless actual_keys.length == 2 && valid_keys & actual_keys == valid_keys
|
267
|
+
raise ArgumentError, "Please supply only key/value pairs for #{min_name} and #{max_name}"
|
268
|
+
end
|
269
|
+
|
270
|
+
[content[min_name], content[max_name]]
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|