ffi-gdal 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +9 -0
  3. data/.devcontainer/devcontainer.json +98 -0
  4. data/.github/CODEOWNERS +1 -0
  5. data/.github/workflows/codacy.yml +3 -3
  6. data/.github/workflows/codeql.yml +4 -4
  7. data/.github/workflows/continuous-integration.yml +30 -19
  8. data/.github/workflows/dependency-review.yml +2 -2
  9. data/.github/workflows/specs-in-docker.yml +12 -6
  10. data/.gitignore +4 -1
  11. data/Changelog.md +40 -5
  12. data/Gemfile +4 -2
  13. data/README.md +35 -0
  14. data/lib/ext/numeric_as_data_type.rb +1 -1
  15. data/lib/ffi/cpl/vsi.rb +10 -0
  16. data/lib/ffi/gdal/gdal.rb +9 -2
  17. data/lib/ffi/gdal/grid_data_metrics_options.rb +27 -5
  18. data/lib/ffi/gdal/grid_inverse_distance_to_a_power_options.rb +30 -10
  19. data/lib/ffi/gdal/grid_moving_average_options.rb +30 -5
  20. data/lib/ffi/gdal/grid_nearest_neighbor_options.rb +24 -4
  21. data/lib/ffi/gdal/internal_helpers/gdal_version.rb +15 -0
  22. data/lib/ffi/gdal/internal_helpers/layout_version.rb +9 -0
  23. data/lib/ffi/gdal/internal_helpers/layout_version_resolver.rb +24 -0
  24. data/lib/ffi/gdal/internal_helpers.rb +11 -0
  25. data/lib/ffi/gdal/utils.rb +984 -0
  26. data/lib/ffi/gdal/version.rb +1 -1
  27. data/lib/ffi/gdal.rb +3 -1
  28. data/lib/ffi/ogr/core.rb +1 -1
  29. data/lib/ffi/ogr/srs_api.rb +17 -0
  30. data/lib/gdal/cpl_error_handler.rb +30 -15
  31. data/lib/gdal/exceptions.rb +35 -16
  32. data/lib/gdal/extensions/color_table/extensions.rb +1 -1
  33. data/lib/gdal/extensions/gridder.rb +4 -0
  34. data/lib/gdal/geo_transform.rb +13 -0
  35. data/lib/gdal/grid_algorithms/algorithm_base.rb +35 -0
  36. data/lib/gdal/grid_algorithms/inverse_distance_to_a_power.rb +3 -7
  37. data/lib/gdal/grid_algorithms/metric_average_distance.rb +5 -4
  38. data/lib/gdal/grid_algorithms/metric_average_distance_pts.rb +5 -4
  39. data/lib/gdal/grid_algorithms/metric_count.rb +5 -4
  40. data/lib/gdal/grid_algorithms/metric_maximum.rb +5 -4
  41. data/lib/gdal/grid_algorithms/metric_minimum.rb +5 -4
  42. data/lib/gdal/grid_algorithms/metric_range.rb +5 -4
  43. data/lib/gdal/grid_algorithms/moving_average.rb +3 -7
  44. data/lib/gdal/grid_algorithms/nearest_neighbor.rb +3 -7
  45. data/lib/gdal/grid_algorithms.rb +2 -0
  46. data/lib/gdal/internal_helpers.rb +8 -5
  47. data/lib/gdal/major_object.rb +6 -0
  48. data/lib/gdal/raster_band.rb +16 -12
  49. data/lib/gdal/utils/dem/options.rb +52 -0
  50. data/lib/gdal/utils/dem.rb +108 -0
  51. data/lib/gdal/utils/grid/options.rb +52 -0
  52. data/lib/gdal/utils/grid.rb +72 -0
  53. data/lib/gdal/utils/helpers/dataset_list.rb +43 -0
  54. data/lib/gdal/utils/helpers/string_list.rb +47 -0
  55. data/lib/gdal/utils/helpers.rb +11 -0
  56. data/lib/gdal/utils/info/options.rb +52 -0
  57. data/lib/gdal/utils/info.rb +40 -0
  58. data/lib/gdal/utils/nearblack/options.rb +52 -0
  59. data/lib/gdal/utils/nearblack.rb +119 -0
  60. data/lib/gdal/utils/rasterize/options.rb +52 -0
  61. data/lib/gdal/utils/rasterize.rb +108 -0
  62. data/lib/gdal/utils/translate/options.rb +52 -0
  63. data/lib/gdal/utils/translate.rb +72 -0
  64. data/lib/gdal/utils/vector_translate/options.rb +52 -0
  65. data/lib/gdal/utils/vector_translate.rb +132 -0
  66. data/lib/gdal/utils/warp/options.rb +52 -0
  67. data/lib/gdal/utils/warp.rb +118 -0
  68. data/lib/gdal/utils.rb +22 -0
  69. data/lib/gdal/warp_options.rb +11 -2
  70. data/lib/gdal.rb +1 -0
  71. data/lib/ogr/extensions/layer/extensions.rb +1 -1
  72. data/lib/ogr/extensions/spatial_reference/extensions.rb +4 -4
  73. data/lib/ogr/geometry.rb +1 -6
  74. data/lib/ogr/layer.rb +1 -1
  75. data/lib/ogr/spatial_reference.rb +27 -2
  76. metadata +32 -5
  77. data/.ruby-version +0 -1
  78. data/lib/gdal/grid_algorithms/data_metrics_base.rb +0 -14
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rasterize/options"
4
+
5
+ module GDAL
6
+ module Utils
7
+ # Wrapper for gdal_rasterize using GDALRasterize C API.
8
+ #
9
+ # @see https://gdal.org/programs/gdal_rasterize.html gdal_rasterize utility documentation.
10
+ # @see https://gdal.org/api/gdal_utils.html#_CPPv413GDALRasterizePKc12GDALDatasetH12GDALDatasetHPK20GDALRasterizeOptionsPi
11
+ # GDALRasterize C API.
12
+ class Rasterize
13
+ # Perform the gdal_rasterize (GDALRasterize) operation.
14
+ #
15
+ # @example Rasterize a dataset with options (for dst_dataset_path).
16
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
17
+ # options = GDAL::Utils::Rasterize::Options.new(options: ["-ts", "10", "10"])
18
+ #
19
+ # dataset = GDAL::Utils::Rasterize.perform(
20
+ # dst_dataset_path: "destination.tif",
21
+ # src_dataset: src_dataset,
22
+ # options: options
23
+ # )
24
+ #
25
+ # # Do something with the dataset.
26
+ # puts dataset.raster_x_size
27
+ #
28
+ # # You must close the dataset when you are done with it.
29
+ # dataset.close
30
+ # src_dataset.close
31
+ #
32
+ # @example Rasterize a dataset (for dst_dataset_path) using block syntax.
33
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
34
+ # options = GDAL::Utils::Rasterize::Options.new(options: ["-ts", "10", "10"])
35
+ #
36
+ # GDAL::Utils::Rasterize.perform(
37
+ # dst_dataset_path: "destination.tif",
38
+ # src_dataset: src_dataset,
39
+ # options: options
40
+ # ) do |dataset|
41
+ # # Do something with the dataset.
42
+ # puts dataset.raster_x_size
43
+ #
44
+ # # Dataset will be closed automatically.
45
+ # end
46
+ # src_dataset.close
47
+ #
48
+ # @example Rasterize a dataset (for dst_dataset).
49
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
50
+ # dst_dataset = GDAL::Dataset.open("destination.tif", "w")
51
+ # options = GDAL::Utils::Rasterize::Options.new(options: ["-ts", "10", "10"])
52
+ #
53
+ # GDAL::Utils::Rasterize.perform(dst_dataset: dst_dataset, src_dataset: src_dataset, options: options)
54
+ #
55
+ # # You must close the dataset when you are done with it.
56
+ # dst_dataset.close
57
+ # src_dataset.close
58
+ #
59
+ # @param dst_dataset_path [String] The path to the destination dataset.
60
+ # @param dst_dataset [GDAL::Dataset] The destination dataset.
61
+ # @param src_dataset [OGR::DataSource] The source dataset.
62
+ # @param options [GDAL::Utils::Rasterize::Options] Options.
63
+ # @yield [GDAL::Dataset] The destination dataset.
64
+ # @return [GDAL::Dataset] The destination dataset (only if block is not specified; dataset must be closed).
65
+ def self.perform(src_dataset:, dst_dataset: nil, dst_dataset_path: nil, options: Options.new, &block)
66
+ if dst_dataset
67
+ for_dataset(dst_dataset: dst_dataset, src_dataset: src_dataset, options: options)
68
+ else
69
+ for_dataset_path(dst_dataset_path: dst_dataset_path, src_dataset: src_dataset, options: options, &block)
70
+ end
71
+ end
72
+
73
+ def self.for_dataset(dst_dataset:, src_dataset:, options: Options.new)
74
+ result_dataset_ptr(dst_dataset: dst_dataset, src_dataset: src_dataset, options: options)
75
+
76
+ # Return the input dataset as the output dataset (dataset is modified in place).
77
+ dst_dataset
78
+ end
79
+ private_class_method :for_dataset
80
+
81
+ def self.for_dataset_path(dst_dataset_path:, src_dataset:, options: Options.new, &block)
82
+ dst_dataset_ptr = result_dataset_ptr(
83
+ dst_dataset_path: dst_dataset_path, src_dataset: src_dataset, options: options
84
+ )
85
+
86
+ ::GDAL::Dataset.open(dst_dataset_ptr, "w", &block)
87
+ end
88
+ private_class_method :for_dataset_path
89
+
90
+ def self.result_dataset_ptr(src_dataset:, dst_dataset_path: nil, dst_dataset: nil, options: Options.new)
91
+ result_code_ptr = ::FFI::MemoryPointer.new(:int)
92
+ dst_dataset_ptr = ::FFI::GDAL::Utils.GDALRasterize(
93
+ dst_dataset_path,
94
+ dst_dataset&.c_pointer,
95
+ src_dataset.c_pointer,
96
+ options.c_pointer,
97
+ result_code_ptr
98
+ )
99
+ success = result_code_ptr.read_int.zero?
100
+
101
+ raise ::GDAL::Error, "GDALRasterize failed." if dst_dataset_ptr.null? || !success
102
+
103
+ dst_dataset_ptr
104
+ end
105
+ private_class_method :result_dataset_ptr
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GDAL
4
+ module Utils
5
+ class Translate
6
+ # Ruby wrapper for GDALTranslateOptions C API (options for gdal_translate utility).
7
+ #
8
+ # @see GDAL::Utils::Translate
9
+ # @see https://gdal.org/programs/gdal_translate.html gdal_translate utility documentation.
10
+ class Options
11
+ # @private
12
+ class AutoPointer < ::FFI::AutoPointer
13
+ # @param pointer [FFI::Pointer]
14
+ def self.release(pointer)
15
+ return unless pointer && !pointer.null?
16
+
17
+ ::FFI::GDAL::Utils.GDALTranslateOptionsFree(pointer)
18
+ end
19
+ end
20
+
21
+ # @return [AutoPointer] C pointer to the GDALTranslateOptions.
22
+ attr_reader :c_pointer
23
+
24
+ # @return [Array<String>] The options.
25
+ attr_reader :options
26
+
27
+ # Create a new instance.
28
+ #
29
+ # @see https://gdal.org/programs/gdal_translate.html
30
+ # List of available options could be found in gdal_translate utility documentation.
31
+ #
32
+ # @example Create a new instance.
33
+ # options = GDAL::Utils::Translate::Options.new(options: ["-of", "GTiff", "-co", "COMPRESS=DEFLATE"])
34
+ #
35
+ # @param options [Array<String>] The options list.
36
+ def initialize(options: [])
37
+ @options = options
38
+ @string_list = ::GDAL::Utils::Helpers::StringList.new(strings: options)
39
+ @c_pointer = AutoPointer.new(options_pointer)
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :string_list
45
+
46
+ def options_pointer
47
+ ::FFI::GDAL::Utils.GDALTranslateOptionsNew(string_list.c_pointer, nil)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "translate/options"
4
+
5
+ module GDAL
6
+ module Utils
7
+ # Wrapper for gdal_translate using GDALTranslate C API.
8
+ #
9
+ # @see https://gdal.org/programs/gdal_translate.html gdal_translate utility documentation.
10
+ # @see https://gdal.org/api/gdal_utils.html#gdal__utils_8h_1a1cf5b30de14ccaf847ae7a77bb546b28 GDALTranslate C API.
11
+ class Translate
12
+ # Perform the gdal_translate (GDALTranslate) operation.
13
+ #
14
+ # @example Translate a dataset.
15
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
16
+ # dataset = GDAL::Utils::Translate.perform(dst_dataset_path: "destination.tif", src_dataset: src_dataset)
17
+ #
18
+ # # Do something with the dataset.
19
+ # puts dataset.raster_x_size
20
+ #
21
+ # # You must close the dataset when you are done with it.
22
+ # dataset.close
23
+ # src_dataset.close
24
+ #
25
+ # @example Translate a dataset with options.
26
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
27
+ # dataset = GDAL::Utils::Translate.perform(
28
+ # dst_dataset_path: "destination.tif",
29
+ # src_dataset: src_dataset,
30
+ # options: GDAL::Utils::Translate::Options.new(options: ["-of", "GTiff", "-co", "COMPRESS=DEFLATE"])
31
+ # )
32
+ #
33
+ # # Do something with the dataset.
34
+ # puts dataset.raster_x_size
35
+ #
36
+ # # You must close the dataset when you are done with it.
37
+ # dataset.close
38
+ # src_dataset.close
39
+ #
40
+ # @example Translate a dataset using block syntax.
41
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
42
+ # GDAL::Utils::Translate.perform(dst_dataset_path: "destination.tif", src_dataset: src_dataset) do |dataset|
43
+ # # Do something with the dataset.
44
+ # puts dataset.raster_x_size
45
+ #
46
+ # # Dataset will be closed automatically.
47
+ # end
48
+ # src_dataset.close
49
+ #
50
+ # @param dst_dataset_path [String] The path to the destination dataset.
51
+ # @param src_dataset [GDAL::Dataset] The source dataset.
52
+ # @param options [GDAL::Utils::Translate::Options] Options.
53
+ # @yield [GDAL::Dataset] The destination dataset.
54
+ # @return [GDAL::Dataset] The destination dataset (only if block is not specified; dataset must be closed).
55
+ # @raise [GDAL::Error] If the operation fails.
56
+ def self.perform(dst_dataset_path:, src_dataset:, options: Options.new, &block)
57
+ result_code_ptr = ::FFI::MemoryPointer.new(:int)
58
+ dst_dataset_ptr = ::FFI::GDAL::Utils.GDALTranslate(
59
+ dst_dataset_path,
60
+ src_dataset.c_pointer,
61
+ options.c_pointer,
62
+ result_code_ptr
63
+ )
64
+ success = result_code_ptr.read_int.zero?
65
+
66
+ raise ::GDAL::Error, "GDALTranslate failed." if dst_dataset_ptr.null? || !success
67
+
68
+ ::GDAL::Dataset.open(dst_dataset_ptr, "w", &block)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GDAL
4
+ module Utils
5
+ class VectorTranslate
6
+ # Ruby wrapper for GDALVectorTranslateOptions C API (options for ogr2ogr utility).
7
+ #
8
+ # @see GDAL::Utils::VectorTranslate
9
+ # @see https://gdal.org/programs/ogr2ogr.html ogr2ogr utility documentation.
10
+ class Options
11
+ # @private
12
+ class AutoPointer < ::FFI::AutoPointer
13
+ # @param pointer [FFI::Pointer]
14
+ def self.release(pointer)
15
+ return unless pointer && !pointer.null?
16
+
17
+ ::FFI::GDAL::Utils.GDALVectorTranslateOptionsFree(pointer)
18
+ end
19
+ end
20
+
21
+ # @return [AutoPointer] C pointer to the GDALVectorTranslateOptions.
22
+ attr_reader :c_pointer
23
+
24
+ # @return [Array<String>] The options.
25
+ attr_reader :options
26
+
27
+ # Create a new instance.
28
+ #
29
+ # @see https://gdal.org/programs/ogr2ogr.html
30
+ # List of available options could be found in ogr2ogr utility documentation.
31
+ #
32
+ # @example Create a new instance.
33
+ # options = GDAL::Utils::VectorTranslate::Options.new(options: ["-overwrite", "-nlt", "MULTIPOLYGON"])
34
+ #
35
+ # @param options [Array<String>] The options list.
36
+ def initialize(options: [])
37
+ @options = options
38
+ @string_list = ::GDAL::Utils::Helpers::StringList.new(strings: options)
39
+ @c_pointer = AutoPointer.new(options_pointer)
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :string_list
45
+
46
+ def options_pointer
47
+ ::FFI::GDAL::Utils.GDALVectorTranslateOptionsNew(string_list.c_pointer, nil)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "vector_translate/options"
4
+
5
+ module GDAL
6
+ module Utils
7
+ # Wrapper for ogr2ogr using GDALVectorTranslate C API.
8
+ #
9
+ # @see https://gdal.org/programs/ogr2ogr.html ogr2ogr utility documentation.
10
+ # @see https://gdal.org/api/gdal_utils.html#_CPPv419GDALVectorTranslatePKc12GDALDatasetHiP12GDALDatasetHPK26GDALVectorTranslateOptionsPi
11
+ # GDALVectorTranslate C API.
12
+ class VectorTranslate
13
+ # Perform the ogr2ogr (GDALVectorTranslate) operation.
14
+ #
15
+ # @example Translate a vector dataset (for dst_dataset_path).
16
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
17
+ # dataset = GDAL::Utils::VectorTranslate.perform(
18
+ # dst_dataset_path: "destination.geojson",
19
+ # src_datasets: [src_dataset]
20
+ # )
21
+ #
22
+ # # Do something with the dataset.
23
+ # puts dataset.layer(0).name
24
+ #
25
+ # # You must close the dataset when you are done with it.
26
+ # dataset.close
27
+ # src_dataset.close
28
+ #
29
+ # @example Translate a vector dataset with options (for dst_dataset_path).
30
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
31
+ # dataset = GDAL::Utils::VectorTranslate.perform(
32
+ # dst_dataset_path: "destination.geojson",
33
+ # src_datasets: [src_dataset],
34
+ # options: GDAL::Utils::VectorTranslate::Options.new(options: ["-nlt", "MULTIPOLYGON"])
35
+ # )
36
+ #
37
+ # # Do something with the dataset.
38
+ # puts dataset.layer(0).name
39
+ #
40
+ # # You must close the dataset when you are done with it.
41
+ # dataset.close
42
+ # src_dataset.close
43
+ #
44
+ # @example Translate a vector dataset using block syntax (for dst_dataset_path).
45
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
46
+ # GDAL::Utils::VectorTranslate.perform(
47
+ # dst_dataset_path: "destination.geojson",
48
+ # src_datasets: [src_dataset]
49
+ # ) do |dataset|
50
+ # # Do something with the dataset.
51
+ # puts dataset.layer(0).name
52
+ #
53
+ # # Dataset will be closed automatically.
54
+ # end
55
+ # src_dataset.close
56
+ #
57
+ # @example Translate a vector dataset (for dst_dataset).
58
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
59
+ # dst_dataset = OGR::DataSource.open("destination.geojson", "w")
60
+ #
61
+ # GDAL::Utils::VectorTranslate.perform(dst_dataset: dst_dataset, src_datasets: [src_dataset])
62
+ #
63
+ # # You must close the dataset when you are done with it.
64
+ # dst_dataset.close
65
+ # src_dataset.close
66
+ #
67
+ # @example Translate a vector dataset with options (for dst_dataset).
68
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
69
+ # dst_dataset = OGR::DataSource.open("destination.geojson", "w")
70
+ #
71
+ # GDAL::Utils::VectorTranslate.perform(
72
+ # dst_dataset: dst_dataset,
73
+ # src_datasets: [src_dataset],
74
+ # options: GDAL::Utils::VectorTranslate::Options.new(options: ["-nlt", "MULTIPOLYGON"])
75
+ # )
76
+ #
77
+ # # You must close the dataset when you are done with it.
78
+ # dst_dataset.close
79
+ # src_dataset.close
80
+ #
81
+ # @param dst_dataset_path [String] The path to the destination dataset.
82
+ # @param dst_dataset [OGR::DataSource] The destination dataset.
83
+ # @param src_datasets [Array<OGR::DataSource>] The source datasets.
84
+ # @param options [GDAL::Utils::VectorTranslate::Options] Options.
85
+ # @yield [OGR::DataSource] The destination dataset.
86
+ # @return [OGR::DataSource] The destination dataset (only if block is not specified; dataset must be closed).
87
+ def self.perform(dst_dataset: nil, dst_dataset_path: nil, src_datasets: [], options: Options.new, &block)
88
+ if dst_dataset
89
+ for_dataset(dst_dataset: dst_dataset, src_datasets: src_datasets, options: options)
90
+ else
91
+ for_dataset_path(dst_dataset_path: dst_dataset_path, src_datasets: src_datasets, options: options, &block)
92
+ end
93
+ end
94
+
95
+ def self.for_dataset(dst_dataset:, src_datasets: [], options: Options.new)
96
+ result_dataset_ptr(dst_dataset: dst_dataset, src_datasets: src_datasets, options: options)
97
+
98
+ # Return the input dataset as the output dataset (dataset is modified in place).
99
+ dst_dataset
100
+ end
101
+ private_class_method :for_dataset
102
+
103
+ def self.for_dataset_path(dst_dataset_path:, src_datasets: [], options: Options.new, &block)
104
+ dst_dataset_ptr = result_dataset_ptr(
105
+ dst_dataset_path: dst_dataset_path, src_datasets: src_datasets, options: options
106
+ )
107
+
108
+ ::OGR::DataSource.open(dst_dataset_ptr, "w", &block)
109
+ end
110
+ private_class_method :for_dataset_path
111
+
112
+ def self.result_dataset_ptr(dst_dataset_path: nil, dst_dataset: nil, src_datasets: [], options: Options.new)
113
+ src_dataset_list = ::GDAL::Utils::Helpers::DatasetList.new(datasets: src_datasets)
114
+ result_code_ptr = ::FFI::MemoryPointer.new(:int)
115
+ dst_dataset_ptr = ::FFI::GDAL::Utils.GDALVectorTranslate(
116
+ dst_dataset_path,
117
+ dst_dataset&.c_pointer,
118
+ src_dataset_list.count,
119
+ src_dataset_list.c_pointer,
120
+ options.c_pointer,
121
+ result_code_ptr
122
+ )
123
+ success = result_code_ptr.read_int.zero?
124
+
125
+ raise ::GDAL::Error, "GDALVectorTranslate failed." if dst_dataset_ptr.null? || !success
126
+
127
+ dst_dataset_ptr
128
+ end
129
+ private_class_method :result_dataset_ptr
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GDAL
4
+ module Utils
5
+ class Warp
6
+ # Ruby wrapper for GDALWarpAppOptions C API (options for ogr2ogr utility).
7
+ #
8
+ # @see GDAL::Utils::Warp
9
+ # @see https://gdal.org/programs/gdalwarp.html gdalwarp utility documentation.
10
+ class Options
11
+ # @private
12
+ class AutoPointer < ::FFI::AutoPointer
13
+ # @param pointer [FFI::Pointer]
14
+ def self.release(pointer)
15
+ return unless pointer && !pointer.null?
16
+
17
+ ::FFI::GDAL::Utils.GDALWarpAppOptionsFree(pointer)
18
+ end
19
+ end
20
+
21
+ # @return [AutoPointer] C pointer to the GDALWarpAppOptions.
22
+ attr_reader :c_pointer
23
+
24
+ # @return [Array<String>] The options.
25
+ attr_reader :options
26
+
27
+ # Create a new instance.
28
+ #
29
+ # @see https://gdal.org/programs/gdalwarp.html
30
+ # List of available options could be found in gdalwarp utility documentation.
31
+ #
32
+ # @example Create a new instance.
33
+ # options = GDAL::Utils::Warp::Options.new(options: ["-multi", "-wo", "CUTLINE_ALL_TOUCHED=TRUE"])
34
+ #
35
+ # @param options [Array<String>] The options list.
36
+ def initialize(options: [])
37
+ @options = options
38
+ @string_list = ::GDAL::Utils::Helpers::StringList.new(strings: options)
39
+ @c_pointer = AutoPointer.new(options_pointer)
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :string_list
45
+
46
+ def options_pointer
47
+ ::FFI::GDAL::Utils.GDALWarpAppOptionsNew(string_list.c_pointer, nil)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "warp/options"
4
+
5
+ module GDAL
6
+ module Utils
7
+ # Wrapper for gdalwarp using GDALWarp C API.
8
+ #
9
+ # @see https://gdal.org/programs/gdalwarp.html gdalwarp utility documentation.
10
+ # @see https://gdal.org/api/gdal_utils.html#_CPPv48GDALWarpPKc12GDALDatasetHiP12GDALDatasetHPK18GDALWarpAppOptionsPi
11
+ # GDALWarp C API.
12
+ class Warp
13
+ # Perform the gdalwarp (GDALWarp) operation.
14
+ #
15
+ # @example Warp a dataset (for dst_dataset_path).
16
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
17
+ # options = GDAL::Utils::Warp::Options.new(options: ["-t_srs", "EPSG:3857"])
18
+ #
19
+ # dataset = GDAL::Utils::Warp.perform(
20
+ # dst_dataset_path: "destination.tif",
21
+ # src_datasets: [src_dataset],
22
+ # options: options
23
+ # )
24
+ #
25
+ # # Do something with the dataset.
26
+ # puts dataset.raster_x_size
27
+ #
28
+ # # You must close the dataset when you are done with it.
29
+ # dataset.close
30
+ # src_dataset.close
31
+ #
32
+ # @example Warp a dataset (for dst_dataset_path) using block syntax.
33
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
34
+ # options = GDAL::Utils::Warp::Options.new(options: ["-t_srs", "EPSG:3857"])
35
+ #
36
+ # GDAL::Utils::Warp.perform(
37
+ # dst_dataset_path: "destination.tif",
38
+ # src_datasets: src_dataset,
39
+ # options: options
40
+ # ) do |dataset|
41
+ # # Do something with the dataset.
42
+ # puts dataset.raster_x_size
43
+ #
44
+ # # Dataset will be closed automatically.
45
+ # end
46
+ # src_dataset.close
47
+ #
48
+ # @example Warp a dataset (for dst_dataset).
49
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
50
+ # dst_dataset = GDAL::Dataset.open("destination.tif", "w") # Dataset with other projection.
51
+ #
52
+ # GDAL::Utils::Warp.perform(dst_dataset: dst_dataset, src_datasets: [src_dataset])
53
+ #
54
+ # # You must close the dataset when you are done with it.
55
+ # dst_dataset.close
56
+ # src_dataset.close
57
+ #
58
+ # @param dst_dataset_path [String] The path to the destination dataset.
59
+ # @param dst_dataset [GDAL::Dataset] The destination dataset.
60
+ # @param src_datasets [Array<GDAL::Dataset>] The source datasets.
61
+ # @param options [GDAL::Utils::Warp::Options] Options.
62
+ # @yield [GDAL::Dataset] The destination dataset.
63
+ # @return [GDAL::Dataset] The destination dataset (only if block is not specified; dataset must be closed).
64
+ def self.perform(dst_dataset: nil, dst_dataset_path: nil, src_datasets: [], options: Options.new, &block)
65
+ if dst_dataset
66
+ for_dataset(dst_dataset: dst_dataset, src_datasets: src_datasets, options: options)
67
+ else
68
+ for_dataset_path(dst_dataset_path: dst_dataset_path, src_datasets: src_datasets, options: options, &block)
69
+ end
70
+ end
71
+
72
+ # @param dst_dataset [GDAL::Dataset] The destination dataset.
73
+ # @param src_datasets [Array<GDAL::Dataset>] The source datasets.
74
+ # @param options [GDAL::Utils::Warp::Options] Options.
75
+ # @return [GDAL::Dataset] The destination dataset (it's the same object as dst_dataset).
76
+ def self.for_dataset(dst_dataset:, src_datasets: [], options: Options.new)
77
+ result_dataset_ptr(dst_dataset: dst_dataset, src_datasets: src_datasets, options: options)
78
+
79
+ # Return the input dataset as the output dataset (dataset is modified in place).
80
+ dst_dataset
81
+ end
82
+ private_class_method :for_dataset
83
+
84
+ # @param dst_dataset_path [String] The path to the destination dataset.
85
+ # @param src_datasets [Array<GDAL::Dataset>] The source datasets.
86
+ # @param options [GDAL::Utils::Warp::Options] Options.
87
+ # @yield [GDAL::Dataset] The destination dataset.
88
+ # @return [GDAL::Dataset] The destination dataset (only if block is not specified; dataset must be closed).
89
+ def self.for_dataset_path(dst_dataset_path:, src_datasets: [], options: Options.new, &block)
90
+ dst_dataset_ptr = result_dataset_ptr(
91
+ dst_dataset_path: dst_dataset_path, src_datasets: src_datasets, options: options
92
+ )
93
+
94
+ ::GDAL::Dataset.open(dst_dataset_ptr, "w", &block)
95
+ end
96
+ private_class_method :for_dataset_path
97
+
98
+ def self.result_dataset_ptr(dst_dataset_path: nil, dst_dataset: nil, src_datasets: [], options: Options.new)
99
+ src_dataset_list = ::GDAL::Utils::Helpers::DatasetList.new(datasets: src_datasets)
100
+ result_code_ptr = ::FFI::MemoryPointer.new(:int)
101
+ dst_dataset_ptr = ::FFI::GDAL::Utils.GDALWarp(
102
+ dst_dataset_path,
103
+ dst_dataset&.c_pointer,
104
+ src_dataset_list.count,
105
+ src_dataset_list.c_pointer,
106
+ options.c_pointer,
107
+ result_code_ptr
108
+ )
109
+ success = result_code_ptr.read_int.zero?
110
+
111
+ raise ::GDAL::Error, "GDALWarp failed." if dst_dataset_ptr.null? || !success
112
+
113
+ dst_dataset_ptr
114
+ end
115
+ private_class_method :result_dataset_ptr
116
+ end
117
+ end
118
+ end
data/lib/gdal/utils.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GDAL
4
+ # Wrappers for the GDAL utilities.
5
+ #
6
+ # @see https://gdal.org/programs/index.html GDAL Utils documentation (gdalwarp, gdal_translate, ...).
7
+ # @see https://gdal.org/api/gdal_utils.html GDAL Utils C API.
8
+ module Utils
9
+ # Internal helpers
10
+ autoload :Helpers, File.expand_path("utils/helpers", __dir__)
11
+
12
+ # GDAL Utils
13
+ autoload :DEM, File.expand_path("utils/dem", __dir__)
14
+ autoload :Grid, File.expand_path("utils/grid", __dir__)
15
+ autoload :Nearblack, File.expand_path("utils/nearblack", __dir__)
16
+ autoload :Rasterize, File.expand_path("utils/rasterize", __dir__)
17
+ autoload :Info, File.expand_path("utils/info", __dir__)
18
+ autoload :Translate, File.expand_path("utils/translate", __dir__)
19
+ autoload :VectorTranslate, File.expand_path("utils/vector_translate", __dir__)
20
+ autoload :Warp, File.expand_path("utils/warp", __dir__)
21
+ end
22
+ end
@@ -12,7 +12,7 @@ module GDAL
12
12
  @destination_dataset = nil
