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.
Files changed (237) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -3
  3. data/.rubocop.yml +7 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +1 -1
  6. data/History.md +143 -1
  7. data/README.md +5 -11
  8. data/Rakefile +2 -60
  9. data/TODO.md +10 -0
  10. data/examples/geometries.rb +4 -6
  11. data/examples/gridding.rb +99 -98
  12. data/examples/ogr_layer_to_layer.rb +0 -2
  13. data/examples/raster_erasing.rb +47 -0
  14. data/examples/remove_small_polygons.rb +62 -0
  15. data/examples/testing_gdal.rb +0 -3
  16. data/examples/warping.rb +140 -0
  17. data/ffi-gdal.gemspec +5 -2
  18. data/lib/ext/error_symbols.rb +1 -1
  19. data/lib/ext/ffi_library_function_checks.rb +3 -2
  20. data/lib/ext/float_ext.rb +2 -2
  21. data/lib/ext/narray_ext.rb +1 -1
  22. data/lib/ext/numeric_as_data_type.rb +1 -1
  23. data/lib/ext/to_bool.rb +2 -2
  24. data/lib/ffi/cpl/conv.rb +1 -3
  25. data/lib/ffi/cpl/error.rb +0 -3
  26. data/lib/ffi/cpl/minixml.rb +17 -21
  27. data/lib/ffi/cpl/progress.rb +27 -0
  28. data/lib/ffi/cpl/string.rb +0 -8
  29. data/lib/ffi/cpl/vsi.rb +0 -1
  30. data/lib/ffi/cpl/xml_node.rb +0 -1
  31. data/lib/ffi/cpl.rb +15 -0
  32. data/lib/ffi/gdal/alg.rb +72 -54
  33. data/lib/ffi/gdal/gdal.rb +669 -672
  34. data/lib/ffi/gdal/grid.rb +141 -24
  35. data/lib/ffi/gdal/grid_data_metrics_options.rb +1 -1
  36. data/lib/ffi/gdal/grid_moving_average_options.rb +1 -1
  37. data/lib/ffi/gdal/matching.rb +0 -2
  38. data/lib/ffi/gdal/transformer_info.rb +1 -1
  39. data/lib/ffi/gdal/version.rb +1 -1
  40. data/lib/ffi/gdal/vrt.rb +0 -2
  41. data/lib/ffi/gdal/warp_options.rb +12 -14
  42. data/lib/ffi/gdal/warper.rb +61 -6
  43. data/lib/ffi/gdal.rb +18 -3
  44. data/lib/ffi/ogr/api.rb +10 -21
  45. data/lib/ffi/ogr/core.rb +9 -12
  46. data/lib/ffi/ogr/featurestyle.rb +0 -5
  47. data/lib/ffi/ogr/geocoding.rb +0 -1
  48. data/lib/ffi/ogr/srs_api.rb +0 -4
  49. data/lib/ffi/ogr/style_value.rb +1 -2
  50. data/lib/ffi/ogr.rb +15 -12
  51. data/lib/ffi-gdal.rb +5 -3
  52. data/lib/gdal/color_entry.rb +1 -0
  53. data/lib/gdal/color_interpretation.rb +2 -2
  54. data/lib/gdal/color_table.rb +14 -14
  55. data/lib/gdal/color_table_mixins/extensions.rb +4 -4
  56. data/lib/gdal/cpl_error_handler.rb +12 -14
  57. data/lib/gdal/data_type.rb +13 -12
  58. data/lib/gdal/dataset.rb +170 -94
  59. data/lib/gdal/dataset_mixins/algorithm_methods.rb +47 -21
  60. data/lib/gdal/dataset_mixins/extensions.rb +32 -61
  61. data/lib/gdal/dataset_mixins/matching.rb +0 -2
  62. data/lib/gdal/dataset_mixins/warp_methods.rb +42 -0
  63. data/lib/gdal/driver.rb +62 -47
  64. data/lib/gdal/driver_mixins/extensions.rb +2 -7
  65. data/lib/gdal/environment_methods.rb +13 -10
  66. data/lib/gdal/exceptions.rb +24 -2
  67. data/lib/gdal/geo_transform.rb +10 -16
  68. data/lib/gdal/geo_transform_mixins/extensions.rb +58 -3
  69. data/lib/gdal/grid.rb +62 -109
  70. data/lib/gdal/{grid_types → grid_algorithms}/data_metrics_base.rb +1 -3
  71. data/lib/gdal/{grid_types → grid_algorithms}/inverse_distance_to_a_power.rb +2 -4
  72. data/lib/gdal/{grid_types → grid_algorithms}/metric_average_distance.rb +2 -2
  73. data/lib/gdal/{grid_types → grid_algorithms}/metric_average_distance_pts.rb +2 -2
  74. data/lib/gdal/{grid_types → grid_algorithms}/metric_count.rb +2 -2
  75. data/lib/gdal/{grid_types → grid_algorithms}/metric_maximum.rb +2 -2
  76. data/lib/gdal/{grid_types → grid_algorithms}/metric_minimum.rb +2 -2
  77. data/lib/gdal/{grid_types → grid_algorithms}/metric_range.rb +2 -2
  78. data/lib/gdal/{grid_types → grid_algorithms}/moving_average.rb +2 -4
  79. data/lib/gdal/{grid_types → grid_algorithms}/nearest_neighbor.rb +2 -4
  80. data/lib/gdal/grid_algorithms.rb +22 -0
  81. data/lib/gdal/gridder/point_extracting.rb +89 -0
  82. data/lib/gdal/gridder.rb +294 -0
  83. data/lib/gdal/gridder_options.rb +273 -0
  84. data/lib/gdal/internal_helpers.rb +132 -23
  85. data/lib/gdal/major_object.rb +13 -10
  86. data/lib/gdal/merger.rb +130 -0
  87. data/lib/gdal/options.rb +3 -2
  88. data/lib/gdal/raster_attribute_table.rb +74 -51
  89. data/lib/gdal/raster_attribute_table_mixins/extensions.rb +21 -3
  90. data/lib/gdal/raster_band.rb +139 -167
  91. data/lib/gdal/raster_band_classifier.rb +19 -18
  92. data/lib/gdal/raster_band_mixins/algorithm_extensions.rb +107 -0
  93. data/lib/gdal/raster_band_mixins/algorithm_methods.rb +79 -40
  94. data/lib/gdal/raster_band_mixins/coloring_extensions.rb +84 -0
  95. data/lib/gdal/raster_band_mixins/extensions.rb +34 -169
  96. data/lib/gdal/raster_band_mixins/io_extensions.rb +180 -0
  97. data/lib/gdal/rpc_info.rb +1 -2
  98. data/lib/gdal/transformer.rb +1 -6
  99. data/lib/gdal/transformers/approximate_transformer.rb +0 -4
  100. data/lib/gdal/transformers/base_general_image_projection_transformer.rb +0 -6
  101. data/lib/gdal/transformers/gcp_transformer.rb +2 -6
  102. data/lib/gdal/transformers/general_image_projection_transformer.rb +8 -7
  103. data/lib/gdal/transformers/general_image_projection_transformer2.rb +1 -1
  104. data/lib/gdal/transformers/geolocation_transformer.rb +0 -4
  105. data/lib/gdal/transformers/reprojection_transformer.rb +0 -8
  106. data/lib/gdal/transformers/rpc_transformer.rb +0 -4
  107. data/lib/gdal/transformers/tps_transformer.rb +1 -3
  108. data/lib/gdal/version_info.rb +7 -8
  109. data/lib/gdal/virtual_dataset.rb +2 -4
  110. data/lib/gdal/warp_operation.rb +17 -14
  111. data/lib/gdal/warp_options.rb +132 -0
  112. data/lib/gdal.rb +41 -2
  113. data/lib/ogr/coordinate_transformation.rb +79 -32
  114. data/lib/ogr/data_source.rb +17 -14
  115. data/lib/ogr/data_source_extensions.rb +1 -5
  116. data/lib/ogr/driver.rb +11 -14
  117. data/lib/ogr/envelope.rb +1 -1
  118. data/lib/ogr/envelope_extensions.rb +23 -6
  119. data/lib/ogr/error_handling.rb +3 -3
  120. data/lib/ogr/exceptions.rb +6 -0
  121. data/lib/ogr/feature.rb +25 -38
  122. data/lib/ogr/feature_definition.rb +6 -8
  123. data/lib/ogr/feature_definition_extensions.rb +2 -6
  124. data/lib/ogr/feature_extensions.rb +71 -41
  125. data/lib/ogr/field.rb +16 -15
  126. data/lib/ogr/field_definition.rb +4 -4
  127. data/lib/ogr/geocoder.rb +5 -5
  128. data/lib/ogr/geometries/geometry_collection.rb +4 -1
  129. data/lib/ogr/geometries/geometry_collection_25d.rb +12 -0
  130. data/lib/ogr/geometries/line_string.rb +30 -8
  131. data/lib/ogr/geometries/line_string_25d.rb +21 -0
  132. data/lib/ogr/geometries/linear_ring.rb +10 -1
  133. data/lib/ogr/geometries/multi_line_string.rb +2 -1
  134. data/lib/ogr/geometries/multi_line_string_25d.rb +13 -0
  135. data/lib/ogr/geometries/multi_point.rb +2 -1
  136. data/lib/ogr/geometries/multi_point_25d.rb +14 -0
  137. data/lib/ogr/geometries/multi_polygon.rb +3 -2
  138. data/lib/ogr/geometries/multi_polygon_25d.rb +13 -0
  139. data/lib/ogr/geometries/point.rb +20 -23
  140. data/lib/ogr/geometries/point_25d.rb +48 -0
  141. data/lib/ogr/geometries/polygon.rb +4 -1
  142. data/lib/ogr/geometries/polygon_25d.rb +14 -0
  143. data/lib/ogr/geometry.rb +125 -93
  144. data/lib/ogr/geometry_field_definition.rb +7 -5
  145. data/lib/ogr/geometry_mixins/container_mixins.rb +23 -0
  146. data/lib/ogr/geometry_mixins/extensions.rb +111 -0
  147. data/lib/ogr/geometry_types/container.rb +10 -3
  148. data/lib/ogr/geometry_types/curve.rb +68 -23
  149. data/lib/ogr/geometry_types/surface.rb +0 -9
  150. data/lib/ogr/internal_helpers.rb +3 -3
  151. data/lib/ogr/layer.rb +4 -5
  152. data/lib/ogr/layer_mixins/extensions.rb +242 -17
  153. data/lib/ogr/layer_mixins/ogr_feature_methods.rb +11 -11
  154. data/lib/ogr/layer_mixins/ogr_field_methods.rb +6 -11
  155. data/lib/ogr/layer_mixins/ogr_layer_method_methods.rb +18 -18
  156. data/lib/ogr/layer_mixins/ogr_query_filter_methods.rb +0 -2
  157. data/lib/ogr/layer_mixins/ogr_sql_methods.rb +1 -1
  158. data/lib/ogr/spatial_reference.rb +12 -37
  159. data/lib/ogr/spatial_reference_mixins/coordinate_system_getter_setters.rb +53 -55
  160. data/lib/ogr/spatial_reference_mixins/exporters.rb +18 -49
  161. data/lib/ogr/spatial_reference_mixins/parameter_getter_setters.rb +10 -29
  162. data/lib/ogr/style_table.rb +2 -2
  163. data/lib/ogr/style_table_extensions.rb +3 -1
  164. data/lib/ogr/style_tool.rb +8 -14
  165. data/lib/ogr.rb +39 -1
  166. data/spec/ffi-gdal_spec.rb +18 -1
  167. data/spec/integration/gdal/color_table_info_spec.rb +49 -33
  168. data/spec/integration/gdal/dataset_info_spec.rb +294 -45
  169. data/spec/integration/gdal/driver_info_spec.rb +139 -31
  170. data/spec/integration/gdal/geo_transform_info_spec.rb +197 -26
  171. data/spec/integration/gdal/gridder_spec.rb +329 -0
  172. data/spec/integration/gdal/raster_attribute_table_info_spec.rb +216 -11
  173. data/spec/integration/gdal/raster_band_algorithms_spec.rb +33 -0
  174. data/spec/integration/gdal/raster_band_info_spec.rb +240 -271
  175. data/spec/integration/ogr/layer_spec.rb +3 -1
  176. data/spec/spec_helper.rb +15 -6
  177. data/spec/support/images/osgeo/gdal/data/hfa/float-rle.img +0 -0
  178. data/spec/support/images/osgeo/geotiff/GeogToWGS84GeoKey/GeogToWGS84GeoKey5.lgo +31 -0
  179. data/spec/support/images/osgeo/geotiff/GeogToWGS84GeoKey/GeogToWGS84GeoKey5.tif +0 -0
  180. data/spec/support/images/osgeo/geotiff/GeogToWGS84GeoKey/GeogToWGS84GeoKey5.tif.msk +0 -0
  181. data/spec/support/images/osgeo/geotiff/GeogToWGS84GeoKey/GeogToWGS84GeoKey5.txt +10 -0
  182. data/spec/support/images/osgeo/geotiff/gdal_eg/cea.tif +0 -0
  183. data/spec/support/images/osgeo/geotiff/gdal_eg/cea.txt +84 -0
  184. data/spec/support/images/osgeo/geotiff/zi_imaging/image0.lgo +45 -0
  185. data/spec/support/images/osgeo/geotiff/zi_imaging/image0.tif +0 -0
  186. data/spec/support/integration_help.rb +32 -2
  187. data/spec/support/shared_examples/gdal/major_object_examples.rb +0 -6
  188. data/spec/support/shared_examples/ogr/a_geometry.rb +1 -1
  189. data/spec/unit/ffi/gdal_spec.rb +1 -1
  190. data/spec/unit/gdal/color_entry_spec.rb +1 -0
  191. data/spec/unit/gdal/color_interpretation_spec.rb +1 -0
  192. data/spec/unit/gdal/dataset_spec.rb +53 -2
  193. data/spec/unit/gdal/geo_transform_mixins/extensions_spec.rb +67 -0
  194. data/spec/unit/gdal/geo_transform_spec.rb +1 -1
  195. data/spec/unit/gdal/grid_spec.rb +83 -0
  196. data/spec/unit/gdal/gridder/point_extracting_spec.rb +99 -0
  197. data/spec/unit/gdal/gridder_options_spec.rb +183 -0
  198. data/spec/unit/gdal/gridder_spec.rb +140 -0
  199. data/spec/unit/gdal/internal_helpers_spec.rb +166 -2
  200. data/spec/unit/gdal/major_object_spec.rb +2 -0
  201. data/spec/unit/gdal/options_spec.rb +1 -0
  202. data/spec/unit/gdal/raster_band_classifier_spec.rb +70 -12
  203. data/spec/unit/gdal/raster_band_mixins/extensions_spec.rb +71 -0
  204. data/spec/unit/gdal/raster_band_mixins/io_extensions_spec.rb +133 -0
  205. data/spec/unit/gdal/raster_band_spec.rb +1 -0
  206. data/spec/unit/gdal/rpc_info_spec.rb +1 -0
  207. data/spec/unit/gdal/version_info_spec.rb +2 -0
  208. data/spec/unit/gdal/warp_operation_spec.rb +1 -0
  209. data/spec/unit/ogr/coordinate_transformation_spec.rb +102 -0
  210. data/spec/unit/ogr/data_source_spec.rb +12 -0
  211. data/spec/unit/ogr/feature_extensions_spec.rb +88 -0
  212. data/spec/unit/ogr/feature_spec.rb +30 -46
  213. data/spec/unit/ogr/geometries/geometry_collection_25d_spec.rb +23 -0
  214. data/spec/unit/ogr/geometries/geometry_collection_spec.rb +3 -3
  215. data/spec/unit/ogr/geometries/line_string_25d_spec.rb +23 -0
  216. data/spec/unit/ogr/geometries/line_string_spec.rb +2 -2
  217. data/spec/unit/ogr/geometries/linear_ring_spec.rb +2 -2
  218. data/spec/unit/ogr/geometries/multi_line_string_25d_spec.rb +23 -0
  219. data/spec/unit/ogr/geometries/multi_point_25d_spec.rb +23 -0
  220. data/spec/unit/ogr/geometries/multi_polygon_25d_spec.rb +23 -0
  221. data/spec/unit/ogr/geometries/point_25d_spec.rb +23 -0
  222. data/spec/unit/ogr/geometries/point_spec.rb +14 -24
  223. data/spec/unit/ogr/geometries/polygon_25d_spec.rb +23 -0
  224. data/spec/unit/ogr/geometries/polygon_spec.rb +1 -1
  225. data/spec/unit/ogr/geometry_field_definition_spec.rb +1 -1
  226. data/spec/unit/ogr/geometry_spec.rb +196 -30
  227. data/spec/unit/ogr/internal_helpers_spec.rb +20 -9
  228. data/spec/unit/ogr/layer_mixins/ogr_feature_methods_spec.rb +14 -6
  229. data/spec/unit/ogr/spatial_reference_mixins/exporters_spec.rb +9 -1
  230. data/spec/unit/ogr/spatial_reference_mixins/parameter_getter_setters_spec.rb +2 -1
  231. data/spec/unit/ogr/style_table_spec.rb +1 -1
  232. data/tmp/.keep +0 -0
  233. metadata +121 -19
  234. data/examples/points.txt +0 -127
  235. data/lib/gdal/grid_types.rb +0 -22
  236. data/lib/ogr/geometries/point_extensions.rb +0 -32
  237. data/lib/ogr/geometry_extensions.rb +0 -59
