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
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative '../gdal'
|
2
|
+
|
1
3
|
module GDAL
|
2
4
|
# Takes a list of Ranges of color values and remaps them. Note that these
|
3
5
|
# values are directly written to the raster band, overwriting all existing
|
@@ -28,7 +30,7 @@ module GDAL
|
|
28
30
|
# @param range [Range] The range of values to map to a new value.
|
29
31
|
# @param map_to_value [Number]
|
30
32
|
def add_range(range, map_to_value)
|
31
|
-
|
33
|
+
raise 'range must be a Ruby Range' unless range.is_a? Range
|
32
34
|
|
33
35
|
@ranges << { range: range, map_to: map_to_value }
|
34
36
|
end
|
@@ -49,14 +51,16 @@ module GDAL
|
|
49
51
|
def equal_count_ranges(range_count)
|
50
52
|
sorted_pixels = @raster_band.to_na.sort
|
51
53
|
sorted_and_masked_pixels = sorted_pixels[sorted_pixels.ne(@raster_band.no_data_value[:value])]
|
54
|
+
return [] if sorted_and_masked_pixels.empty?
|
55
|
+
|
52
56
|
range_size = (sorted_and_masked_pixels.size / range_count).to_i
|
53
57
|
|
54
|
-
log "
|
58
|
+
log "Masked pixel count/total pixel count: #{sorted_and_masked_pixels.size}/#{sorted_pixels.size}"
|
55
59
|
log "Min pixel value: #{sorted_and_masked_pixels.min}"
|
56
60
|
log "Max pixel value: #{sorted_and_masked_pixels.max}"
|
57
61
|
log "Range size: #{range_size}"
|
58
62
|
|
59
|
-
break_values = range_count
|
63
|
+
break_values = Array.new(range_count) { |i| sorted_and_masked_pixels[range_size * i] }.uniq
|
60
64
|
log "Break values: #{break_values}"
|
61
65
|
return if break_values.uniq.size != range_count
|
62
66
|
|
@@ -82,23 +86,20 @@ module GDAL
|
|
82
86
|
# values, so if you don't want to overwrite the Dataset you're working with,
|
83
87
|
# you should copy it first.
|
84
88
|
def classify!
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
else
|
97
|
-
log "pixel #{pixel_number} (value: #{narray[pixel_number]}) not in any given range"
|
98
|
-
end
|
89
|
+
nodata_value = @raster_band.no_data_value[:value]
|
90
|
+
band_pixels = @raster_band.to_na
|
91
|
+
new_band_pixels = GDAL._narray_from_data_type(@raster_band.data_type, @raster_band.x_size, @raster_band.y_size)
|
92
|
+
new_band_pixels[band_pixels.eq(nodata_value)] = nodata_value
|
93
|
+
|
94
|
+
@ranges.each do |r|
|
95
|
+
new_band_pixels[
|
96
|
+
band_pixels.ne(nodata_value).
|
97
|
+
and(band_pixels.le(r[:range].max)).
|
98
|
+
and(band_pixels.ge(r[:range].min))
|
99
|
+
] = r[:map_to]
|
99
100
|
end
|
100
101
|
|
101
|
-
@raster_band.
|
102
|
+
@raster_band.write_xy_narray(new_band_pixels)
|
102
103
|
end
|
103
104
|
|
104
105
|
private
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require_relative '../../ogr'
|
2
|
+
|
3
|
+
module GDAL
|
4
|
+
module RasterBandMixins
|
5
|
+
# RasterBand methods for doing warp-like things, but not using GDAL's Warp
|
6
|
+
# API.
|
7
|
+
module AlgorithmExtensions
|
8
|
+
# A method that doesn't use GDAL's Warp API for erasing pixels (setting to
|
9
|
+
# NODATA) in the method-owning RasterBand. It simply iterates over all of
|
10
|
+
# the valued pixels (ones that aren't NODATA pixels) and yields them to a
|
11
|
+
# block. The return value of the block tells the method whether to keep
|
12
|
+
# the pixel or not: a truthy return value keeps the pixel; a false value
|
13
|
+
# sets the pixel value to the band's NODATA value. If there's no NODATA
|
14
|
+
# value set, it will raise an exception.
|
15
|
+
#
|
16
|
+
# A typical clip operation would be from checking to see if the
|
17
|
+
# RasterBand's pixel is within some Polygon. Doing so would look like:
|
18
|
+
#
|
19
|
+
# @example Clipping by polygon
|
20
|
+
#
|
21
|
+
# contrived_wkt = 'POLYGON ((0 0, 0 20, 20 20, 20 0, 0 0))'
|
22
|
+
# polygon = OGR::Geometry.create_from_wkt(contrived_wkt)
|
23
|
+
#
|
24
|
+
# # Note the 'w' to open for writing!
|
25
|
+
# dataset = GDAL::Dataset.open('my.tif', 'w')
|
26
|
+
# geo_transform = dataset.geo_transform
|
27
|
+
# test_point = OGR::Point.new
|
28
|
+
#
|
29
|
+
# dataset.raster_band(1).simple_erase! do |pixel_num, line_num|
|
30
|
+
# # Project the pixel using the dataset's GeoTransform
|
31
|
+
# projected_point_values = geo_transform.apply_geo_transform(pixel_num, line_num)
|
32
|
+
# test_point.set_point(projected_point_values[:x_geo], projected_point_values[:y_geo])
|
33
|
+
#
|
34
|
+
# test_point.within? polygon
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# # Make sure to close the dataset so the changes get flushed to disk.
|
38
|
+
# dataset.close
|
39
|
+
#
|
40
|
+
# You could, however use any other criteria in the block for erasing
|
41
|
+
# points away. The method also the pixel value in case you can use it for
|
42
|
+
# erasing. Perhaps, for example, you want to remove all pixels in the
|
43
|
+
# upper left quadrant of your raster that have a value less than 0. That
|
44
|
+
# would look like:
|
45
|
+
#
|
46
|
+
# @example Erasing using pixel location and values
|
47
|
+
#
|
48
|
+
# dataset = GDAL::Dataset.open('my.tif', 'w')
|
49
|
+
# raster_band = dataset.raster_band(1)
|
50
|
+
#
|
51
|
+
# raster_band.simple_erase! do |x, y, value|
|
52
|
+
# if x < (raster_band.x_size / 2) && y < (raster_band.y_size / 2) && value < 0
|
53
|
+
# false
|
54
|
+
# else
|
55
|
+
# true
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# @return [Fixnum] The number of pixels that were erased.
|
60
|
+
def simple_erase!
|
61
|
+
erase_value = no_data_value[:value]
|
62
|
+
write_buffer = GDAL._buffer_from_data_type(data_type, x_size)
|
63
|
+
erased_pixel_count = 0
|
64
|
+
|
65
|
+
unless erase_value
|
66
|
+
raise GDAL::NoRasterEraseValue,
|
67
|
+
'Cannot erase values, RasterBand does not have a NODATA value set'
|
68
|
+
end
|
69
|
+
|
70
|
+
y_size.times do |line_num|
|
71
|
+
pixel_row = raster_io('r', x_size: x_size, y_size: 1, x_offset: 0, y_offset: line_num)
|
72
|
+
pixel_values = GDAL._read_pointer(pixel_row, data_type, x_size)
|
73
|
+
row_changed = false
|
74
|
+
pixel_num = 0
|
75
|
+
|
76
|
+
while pixel_num < pixel_values.length
|
77
|
+
pixel_value = pixel_values[pixel_num]
|
78
|
+
next if pixel_value == no_data_value[:value]
|
79
|
+
|
80
|
+
keep_in_raster = yield(pixel_num, line_num, pixel_value)
|
81
|
+
next if keep_in_raster
|
82
|
+
|
83
|
+
erased_pixel_count += 1
|
84
|
+
pixel_values[pixel_num] = erase_value
|
85
|
+
row_changed = true
|
86
|
+
pixel_num += 1
|
87
|
+
end
|
88
|
+
|
89
|
+
rewrite_pixel_row(write_buffer, pixel_values, line_num) if row_changed
|
90
|
+
end
|
91
|
+
|
92
|
+
erased_pixel_count
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# @param write_buffer [FFI::Buffer]
|
98
|
+
# @param pixel_values [Array<Number>]
|
99
|
+
# @param line_number [Fixnum]
|
100
|
+
def rewrite_pixel_row(write_buffer, pixel_values, line_number)
|
101
|
+
GDAL._write_pointer(write_buffer, data_type, pixel_values)
|
102
|
+
raster_io('w', write_buffer, x_size: x_size, y_size: 1, y_offset: line_number)
|
103
|
+
write_buffer.clear
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require_relative '../../ffi/gdal/alg'
|
2
|
-
|
3
1
|
module GDAL
|
4
2
|
module RasterBandMixins
|
5
3
|
module AlgorithmMethods
|
@@ -18,22 +16,25 @@ module GDAL
|
|
18
16
|
# @param green_band [GDAL::RasterBand, FFI::Pointer]
|
19
17
|
# @param blue_band [GDAL::RasterBand, FFI::Pointer]
|
20
18
|
# @param colors [Fixnum] Number of colors to return; 2-256.
|
21
|
-
# @param color_interpretation [FFI::GDAL::PaletteInterp] The type
|
19
|
+
# @param color_interpretation [FFI::GDAL::GDAL::PaletteInterp] The type
|
22
20
|
# of ColorTable to return.
|
21
|
+
# @param progress_function [Proc, FFI:GDAL::GDAL.ProgressFunc]
|
22
|
+
# @param progress_arg [FFI::Pointer] Usually used when when using a
|
23
|
+
# +FFI::CPL::Progress.GDALCreateScaledProgress+.
|
23
24
|
# @return [GDAL::ColorTable]
|
24
25
|
def compute_median_cut_pct(red_band, green_band, blue_band,
|
25
|
-
colors, color_interpretation,
|
26
|
+
colors, color_interpretation, progress_function: nil, progress_arg: nil)
|
26
27
|
color_table = GDAL::ColorTable.new(color_interpretation)
|
27
28
|
|
28
29
|
FFI::GDAL::Alg.GDALComputeMedianCutPCT(
|
29
30
|
red_band,
|
30
31
|
green_band,
|
31
32
|
blue_band,
|
32
|
-
nil,
|
33
|
+
nil, # This isn't yet supported in GDAL.
|
33
34
|
colors,
|
34
35
|
color_table.c_pointer,
|
35
|
-
|
36
|
-
|
36
|
+
progress_function,
|
37
|
+
progress_arg)
|
37
38
|
|
38
39
|
color_table
|
39
40
|
end
|
@@ -54,10 +55,13 @@ module GDAL
|
|
54
55
|
# @param blue_band [GDAL::RasterBand, FFI::Pointer]
|
55
56
|
# @param output_band [GDAL::RasterBand, FFI::Pointer]
|
56
57
|
# @param color_table [GDAL::ColorTable, FFI::Pointer]
|
58
|
+
# @param progress_function [Proc, FFI:GDAL::GDAL.ProgressFunc]
|
59
|
+
# @param progress_arg [FFI::Pointer] Usually used when when using a
|
60
|
+
# +FFI::CPL::Progress.GDALCreateScaledProgress+.
|
57
61
|
# @return [GDAL::RasterBand] +output_band+ with the dithering algorithm
|
58
62
|
# applied.
|
59
63
|
def dither_rgb_to_pct(red_band, green_band, blue_band, output_band,
|
60
|
-
color_table,
|
64
|
+
color_table, progress_function: nil, progress_arg: nil)
|
61
65
|
red_ptr = GDAL._pointer(GDAL::RasterBand, red_band)
|
62
66
|
green_ptr = GDAL._pointer(GDAL::RasterBand, green_band)
|
63
67
|
blue_ptr = GDAL._pointer(GDAL::RasterBand, blue_band)
|
@@ -70,8 +74,8 @@ module GDAL
|
|
70
74
|
blue_ptr,
|
71
75
|
output_ptr,
|
72
76
|
color_table_ptr,
|
73
|
-
|
74
|
-
|
77
|
+
progress_function,
|
78
|
+
progress_arg)
|
75
79
|
|
76
80
|
output_band
|
77
81
|
end
|
@@ -105,6 +109,9 @@ module GDAL
|
|
105
109
|
# values.
|
106
110
|
#
|
107
111
|
# @param proximity_band [GDAL::RasterBand, FFI::Pointer]
|
112
|
+
# @param progress_function [Proc, FFI:GDAL::GDAL.ProgressFunc]
|
113
|
+
# @param progress_arg [FFI::Pointer] Usually used when when using a
|
114
|
+
# +FFI::CPL::Progress.GDALCreateScaledProgress+.
|
108
115
|
# @param options [Hash]
|
109
116
|
# @option options [String] values A list of target pixel values to measure
|
110
117
|
# the distance from. If this isn't provided, proximity will be computed
|
@@ -118,7 +125,7 @@ module GDAL
|
|
118
125
|
# @option options [Fixnum] fixed_buf_val If set, all pixels within the
|
119
126
|
# +maxdist+ threshold are set to this fixed value instead of to a
|
120
127
|
# proximity distance.
|
121
|
-
def compute_proximity!(proximity_band, **options
|
128
|
+
def compute_proximity!(proximity_band, progress_function: nil, progress_arg: nil, **options)
|
122
129
|
proximity_band_ptr = GDAL._pointer(GDAL::RasterBand, proximity_band)
|
123
130
|
options_ptr = GDAL::Options.pointer(options)
|
124
131
|
|
@@ -126,8 +133,8 @@ module GDAL
|
|
126
133
|
@c_pointer,
|
127
134
|
proximity_band_ptr,
|
128
135
|
options_ptr,
|
129
|
-
|
130
|
-
|
136
|
+
progress_function,
|
137
|
+
progress_arg)
|
131
138
|
end
|
132
139
|
|
133
140
|
# Fill selected raster regions by interpolation from the edges. It
|
@@ -153,20 +160,24 @@ module GDAL
|
|
153
160
|
# directions to find values to interpolate from.
|
154
161
|
# @param smoothing_iterations [Fixnum] The number of 3x3 smoothing filter
|
155
162
|
# passes to run. Can be 0.
|
163
|
+
# @param progress_function [Proc, FFI:GDAL::GDAL.ProgressFunc]
|
164
|
+
# @param progress_arg [FFI::Pointer] Usually used when when using a
|
165
|
+
# +FFI::CPL::Progress.GDALCreateScaledProgress+.
|
156
166
|
# @param options [Hash]
|
157
167
|
# TODO: document what valid options are.
|
158
|
-
def fill_nodata!(mask_band, max_search_distance, smoothing_iterations,
|
168
|
+
def fill_nodata!(mask_band, max_search_distance, smoothing_iterations, progress_function: nil, progress_arg: nil,
|
169
|
+
**options)
|
159
170
|
mask_band_ptr = GDAL._pointer(GDAL::RasterBand, mask_band)
|
160
171
|
options_ptr = GDAL::Options.pointer(options)
|
161
172
|
|
162
|
-
!!FFI::GDAL.GDALFillNodata(@c_pointer,
|
173
|
+
!!FFI::GDAL::Alg.GDALFillNodata(@c_pointer,
|
163
174
|
mask_band_ptr,
|
164
175
|
max_search_distance,
|
165
|
-
0,
|
176
|
+
0, # deprecated option in GDAL
|
166
177
|
smoothing_iterations,
|
167
178
|
options_ptr,
|
168
|
-
|
169
|
-
|
179
|
+
progress_function,
|
180
|
+
progress_arg)
|
170
181
|
end
|
171
182
|
|
172
183
|
# Creates vector polygons for all connected regions of pixels in the raster
|
@@ -196,16 +207,23 @@ module GDAL
|
|
196
207
|
# suitable for collection as polygons.
|
197
208
|
# @param pixel_value_field [Fixnum] Index of the feature attribute into
|
198
209
|
# which the pixel value of the polygon should be written.
|
210
|
+
# @param use_integer_function [Boolean] Indicates using GDAL's
|
211
|
+
# GDALPolygonize() instead of GDALFPolygonize(); the former uses a
|
212
|
+
# 32-bit integer buffer for reading pixel band values, the latter uses a
|
213
|
+
# 32-bit float buffer. The integer based function is faster but less
|
214
|
+
# precise.
|
199
215
|
# @param options [Hash]
|
200
216
|
# @option options [Fixnum] '8CONNECTED' (4) Set to 8 to use 8
|
201
217
|
# connectedness.
|
202
|
-
# @param
|
218
|
+
# @param progress_function [Proc, FFI:GDAL::GDAL.ProgressFunc]
|
219
|
+
# @param progress_arg [FFI::Pointer] Usually used when when using a
|
220
|
+
# +FFI::CPL::Progress.GDALCreateScaledProgress+.
|
203
221
|
# @return [OGR::Layer]
|
204
|
-
def polygonize(layer, mask_band: nil, pixel_value_field: -1, use_integer_function: false,
|
205
|
-
**options
|
222
|
+
def polygonize(layer, mask_band: nil, pixel_value_field: -1, use_integer_function: false, progress_function: nil,
|
223
|
+
progress_arg: nil, **options)
|
206
224
|
mask_band_ptr = GDAL._pointer(GDAL::RasterBand, mask_band, false)
|
207
225
|
layer_ptr = GDAL._pointer(OGR::Layer, layer)
|
208
|
-
|
226
|
+
raise OGR::InvalidLayer, "Invalid layer: #{layer.inspect}" if layer_ptr.null?
|
209
227
|
log "Pixel value field: #{pixel_value_field}"
|
210
228
|
|
211
229
|
options_ptr = GDAL::Options.pointer(options)
|
@@ -219,8 +237,8 @@ module GDAL
|
|
219
237
|
layer_ptr, # hOutLayer
|
220
238
|
pixel_value_field, # iPixValField
|
221
239
|
options_ptr, # papszOptions
|
222
|
-
|
223
|
-
|
240
|
+
progress_function, # pfnProgress
|
241
|
+
progress_arg # pProgressArg
|
224
242
|
)
|
225
243
|
|
226
244
|
layer_ptr.instance_of?(OGR::Layer) ? layer_ptr : OGR::Layer.new(layer_ptr)
|
@@ -242,10 +260,16 @@ module GDAL
|
|
242
260
|
# @param mask_band [GDAL::RasterBand] [description] All pixels in this
|
243
261
|
# band with a value other than 0 will be considered suitable for
|
244
262
|
# inclusion in polygons.
|
263
|
+
# @param progress_function [Proc, FFI:GDAL::GDAL.ProgressFunc]
|
264
|
+
# @param progress_arg [FFI::Pointer] Usually used when when using a
|
265
|
+
# +FFI::CPL::Progress.GDALCreateScaledProgress+.
|
245
266
|
# @param options [Hash] None supported in GDAL as of this writing.
|
246
|
-
def sieve_filter!(size_threshold, connectedness, mask_band: nil,
|
247
|
-
|
248
|
-
|
267
|
+
def sieve_filter!(size_threshold, connectedness, mask_band: nil, progress_function: nil, progress_arg: nil,
|
268
|
+
**options)
|
269
|
+
_sieve_filter(size_threshold, connectedness, self, mask_band: mask_band,
|
270
|
+
progress_function: progress_function,
|
271
|
+
progress_arg: progress_arg,
|
272
|
+
**options)
|
249
273
|
end
|
250
274
|
|
251
275
|
# The same as +sieve_filter!+, but returns a new GDAL::RasterBand as the
|
@@ -253,15 +277,12 @@ module GDAL
|
|
253
277
|
#
|
254
278
|
# @see +sieve_filter!
|
255
279
|
# @param destination_band [GDAL::RasterBand]
|
256
|
-
def sieve_filter(size_threshold, connectedness, destination_band,
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
_sieve_filter(size_threshold, connectedness, destination_band_ptr,
|
264
|
-
mask_band: mask_band, **options, &progress)
|
280
|
+
def sieve_filter(size_threshold, connectedness, destination_band, mask_band: nil, progress_function: nil,
|
281
|
+
progress_arg: nil, **options)
|
282
|
+
_sieve_filter(size_threshold, connectedness, destination_band, mask_band: mask_band,
|
283
|
+
progress_function: progress_function,
|
284
|
+
progress_arg: progress_arg,
|
285
|
+
**options)
|
265
286
|
|
266
287
|
if destination_band.is_a? GDAL::RasterBand
|
267
288
|
destination_band
|
@@ -272,9 +293,27 @@ module GDAL
|
|
272
293
|
|
273
294
|
private
|
274
295
|
|
275
|
-
|
276
|
-
|
296
|
+
# @param size_threshold [Fixnum] Polygons found in the raster with sizes
|
297
|
+
# smaller than this will be merged into their largest neighbor.
|
298
|
+
# @param connectedness [Fixnum] 4 or 8. 4 indicates that diagonal pixels
|
299
|
+
# are not considered directly adjacent for polygon membership purposes;
|
300
|
+
# 8 indicates they are.
|
301
|
+
# @param mask_band [GDAL::RasterBand] [description] All pixels in this
|
302
|
+
# band with a value other than 0 will be considered suitable for
|
303
|
+
# inclusion in polygons.
|
304
|
+
# @param progress_function [Proc, FFI:GDAL::GDAL.ProgressFunc]
|
305
|
+
# @param progress_arg [FFI::Pointer] Usually used when when using a
|
306
|
+
# +FFI::CPL::Progress.GDALCreateScaledProgress+.
|
307
|
+
# @param options [Hash] None supported in GDAL as of this writing.
|
308
|
+
def _sieve_filter(size_threshold, connectedness, destination_band, mask_band: nil, progress_function: nil,
|
309
|
+
progress_arg: nil, **options)
|
277
310
|
mask_band_ptr = GDAL._pointer(GDAL::RasterBand, mask_band, false)
|
311
|
+
destination_band_ptr = GDAL._pointer(GDAL::RasterBand, destination_band)
|
312
|
+
|
313
|
+
if destination_band.nil? || destination_band.null?
|
314
|
+
raise GDAL::InvalidRasterBand, "destination_band isn't a valid GDAL::RasterBand: #{destination_band}"
|
315
|
+
end
|
316
|
+
|
278
317
|
options_ptr = GDAL::Options.pointer(options)
|
279
318
|
|
280
319
|
FFI::GDAL::Alg.GDALSieveFilter(
|
@@ -284,8 +323,8 @@ module GDAL
|
|
284
323
|
size_threshold,
|
285
324
|
connectedness,
|
286
325
|
options_ptr,
|
287
|
-
|
288
|
-
|
326
|
+
progress_function,
|
327
|
+
progress_arg)
|
289
328
|
end
|
290
329
|
end
|
291
330
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module GDAL
|
2
|
+
module RasterBandMixins
|
3
|
+
# RasterBand methods added for dealing with colorizing.
|
4
|
+
module ColoringExtensions
|
5
|
+
# Sets the band to be a Palette band, then applies an RGB color table using
|
6
|
+
# the given colors. Colors are distributed evenly across the table based
|
7
|
+
# on the number of colors given. Note that this will overwrite any existing
|
8
|
+
# color table that may be set on this band.
|
9
|
+
#
|
10
|
+
# @param colors [Array<Fixnum, String>, Fixnum, String] Can be a single or
|
11
|
+
# many colors, given as either R, G, and B integers (0-255) or as strings
|
12
|
+
# of Hex.
|
13
|
+
#
|
14
|
+
# @example Colors as RGB values
|
15
|
+
# # This will make the first 128 values black, and the last 128, red.
|
16
|
+
# my_band.colorize!([[0, 0, 0], [255, 0, 0]])
|
17
|
+
#
|
18
|
+
# @example Colors as Hex values
|
19
|
+
# # Same as above...
|
20
|
+
# my_band.colorize!(%w[#000000 #FF0000])
|
21
|
+
def colorize!(*colors)
|
22
|
+
return if colors.empty?
|
23
|
+
|
24
|
+
self.color_interpretation ||= :GCI_PaletteIndex
|
25
|
+
table = GDAL::ColorTable.new(:GPI_RGB)
|
26
|
+
table.add_color_entry(0, 0, 0, 0, 255)
|
27
|
+
|
28
|
+
# Start at 1 instead of 0 because we manually set the first color entry
|
29
|
+
# to white.
|
30
|
+
color_entry_index_range =
|
31
|
+
case data_type
|
32
|
+
when :GDT_Byte then 1..255
|
33
|
+
when :GDT_UInt16 then 1..65_535
|
34
|
+
else raise "Can't colorize a #{data_type} band--must be :GDT_Byte or :GDT_UInt16"
|
35
|
+
end
|
36
|
+
|
37
|
+
bin_count = (color_entry_index_range.last + 1) / colors.size.to_f
|
38
|
+
|
39
|
+
color_entry_index_range.step do |color_entry_index|
|
40
|
+
color_number = (color_entry_index / bin_count).floor.to_i
|
41
|
+
color = colors[color_number]
|
42
|
+
|
43
|
+
# TODO: Fix possible uninitialized rgb_array
|
44
|
+
rgb_array = hex_to_rgb(color) unless color.is_a?(Array)
|
45
|
+
table.add_color_entry(color_entry_index,
|
46
|
+
rgb_array[0], rgb_array[1], rgb_array[2], 255)
|
47
|
+
end
|
48
|
+
|
49
|
+
self.color_table = table
|
50
|
+
end
|
51
|
+
|
52
|
+
# Gets the colors from the associated ColorTable and returns an Array of
|
53
|
+
# those, where each ColorEntry is [R, G, B, A].
|
54
|
+
#
|
55
|
+
# @return [Array<Array<Fixnum>>]
|
56
|
+
def colors_as_rgb
|
57
|
+
return [] unless color_table
|
58
|
+
|
59
|
+
color_table.color_entries_as_rgb.map(&:to_a)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Gets the colors from the associated ColorTable and returns an Array of
|
63
|
+
# Strings, where the RGB color for each ColorEntry has been converted to
|
64
|
+
# Hex.
|
65
|
+
#
|
66
|
+
# @return [Array<String>]
|
67
|
+
def colors_as_hex
|
68
|
+
colors_as_rgb.map do |rgba|
|
69
|
+
rgb = rgba.to_a[0..2]
|
70
|
+
|
71
|
+
"##{rgb[0].to_s(16)}#{rgb[1].to_s(16)}#{rgb[2].to_s(16)}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param hex [String]
|
76
|
+
def hex_to_rgb(hex)
|
77
|
+
hex.sub!(/^#/, '')
|
78
|
+
matches = hex.match(/(?<red>[a-zA-Z0-9]{2})(?<green>[a-zA-Z0-9]{2})(?<blue>[a-zA-Z0-9]{2})/)
|
79
|
+
|
80
|
+
[matches[:red].to_i(16), matches[:green].to_i(16), matches[:blue].to_i(16)]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|