13
13
 
14
14
  options.each_key do |k|
15
- assign_meth = "#{k}=".to_sym
15
+ assign_meth = :"#{k}="
16
16
 
17
17
  begin
18
18
  if respond_to?(assign_meth)
@@ -175,8 +175,17 @@ module GDAL
175
175
  def source_per_band_validity_mask_function=(band_procs)
176
176
  mask_func = FFI::GDAL::Warper::MaskFunc
177
177
 
178
+ mask_func_return_type =
179
+ if mask_func.respond_to?(:return_type)
180
+ # `.return_type` is for FFI 1.16.0+;
181
+ mask_func.return_type
182
+ else
183
+ # `.result_type` is for older FFI versions.
184
+ mask_func.result_type
185
+ end
186
+
178
187
  funcs = band_procs.map do |band_proc|
179
- FFI::Function.new(mask_func.result_type, mask_func.param_types, band_proc, blocking: true)
188
+ FFI::Function.new(mask_func_return_type, mask_func.param_types, band_proc, blocking: true)
180
189
  end
181
190
 
182
191
  pointer = FFI::MemoryPointer.new(:pointer, band_procs.length)
data/lib/gdal.rb CHANGED
@@ -37,6 +37,7 @@ module GDAL
37
37
  autoload :Options, gdal_require("gdal/options")