@@ -4,31 +4,229 @@ module OGR
4
4
  module LayerMixins
5
5
  # Methods not part of the C Layer API.
6
6
  module Extensions
7
+ # Enumerates through all associated features. Beware: it calls
8
+ # {#reset_reading} both before and after it's called. If you're using
9
+ # {OGR::Layer#next_feature} for iterating through features somewhere in
10
+ # your code, this will reset that reading.
11
+ #
12
+ # @return [Enumerator]
13
+ # @yieldparam [OGR::Feature]
14
+ def each_feature
15
+ return enum_for(:each_feature) unless block_given?
16
+
17
+ FFI::OGR::API.OGR_L_ResetReading(@c_pointer)
18
+
19
+ loop do
20
+ feature = next_feature
21
+ break unless feature
22
+
23
+ begin
24
+ yield feature
25
+ rescue
26
+ feature.destroy!
27
+ raise
28
+ end
29
+
30
+ feature.destroy!
31
+ end
32
+
33
+ FFI::OGR::API.OGR_L_ResetReading(@c_pointer)
34
+ end
35
+
36
+ # @return [Enumerator]
37
+ # @yieldparam [FFI::Pointer] A pointer to each feature in the layer.
38
+ def each_feature_pointer
39
+ return enum_for(:each_feature_pointer) unless block_given?
40
+
41
+ FFI::OGR::API.OGR_L_ResetReading(@c_pointer)
42
+
43
+ loop do
44
+ feature_ptr = FFI::OGR::API.OGR_L_GetNextFeature(@c_pointer)
45
+
46
+ if feature_ptr.null?
47
+ FFI::OGR::API.OGR_F_Destroy(feature_ptr)
48
+ break
49
+ end
50
+
51
+ begin
52
+ yield feature_ptr
53
+ rescue
54
+ FFI::OGR::API.OGR_F_Destroy(feature_ptr)
55
+ raise
56
+ end
57
+
58
+ FFI::OGR::API.OGR_F_Destroy(feature_ptr)
59
+ end
60
+
61
+ FFI::OGR::API.OGR_L_ResetReading(@c_pointer)
62
+ end
63
+
64
+ # Returns all features as an Array. Note that if you just want to iterate
65
+ # through features, {{#each_feature}} will perform better.
66
+ #
7
67
  # @return [Array<OGR::Feature>]