38
38
  autoload :RasterAttributeTable, gdal_require("gdal/raster_attribute_table")
39
39
  autoload :RasterBand, gdal_require("gdal/raster_band")
40
+ autoload :Utils, gdal_require("gdal/utils")
40
41
  end
41
42
 
42
43
  require_relative "gdal/exceptions"
@@ -130,7 +130,7 @@ module OGR
130
130
  # least at this point), it needs to be as fast as possible.
131
131
  each_feature_pointer do |feature_ptr| # rubocop:todo Metrics/BlockLength
132
132
  field_values = field_indices.map.with_index do |j, attribute_index|
133
- FFI::OGR::API.send("OGR_F_GetFieldAs#{with_attributes.values[attribute_index].capitalize}", feature_ptr, j)
133
+ FFI::OGR::API.send(:"OGR_F_GetFieldAs#{with_attributes.values[attribute_index].capitalize}", feature_ptr, j)
134
134
  end
135
135
 
136
136
  geom_ptr = FFI::OGR::API.OGR_F_GetGeometryRef(feature_ptr)
@@ -11,8 +11,8 @@ module OGR
11
11
  # @raise [NameError] If the +unit_label+ isn't of a known type.
12
12
  def angular_units=(unit_label)
13
13
  unit_name = unit_label.to_s.upcase
14
- unit_label = self.class.const_get("#{unit_name}_LABEL".to_sym)
15
- unit_value = self.class.const_get("RADIAN_TO_#{unit_name}".to_sym)
14
+ unit_label = self.class.const_get(:"#{unit_name}_LABEL")
15
+ unit_value = self.class.const_get(:"RADIAN_TO_#{unit_name}")
16
16
 
17
17
  set_angular_units(unit_label, unit_value)
18
18
  rescue NameError
@@ -24,8 +24,8 @@ module OGR
24
24
  # @raise [NameError] If the +unit_label+ isn't of a known type.
25
25
  def linear_units=(unit_label)
26
26
  unit_name = unit_label.to_s.upcase
27
- unit_label = self.class.const_get("#{unit_name}_LABEL".to_sym)
28
- unit_value = self.class.const_get("METER_TO_#{unit_name}".to_sym)
27
+ unit_label = self.class.const_get(:"#{unit_name}_LABEL")
28
+ unit_value = self.class.const_get(:"METER_TO_#{unit_name}")
29
29
 
30
30
  set_linear_units(unit_label, unit_value)
31
31
  rescue NameError