8
68
  def features
9
- return [] if feature_count.zero?
69
+ each_feature.map { |f| f.clone }
70
+ end
71
+
72
+ # @return [OGR::Polygon] A polygon derived from a LinearRing that connects
73
+ # the 4 bounding box points (from the extent).
74
+ def geometry_from_extent
75
+ ring = OGR::LinearRing.new
76
+
77
+ ring.point_count = 5
78
+ ring.set_point(0, extent.x_min, extent.y_min)
79
+ ring.set_point(1, extent.x_min, extent.y_max)
80
+ ring.set_point(2, extent.x_max, extent.y_max)
81
+ ring.set_point(3, extent.x_max, extent.y_min)
82
+ ring.set_point(4, extent.x_min, extent.y_min)
83
+
84
+ polygon = OGR::Polygon.new spatial_reference: spatial_reference.dup
85
+ polygon.add_geometry(ring)
86
+
87
+ polygon
88
+ end
89
+
90
+ # Iterates through all geometries in the Layer and extracts the point
91
+ # values to an Array. The result will be an Array of Arrays where the
92
+ # inner Array is the point values. If +with_attributes+ is given, it will
93
+ # extract the field values for each given field names.
94
+ #
95
+ # @example Not passing +with_attributes+
96
+ # points = layer.point_values
97
+ # # => [[100, 100], [100, 120], [110, 110], [110, 100], [100, 100]]
98
+ #
99
+ # @example With +with_attributes+
100
+ # points = layer.point_values('Moisture' => :double, 'Color' => :string)
101
+ # # => [[100, 100, 74.2, 'Red'],
102
+ # [100, 120, 19.0, 'Blue'],
103
+ # [110, 110, 21.1, 'Red'],
104
+ # [110, 100, 54.99, 'Green'],
105
+ # [100, 100, 3.3, 'Red']]
106
+ #
107
+ # @param with_attributes [String, Array<String>]
108
+ # @return [Array<Array>]
109
+ # @raise [OGR::UnsupportedGeometryType] if a geometry of some type is
110
+ # encountered that the method doesn't know how to extract point values
111
+ # from.
112
+ def point_values(with_attributes = {})
113
+ return [[]] if feature_count.zero?
114
+
115
+ field_indices = with_attributes.keys.map { |field_name| find_field_index(field_name) }
116
+ values = Array.new(feature_count) { Array.new(2 + with_attributes.size) }
117
+ start = Time.now
118
+ i = 0
119
+
120
+ # Initing these once and only once in the case the geom type is _not_
121
+ # wkbPoint.
122
+ x_ptr = FFI::MemoryPointer.new(:double)
123
+ y_ptr = FFI::MemoryPointer.new(:double)
10
124
 
11
- feature_list = feature_count.times.map do |i|
12
- feature(i)
125
+ each_feature_pointer do |feature_ptr|
126
+ field_values = field_indices.map.with_index do |j, attribute_index|
127
+ FFI::OGR::API.send("OGR_F_GetFieldAs#{with_attributes.values[attribute_index].capitalize}", feature_ptr, j)
128
+ end
129
+
130
+ geom_ptr = FFI::OGR::API.OGR_F_GetGeometryRef(feature_ptr)
131
+ geom_ptr.autorelease = false
132
+ FFI::OGR::API.OGR_G_FlattenTo2D(geom_ptr)
133
+ geom_type = FFI::OGR::API.OGR_G_GetGeometryType(geom_ptr)
134
+
135
+ case geom_type
136
+ when :wkbPoint
137
+ values[i] = collect_point_values(geom_ptr, field_values)
138
+ i += 1
139
+ when :wkbLineString, :wkbLinearRing
140
+ extract_ring_points(geom_ptr, x_ptr, y_ptr) do |points|
141
+ values[i] = points.push(*field_values)
142
+ i += 1
143
+ end
144
+ when :wkbPolygon
145
+ exterior_ring_ptr = FFI::OGR::API.OGR_G_GetGeometryRef(geom_ptr, 0)
146
+
147
+ extract_ring_points(exterior_ring_ptr, x_ptr, y_ptr) do |points|
148
+ values[i] = points.push(*field_values)
149
+ i += 1
150
+ end
151
+
152
+ count = FFI::OGR::API.OGR_G_GetGeometryCount(geom_ptr)
153
+ next if count > 1
154
+
155
+ count.times do |ring_num|
156
+ next if ring_num.zero?
157
+ ring_ptr = FFI::OGR::API.OGR_G_GetGeometryRef(geom_ptr, ring_num)
158
+
159
+ extract_ring_points(ring_ptr, x_ptr, y_ptr) do |points|
160
+ values[i] = points.push(*field_values)
161
+ i += 1
162
+ end
163
+ end
164
+ when :wkbMultiPoint, :wkbMultiLineString
165
+ count = FFI::OGR::API.OGR_G_GetGeometryCount(geom_ptr)
166
+
167
+ count.times do |geom_num|
168
+ ring_ptr = FFI::OGR::API.OGR_G_GetGeometryRef(geom_ptr, geom_num)
169
+
170
+ extract_ring_points(ring_ptr, x_ptr, y_ptr) do |points|
171
+ values[i] = points.push(*field_values)
172
+ i += 1
173
+ end
174
+ end
175
+ when :wkbMultiPolygon
176
+ polygon_count = FFI::OGR::API.OGR_G_GetGeometryCount(geom_ptr)
177
+
178
+ polygon_count.times do |polygon_num|
179
+ polygon_ptr = FFI::OGR::API.OGR_G_GetGeometryRef(geom_ptr, polygon_num)
180
+ polygon_ptr.autorelease = false
181
+ exterior_ring_ptr = FFI::OGR::API.OGR_G_GetGeometryRef(polygon_ptr, 0)
182
+ exterior_ring_ptr.autorelease = false
183
+
184
+ extract_ring_points(exterior_ring_ptr, x_ptr, y_ptr) do |points|
185
+ values[i] = points.push(*field_values)
186
+ i += 1
187
+ end
188
+
189
+ count = FFI::OGR::API.OGR_G_GetGeometryCount(polygon_ptr)
190
+ next if count > 1
191
+
192
+ count.times do |ring_num|
193
+ next if ring_num.zero?
194
+ ring_ptr = FFI::OGR::API.OGR_G_GetGeometryRef(polygon_ptr, ring_num)
195
+ ring_ptr.autorelease = false
196
+
197
+ extract_ring_points(ring_ptr, x_ptr, y_ptr) do |points|
198
+ values[i] = points.push(*field_values)
199
+ i += 1
200
+ end
201
+ end
202
+ end
203
+ else raise OGR::UnsupportedGeometryType,
204
+ "Not sure how to extract point_values for a #{geom_type}"
205
+ end
13
206
  end
14
207
 
15
- @features = feature_list
208
+ log "#point_values took #{Time.now - start}s"
209
+
210
+ values
16
211
  end
17
212
 
18
- # @return [OGR::Geometry] A convex hull geometry derived from a LineString
19
- # that connects the 4 bounding box points (from the extent).
20
- def geometry_from_extent
21
- sr = spatial_reference
22
- geometry = OGR::Geometry.create(:wkbLineString)
23
- geometry.spatial_reference = sr
213
+ # Iterates through features to see if any of them are 3d.
214
+ #
215
+ # @return [Boolean]
216
+ def any_geometries_with_z?
217
+ found_z_geom = false
218
+
219
+ each_feature_pointer do |feature_ptr|
220
+ break if found_z_geom
221
+ geom_ptr = FFI::OGR::API.OGR_F_GetGeometryRef(feature_ptr)
222
+ geom_ptr.autorelease = false
223
+ coordinate_dimension = FFI::OGR::API.OGR_G_GetCoordinateDimension(geom_ptr)
224
+ found_z_geom = coordinate_dimension == 3
225
+ end
24
226
 
25
- geometry.add_point(extent.x_min, extent.y_min)
26
- geometry.add_point(extent.x_min, extent.y_max)
27
- geometry.add_point(extent.x_max, extent.y_max)
28
- geometry.add_point(extent.x_max, extent.y_min)
29
- geometry.add_point(extent.x_min, extent.y_min)
227
+ feature.destroy! if feature.c_pointer
30
228
 
31
- geometry.convex_hull
229
+ found_z_geom
32
230
  end
33
231
 
34
232
  # @return [Hash]
@@ -38,7 +236,7 @@ module OGR
38
236
  extent: extent.as_json(options),
39
237
  feature_count: feature_count,
40
238
  feature_definition: feature_definition.as_json(options),
41
- features: features.map(&:as_json),
239
+ features: each_feature.map { |f| f.as_json(options) },
42
240
  fid_column: fid_column,
43
241
  geometry_column: geometry_column,
44
242
  geometry_type: geometry_type,
@@ -54,6 +252,33 @@ module OGR
54
252
  def to_json(options = nil)
55
253
  as_json(options).to_json
56
254
  end
255
+
256
+ private
257
+
258
+ # @param geometry_ptr [FFI::Pointer]
259
+ # @param field_values [Array]
260
+ # @return [Array]
261
+ def collect_point_values(geometry_ptr, field_values)
262
+ [FFI::OGR::API.OGR_G_GetX(geometry_ptr, 0), FFI::OGR::API.OGR_G_GetY(geometry_ptr, 0), *field_values]
263
+ end
264
+
265
+ # @param ring_ptr [FFI::Pointer] Pointer to the LineString/LinearRing to
266
+ # extract points from.
267
+ # @param x_ptr [FFI::Pointer] Pointer to use for writing the x value to.
268
+ # @param y_ptr [FFI::Pointer] Pointer to use for writing the y value to.
269
+ # @yieldparam [Array<Float>] (x, y)
270
+ def extract_ring_points(ring_ptr, x_ptr, y_ptr)
271
+ point_count = FFI::OGR::API.OGR_G_GetPointCount(ring_ptr)
272
+
273
+ point_count.times do |point_num|
274
+ FFI::OGR::API.OGR_G_GetPoint(ring_ptr, point_num, x_ptr, y_ptr, nil)
275
+
276
+ yield [x_ptr.read_double, y_ptr.read_double]
277
+
278
+ x_ptr.clear
279
+ y_ptr.clear
280
+ end
281
+ end
57
282
  end
58
283
  end
59
284
  end
@@ -1,6 +1,3 @@
1
- require_relative '../feature'
2
- require_relative '../feature_definition'
3
-
4
1
  module OGR
5
2
  module LayerMixins
6
3
  module OGRFeatureMethods
@@ -14,7 +11,7 @@ module OGR
14
11
  # This object should not be modified.
15
12
  OGR::FeatureDefinition.new(feature_defn_pointer)
16
13
  end
17
- alias_method :feature_definition, :definition
14
+ alias feature_definition definition
18
15
 
19
16
  # Adds the new OGR::Feature to the Layer. The feature should have been
20
17
  # created using the Layer's FeatureDefintion.
@@ -27,7 +24,7 @@ module OGR
27
24
  # @return [Boolean]
28
25
  def create_feature(feature)
29
26
  unless can_sequential_write?
30
- fail OGR::UnsupportedOperation, 'This layer does not support feature creation.'
27
+ raise OGR::UnsupportedOperation, 'This layer does not support feature creation.'
31
28
  end
32
29
 
33
30
  ogr_err = FFI::OGR::API.OGR_L_CreateFeature(@c_pointer, feature.c_pointer)
@@ -43,7 +40,7 @@ module OGR
43
40
  # does not exist.
44
41
  def delete_feature(feature_id)
45
42
  unless can_delete_feature?
46
- fail OGR::UnsupportedOperation, 'This layer does not support feature deletion.'
43
+ raise OGR::UnsupportedOperation, 'This layer does not support feature deletion.'
47
44
  end
48
45
 
49
46
  ogr_err = FFI::OGR::API.OGR_L_DeleteFeature(@c_pointer, feature_id)
@@ -65,11 +62,11 @@ module OGR
65
62
  # @param new_feature [OGR::Feature, FFI::Pointer]
66
63
  def feature=(new_feature)
67
64
  unless can_random_write?
68
- fail OGR::UnsupportedOperation, '#feature= not supported by this Layer'
65
+ raise OGR::UnsupportedOperation, '#feature= not supported by this Layer'
69
66
  end
70
67
 
71
68
  new_feature_ptr = GDAL._pointer(OGR::Feature, new_feature)
72
- fail OGR::InvalidFeature if new_feature_ptr.nil? || new_feature_ptr.null?
69
+ raise OGR::InvalidFeature if new_feature_ptr.nil? || new_feature_ptr.null?
73
70
 
74
71
  ogr_err = FFI::OGR::API.OGR_L_SetFeature(@c_pointer, new_feature_ptr)
75
72
 
@@ -81,7 +78,7 @@ module OGR
81
78
  # @return [OGR::Feature, nil]
82
79
  def feature(index)
83
80
  unless can_random_read?
84
- fail OGR::UnsupportedOperation, '#feature(index) not supported by this Layer'
81
+ raise OGR::UnsupportedOperation, '#feature(index) not supported by this Layer'
85
82
  end
86
83
 
87
84
  feature_pointer = FFI::OGR::API.OGR_L_GetFeature(@c_pointer, index)
@@ -94,10 +91,13 @@ module OGR
94
91
  # current spatial filter will be returned. Use +reset_reading+ to start at
95
92
  # the beginning again.
96
93
  #
94
+ # NOTE: You *must* call {{OGR::Feature#destroy!}} on the returned feature,
95
+ # otherwise expect segfaults.
96
+ #
97
97
  # @return [OGR::Feature, nil]
98
98
  def next_feature
99
99
  feature_pointer = FFI::OGR::API.OGR_L_GetNextFeature(@c_pointer)
100
- return nil if feature_pointer.null?
100
+ return if feature_pointer.null?
101
101
 
102
102
  OGR::Feature.new(feature_pointer)
103
103
  end
@@ -111,7 +111,7 @@ module OGR
111
111
 
112
112
  ogr_err.handle_result "Unable to set next feature index to #{feature_index}"
113
113
  end
114
- alias_method :set_next_by_index, :next_feature_index=
114
+ alias set_next_by_index next_feature_index=
115
115
 
116
116
  # @return [Fixnum]
117
117
  def features_read
@@ -1,8 +1,3 @@
1
- require_relative '../field_definition'
2
- require_relative '../field'
3
- require_relative '../geometry_field_definition'
4
- require_relative '../../ffi/ogr/api'
5
-
6
1
  module OGR
7
2
  module LayerMixins
8
3
  module OGRFieldMethods
@@ -16,7 +11,7 @@ module OGR
16
11
  # @return [Boolean]
17
12
  def create_field(field_definition, approx_ok = false)
18
13
  unless can_create_field?
19
- fail OGR::UnsupportedOperation, 'This layer does not support field creation.'
14
+ raise OGR::UnsupportedOperation, 'This layer does not support field creation.'
20
15
  end
21
16
 
22
17
  field_definition_ptr = GDAL._pointer(OGR::FieldDefinition, field_definition)
@@ -30,7 +25,7 @@ module OGR
30
25
  # @return +true+ if successful, otherwise raises an OGR exception.
31
26
  def delete_field(field_id)
32
27
  unless can_delete_field?
33
- fail OGR::UnsupportedOperation, 'This driver does not support field deletion.'
28
+ raise OGR::UnsupportedOperation, 'This driver does not support field deletion.'
34
29
  end
35
30
 
36
31
  ogr_err = FFI::OGR::API.OGR_L_DeleteField(@c_pointer, field_id)
@@ -43,7 +38,7 @@ module OGR
43
38
  # @return [Boolean]
44
39
  def reorder_fields(*new_order)
45
40
  unless can_reorder_fields?
46
- fail OGR::UnsupportedOperation, 'This driver does not support field reordering.'
41
+ raise OGR::UnsupportedOperation, 'This driver does not support field reordering.'
47
42
  end
48
43
 
49
44
  return false if new_order.empty?
@@ -62,7 +57,7 @@ module OGR
62
57
  # @param new_position [Fixnum]
63
58
  def reorder_field(old_position, new_position)
64
59
  unless can_reorder_fields?
65
- fail OGR::UnsupportedOperation, 'This driver does not support field reordering.'
60
+ raise OGR::UnsupportedOperation, 'This driver does not support field reordering.'
66
61
  end
67
62
 
68
63
  ogr_err = FFI::OGR::API.OGR_L_ReorderField(@c_pointer, old_position, new_position)
@@ -77,7 +72,7 @@ module OGR
77
72
  # ALTER_WIDTH_PRECISION_FLAG, or ALTER_ALL_FLAG.
78
73
  def alter_field_definition(field_index, new_field_definition, flags)
79
74
  unless can_alter_field_definition?
80
- fail OGR::UnsupportedOperation, 'This layer does not support field definition altering.'
75
+ raise OGR::UnsupportedOperation, 'This layer does not support field definition altering.'
81
76
  end
82
77
 
83
78
  new_field_definition_ptr = GDAL._pointer(OGR::FieldDefinition, new_field_definition)
@@ -112,7 +107,7 @@ module OGR
112
107
  # @return [Boolean]
113
108
  def create_geometry_field(geometry_field_def, approx_ok = false)
114
109
  unless can_create_geometry_field?
115
- fail OGR::UnsupportedOperation, 'This layer does not support geometry field creation'
110
+ raise OGR::UnsupportedOperation, 'This layer does not support geometry field creation'
116
111
  end
117
112
 
118
113
  geometry_field_definition_ptr = GDAL._pointer(OGR::GeometryFieldDefinition, geometry_field_def)
@@ -20,8 +20,8 @@ module OGR
20
20
  # that will be created from the fields of the input Layer.
21
21
  # @option options [String] method_prefix Set a prefix for the field names
22
22
  # that will be created from the fields of the method Layer.
23
- def clip(method_layer, **options, &progress)
24
- run_layer_method(:OGR_L_Clip, method_layer, **options, &progress)
23
+ def clip(method_layer, output_layer, **options, &progress)
24
+ run_layer_method(:OGR_L_Clip, method_layer, output_layer, **options, &progress)
25
25
  end
26
26
 
27
27
  # Remove areas in this layer that are covered by the method layer.
@@ -40,8 +40,8 @@ module OGR
40
40
  # that will be created from the fields of the input Layer.
41
41
  # @option options [String] method_prefix Set a prefix for the field names
42
42
  # that will be created from the fields of the method Layer.
43
- def erase(method_layer, **options, &progress)
44
- run_layer_method(:OGR_L_Erase, method_layer, **options, &progress)
43
+ def erase(method_layer, output_layer, **options, &progress)
44
+ run_layer_method(:OGR_L_Erase, method_layer, output_layer, **options, &progress)
45
45
  end
46
46
 
47
47
  # The result layer contains features whose geometries represent areas that
@@ -58,8 +58,8 @@ module OGR
58
58
  # that will be created from the fields of the input Layer.
59
59
  # @option options [String] method_prefix Set a prefix for the field names
60
60
  # that will be created from the fields of the method Layer.
61
- def identity(method_layer, **options, &progress)
62
- run_layer_method(:OGR_L_Identity, method_layer, **options, &progress)
61
+ def identity(method_layer, output_layer, **options, &progress)
62
+ run_layer_method(:OGR_L_Identity, method_layer, output_layer, **options, &progress)
63
63
  end
64
64
 
65
65
  # Intersection of this layer and +method_layer+.
@@ -74,8 +74,8 @@ module OGR
74
74
  # that will be created from the fields of the input Layer.
75
75
  # @option options [String] method_prefix Set a prefix for the field names
76
76
  # that will be created from the fields of the method Layer.
77
- def intersection(method_layer, **options, &progress)
78
- run_layer_method(:OGR_L_Intersection, method_layer, **options, &progress)
77
+ def intersection(method_layer, output_layer, **options, &progress)
78
+ run_layer_method(:OGR_L_Intersection, method_layer, output_layer, **options, &progress)
79
79
  end
80
80
 
81
81
  # The result layer contains features whose geometries represent areas that
@@ -95,8 +95,8 @@ module OGR
95
95
  # that will be created from the fields of the input Layer.
96
96
  # @option options [String] method_prefix Set a prefix for the field names
97
97
  # that will be created from the fields of the method Layer.
98
- def symmetrical_difference(method_layer, **options, &progress)
99
- run_layer_method(:OGR_L_SymDifference, method_layer, **options, &progress)
98
+ def symmetrical_difference(method_layer, output_layer, **options, &progress)
99
+ run_layer_method(:OGR_L_SymDifference, method_layer, output_layer, **options, &progress)
100
100
  end
101
101
 
102
102
  # The result layer contains features whose geometries represent areas that
@@ -115,8 +115,8 @@ module OGR
115
115
  # that will be created from the fields of the input Layer.
116
116
  # @option options [String] method_prefix Set a prefix for the field names
117
117
  # that will be created from the fields of the method Layer.
118
- def union(method_layer, **options, &progress)
119
- run_layer_method(:OGR_L_Union, method_layer, **options, &progress)
118
+ def union(method_layer, output_layer, **options, &progress)
119
+ run_layer_method(:OGR_L_Union, method_layer, output_layer, **options, &progress)
120
120
  end
121
121
 
122
122
  # Update this layer with features from the update layer. The result layer
@@ -136,18 +136,18 @@ module OGR
136
136
  # that will be created from the fields of the input Layer.
137
137
  # @option options [String] method_prefix Set a prefix for the field names
138
138
  # that will be created from the fields of the method Layer.
139
- def update(method_layer, **options, &progress)
140
- run_layer_method(:OGR_L_Update, method_layer, **options, &progress)
139
+ def update(method_layer, output_layer, **options, &progress)
140
+ run_layer_method(:OGR_L_Update, method_layer, output_layer, **options, &progress)
141
141
  end
142
142
 
143
143
  private
144
144
 
145
- def run_layer_method(method_name, method_layer, **options, &progress)
145
+ def run_layer_method(method_name, method_layer, output_layer, **options, &progress)
146
146
  method_layer_ptr = GDAL._pointer(OGR::Layer, method_layer)
147
147
  options_ptr = GDAL::Options.pointer(options)
148
- result_layer_ptr = FFI::MemoryPointer.new(:OGRLayerH)
148
+ result_layer_ptr = output_layer.c_pointer
149
149
 
150
- ogr_err = FFI::GDAL.send(method_name,
150
+ ogr_err = FFI::OGR::API.send(method_name,
151
151
  @c_pointer,
152
152
  method_layer_ptr,
153
153
  result_layer_ptr,
@@ -156,7 +156,7 @@ module OGR
156
156
  nil)
157
157
  ogr_err.handle_result
158
158
 
159
- OGR::Layer.new(result_layer_ptr)
159
+ output_layer
160
160
  end
161
161
  end
162
162
  end
@@ -1,5 +1,3 @@
1
- require_relative '../geometry'
2
-
3
1
  module OGR
4
2
  module LayerMixins
5
3
  module OGRQueryFilterMethods
@@ -36,7 +36,7 @@ module OGR
36
36
  # @return [Boolean]
37
37
  def transact
38
38
  unless supports_transactions?
39
- fail OGR::UnsupportedOperation, 'This layer does not support transactions.'
39
+ raise OGR::UnsupportedOperation, 'This layer does not support transactions.'
40
40
  end
41
41
 
42
42
  ogr_err = yield
@@ -1,5 +1,5 @@
1
- require_relative '../ffi/ogr'
2
- require_relative '../gdal/logger'
1
+ require_relative '../ogr'
2
+ require_relative '../gdal'
3
3
  require_relative 'spatial_reference_extensions'
4
4
  require_relative 'spatial_reference_mixins/coordinate_system_getter_setters'
5
5
  require_relative 'spatial_reference_mixins/exporters'
@@ -36,31 +36,21 @@ module OGR
36
36
  pointer_array = methods_ptr_ptr.get_array_of_pointer(0, count)
37
37
 
38
38
  list = pointer_array.map(&:read_string).sort
39
- list.map! { |l| l.gsub(/_/, ' ') } if strip_underscores
40
39
 
41
- list
40
+ strip_underscores ? list.map! { |l| l.tr('_', ' ') } : list
42
41
  end
43
42
 
44
43
  # @param projection_method [String] One of
45
44
  # OGR::SpatialReference.projection_methods.
46
45
  # @return [Hash{parameter => Array<String>, user_visible_name => String}]
47
46
  def self.parameter_list(projection_method)
48
- name_ptr = FFI::MemoryPointer.new(:string)
49
- name_ptr_ptr = FFI::MemoryPointer.new(:pointer)
50
- name_ptr_ptr.write_pointer(name_ptr)
51
-
52
- params_ptr_ptr = FFI::OGR::SRSAPI.OPTGetParameterList(projection_method,
53
- name_ptr_ptr)
47
+ name_ptr_ptr = GDAL._pointer_pointer(:string)
48
+ params_ptr_ptr = FFI::OGR::SRSAPI.OPTGetParameterList(projection_method, name_ptr_ptr)
54
49
  count = FFI::CPL::String.CSLCount(params_ptr_ptr)
55
50
 
56
51
  # For some reason #get_array_of_string leaves off the first 6.
57
52
  pointer_array = params_ptr_ptr.get_array_of_pointer(0, count)
58
-
59
- name = if name_ptr_ptr.read_pointer.null?
60
- nil
61
- else
62
- name_ptr_ptr.read_pointer.read_string
63
- end
53
+ name = GDAL._read_pointer_pointer_safely(name_ptr_ptr, :string)
64
54
 
65
55
  {
66
56
  parameters: pointer_array.map(&:read_string).sort,
@@ -73,14 +63,8 @@ module OGR
73
63
  # @param projection_method [String]
74
64
  # @param parameter_name [String]
75
65
  def self.parameter_info(projection_method, parameter_name)
76
- name_ptr = FFI::MemoryPointer.new(:string)
77
- name_ptr_ptr = FFI::MemoryPointer.new(:pointer)
78
- name_ptr_ptr.write_pointer(name_ptr)
79
-
80
- type_ptr = FFI::MemoryPointer.new(:string)
81
- type_ptr_ptr = FFI::MemoryPointer.new(:pointer)
82
- type_ptr_ptr.write_pointer(type_ptr)
83
-
66
+ name_ptr_ptr = GDAL._pointer_pointer(:string)
67
+ type_ptr_ptr = GDAL._pointer_pointer(:string)
84
68
  default_value_ptr = FFI::MemoryPointer.new(:double)
85
69
 
86
70
  result = FFI::OGR::SRSAPI.OPTGetParameterInfo(projection_method, parameter_name,
@@ -88,17 +72,8 @@ module OGR
88
72
 
89
73
  return {} unless result
90
74
 
91
- name = if name_ptr_ptr.read_pointer.null?
92
- nil
93
- else
94
- name_ptr_ptr.read_pointer.read_string
95
- end
96
-
97
- type = if type_ptr_ptr.read_pointer.null?
98
- nil
99
- else
100
- type_ptr_ptr.read_pointer.read_string
101
- end
75
+ name = GDAL._read_pointer_pointer_safely(name_ptr_ptr, :string)
76
+ type = GDAL._read_pointer_pointer_safely(name_ptr_ptr, :string)
102
77
 
103
78
  {
104
79
  type: type,
@@ -144,7 +119,7 @@ module OGR
144
119
 
145
120
  return if @c_pointer && !@c_pointer.null?
146
121
 
147
- fail OGR::CreateFailure, 'Unable to create SpatialReference.'
122
+ raise OGR::CreateFailure, 'Unable to create SpatialReference.'
148
123
  end
149
124
 
150
125
  def destroy!
@@ -177,7 +152,7 @@ module OGR
177
152
  # @return [Boolean]
178
153
  def copy_geog_cs_from(other_spatial_ref)
179
154
  other_spatial_ref_ptr = GDAL._pointer(OGR::SpatialReference, other_spatial_ref)
180
- fail OGR::InvalidSpatialReference if other_spatial_ref_ptr.nil? || other_spatial_ref_ptr.null?
155
+ raise OGR::InvalidSpatialReference if other_spatial_ref_ptr.nil? || other_spatial_ref_ptr.null?
181
156
 
182
157
  ogr_err = FFI::OGR::SRSAPI.OSRCopyGeogCSFrom(@c_pointer, other_spatial_ref_ptr)
183
158