ffi-gdal 0.0.4 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -1
  3. data/Rakefile +12 -1
  4. data/TODO.md +11 -0
  5. data/ffi-gdal.gemspec +2 -2
  6. data/lib/ext/error_symbols.rb +59 -0
  7. data/lib/ext/float_ext.rb +15 -0
  8. data/lib/ext/narray_ext.rb +16 -0
  9. data/lib/ext/to_bool.rb +2 -0
  10. data/lib/ffi-gdal.rb +139 -4
  11. data/lib/ffi/{gdal/cpl_conv.rb → cpl/conv_h.rb} +2 -3
  12. data/lib/ffi/{gdal/cpl_error.rb → cpl/error_h.rb} +1 -25
  13. data/lib/ffi/cpl/minixml_h.rb +14 -0
  14. data/lib/ffi/{gdal/cpl_string.rb → cpl/string_h.rb} +0 -25
  15. data/lib/ffi/{gdal/cpl_vsi.rb → cpl/vsi_h.rb} +0 -0
  16. data/lib/ffi/cpl/xml_node.rb +13 -0
  17. data/lib/ffi/gdal.rb +57 -593
  18. data/lib/ffi/gdal/alg_h.rb +127 -0
  19. data/lib/ffi/gdal/gdal_grid_data_metrics_options.rb +14 -0
  20. data/lib/ffi/gdal/gdal_grid_inverse_distance_to_a_power_options.rb +19 -0
  21. data/lib/ffi/gdal/gdal_grid_moving_average_options.rb +14 -0
  22. data/lib/ffi/gdal/gdal_grid_nearest_neighbor_options.rb +13 -0
  23. data/lib/ffi/gdal/gdal_h.rb +683 -0
  24. data/lib/ffi/gdal/gdal_rpc_info.rb +27 -0
  25. data/lib/ffi/gdal/gdal_transformer_info.rb +14 -0
  26. data/lib/ffi/gdal/gdal_warp_options.rb +43 -0
  27. data/lib/ffi/gdal/grid_h.rb +51 -0
  28. data/lib/ffi/gdal/version.rb +1 -1
  29. data/lib/ffi/gdal/warper_h.rb +48 -0
  30. data/lib/ffi/ogr.rb +12 -0
  31. data/lib/ffi/ogr/api_h.rb +553 -0
  32. data/lib/ffi/ogr/core_h.rb +148 -0
  33. data/lib/ffi/ogr/featurestyle_h.rb +22 -0
  34. data/lib/ffi/ogr/geocoding_h.rb +21 -0
  35. data/lib/ffi/ogr/ogr_contour_writer_info.rb +14 -0
  36. data/lib/ffi/ogr/ogr_envelope.rb +12 -0
  37. data/lib/ffi/ogr/ogr_envelope_3d.rb +14 -0
  38. data/lib/ffi/ogr/ogr_field.rb +50 -0
  39. data/lib/ffi/ogr/ogr_style_param.rb +12 -0
  40. data/lib/ffi/ogr/ogr_style_value.rb +13 -0
  41. data/lib/ffi/ogr/srs_api_h.rb +325 -0
  42. data/lib/gdal/color_entry.rb +47 -0
  43. data/lib/gdal/color_entry_extensions.rb +30 -0
  44. data/lib/gdal/color_interpretation.rb +15 -0
  45. data/lib/gdal/color_table.rb +146 -0
  46. data/lib/gdal/color_table_extensions.rb +47 -0
  47. data/lib/gdal/color_table_types/cmyk.rb +25 -0
  48. data/lib/gdal/color_table_types/gray.rb +9 -0
  49. data/lib/gdal/color_table_types/hls.rb +21 -0
  50. data/lib/gdal/color_table_types/rgb.rb +25 -0
  51. data/lib/gdal/data_type.rb +38 -0
  52. data/lib/gdal/dataset.rb +437 -0
  53. data/lib/gdal/dataset_extensions.rb +496 -0
  54. data/lib/gdal/driver.rb +244 -0
  55. data/lib/gdal/driver_extensions.rb +56 -0
  56. data/lib/gdal/environment_methods.rb +43 -0
  57. data/lib/{ffi-gdal → gdal}/exceptions.rb +4 -1
  58. data/lib/gdal/geo_transform.rb +188 -0
  59. data/lib/gdal/geo_transform_extensions.rb +90 -0
  60. data/lib/gdal/logger.rb +7 -0
  61. data/lib/{ffi-gdal → gdal}/major_object.rb +15 -14
  62. data/lib/gdal/options.rb +49 -0
  63. data/lib/gdal/raster_attribute_table.rb +185 -0
  64. data/lib/gdal/raster_attribute_table_extensions.rb +40 -0
  65. data/lib/{ffi-gdal → gdal}/raster_band.rb +227 -99
  66. data/lib/gdal/raster_band_extensions.rb +198 -0
  67. data/lib/{ffi-gdal → gdal}/version_info.rb +8 -0
  68. data/lib/gdal/warp_operation.rb +96 -0
  69. data/lib/ogr/coordinate_transformation.rb +108 -0
  70. data/lib/ogr/data_source.rb +172 -0
  71. data/lib/ogr/data_source_extensions.rb +32 -0
  72. data/lib/ogr/driver.rb +119 -0
  73. data/lib/ogr/envelope.rb +80 -0
  74. data/lib/ogr/envelope_extensions.rb +92 -0
  75. data/lib/ogr/exceptions.rb +35 -0
  76. data/lib/ogr/feature.rb +212 -0
  77. data/lib/ogr/feature_definition.rb +120 -0
  78. data/lib/ogr/feature_definition_extensions.rb +36 -0
  79. data/lib/ogr/feature_extensions.rb +31 -0
  80. data/lib/ogr/field.rb +91 -0
  81. data/lib/ogr/field_extensions.rb +23 -0
  82. data/lib/ogr/geocoding_session.rb +84 -0
  83. data/lib/ogr/geometry.rb +617 -0
  84. data/lib/ogr/geometry_extensions.rb +60 -0
  85. data/lib/ogr/geometry_types/collection.rb +45 -0
  86. data/lib/ogr/geometry_types/curve.rb +120 -0
  87. data/lib/ogr/geometry_types/surface.rb +20 -0
  88. data/lib/ogr/layer.rb +226 -0
  89. data/lib/ogr/layer_extensions.rb +55 -0
  90. data/lib/ogr/line_string.rb +7 -0
  91. data/lib/ogr/linear_ring.rb +6 -0
  92. data/lib/ogr/multi_line_string.rb +9 -0
  93. data/lib/ogr/multi_point.rb +7 -0
  94. data/lib/ogr/multi_polygon.rb +14 -0
  95. data/lib/ogr/point.rb +89 -0
  96. data/lib/ogr/polygon.rb +9 -0
  97. data/lib/ogr/spatial_reference.rb +723 -0
  98. data/lib/ogr/spatial_reference_extensions.rb +32 -0
  99. data/lib/ogr/style_table.rb +17 -0
  100. data/lib/ogr/style_table_extensions.rb +16 -0
  101. data/spec/{ffi-gdal/integration → integration}/color_table_info_spec.rb +1 -1
  102. data/spec/{ffi-gdal/integration → integration}/dataset_info_spec.rb +0 -0
  103. data/spec/{ffi-gdal/integration → integration}/driver_info_spec.rb +1 -1
  104. data/spec/{ffi-gdal/integration → integration}/geo_transform_info_spec.rb +0 -0
  105. data/spec/{ffi-gdal/integration → integration}/raster_attribute_table_info_spec.rb +1 -1
  106. data/spec/{ffi-gdal/integration → integration}/raster_band_info_spec.rb +5 -5
  107. data/spec/spec_helper.rb +4 -1
  108. data/spec/support/shapefiles/states_21basic/states.prj +1 -0
  109. data/spec/support/shapefiles/states_21basic/states.sbn +0 -0
  110. data/spec/support/shapefiles/states_21basic/states.sbx +0 -0
  111. data/spec/support/shapefiles/states_21basic/states.shp +0 -0
  112. data/spec/support/worldfiles/SR_50M/SR_50M.VERSION.txt +1 -0
  113. data/spec/support/worldfiles/SR_50M/SR_50M.prj +1 -0
  114. data/spec/support/worldfiles/SR_50M/SR_50M.tfw +6 -0
  115. data/spec/{ext/cpl_error_symbols_spec.rb → unit/ext/error_symbols_spec.rb} +1 -1
  116. data/spec/unit/gdal/color_table_spec.rb +146 -0
  117. data/spec/unit/ogr/layer_spec.rb +97 -0
  118. data/spec/unit/ogr/linear_ring_spec.rb +111 -0
  119. data/spec/unit/ogr/point_spec.rb +321 -0
  120. data/spec/{ffi-gdal/unit → unit}/version_info_spec.rb +1 -1
  121. data/testing_gdal.rb +168 -0
  122. data/testing_gdalwarp.rb +91 -0
  123. data/testing_layer_to_layer.rb +35 -0
  124. data/testing_ndvi.rb +76 -0
  125. data/testing_nir.rb +77 -0
  126. data/testing_ogr.rb +63 -0
  127. metadata +167 -59
  128. data/lib/ext/cpl_error_symbols.rb +0 -37
  129. data/lib/ffi-gdal/color_table.rb +0 -59
  130. data/lib/ffi-gdal/dataset.rb +0 -359
  131. data/lib/ffi-gdal/driver.rb +0 -151
  132. data/lib/ffi-gdal/geo_transform.rb +0 -137
  133. data/lib/ffi-gdal/raster_attribute_table.rb +0 -78
  134. data/lib/ffi/gdal/ogr_api.rb +0 -21
  135. data/lib/ffi/gdal/ogr_core.rb +0 -195
  136. data/lib/ffi/gdal/ogr_srs_api.rb +0 -44
  137. data/meow.rb +0 -144
  138. data/rubby.rb +0 -224
@@ -0,0 +1,120 @@
1
+ require_relative '../ffi/ogr'
2
+ require_relative 'feature_definition_extensions'
3
+ require_relative 'field'
4
+
5
+ module OGR
6
+ class FeatureDefinition
7
+ include FeatureDefinitionExtensions
8
+
9
+ # @param name [String]
10
+ def self.create(name)
11
+ feature_defn_pointer = FFI::GDAL.OGR_FD_Create(name)
12
+ return nil if feature_defn_pointer.null?
13
+
14
+ new(feature_defn_pointer)
15
+ end
16
+
17
+ # @param feature_definition [String]
18
+ def initialize(feature_definition)
19
+ @feature_definition_pointer = GDAL._pointer(OGR::FeatureDefinition,
20
+ feature_definition)
21
+
22
+ close_me = -> { FFI::GDAL.OGR_FD_Destroy(@feature_definition_pointer) }
23
+ ObjectSpace.define_finalizer self, close_me
24
+ end
25
+
26
+ def c_pointer
27
+ @feature_definition_pointer
28
+ end
29
+
30
+ # @return [String]
31
+ def name
32
+ FFI::GDAL.OGR_FD_GetName(@feature_definition_pointer)
33
+ end
34
+
35
+ # @return [Fixnum]
36
+ def field_count
37
+ FFI::GDAL.OGR_FD_GetFieldCount(@feature_definition_pointer)
38
+ end
39
+
40
+ # @param index [Fixnum]
41
+ # @return [OGR::Field]
42
+ def field(index)
43
+ field_ptr = FFI::GDAL.OGR_FD_GetFieldDefn(@feature_definition_pointer, index)
44
+ return nil if field_ptr.null?
45
+
46
+ OGR::Field.new(field_ptr)
47
+ end
48
+
49
+ # @param name [String]
50
+ # @return [Fixnum] -1 if no match found
51
+ def field_index(name)
52
+ FFI::GDAL.OGR_FD_GetFieldIndex(@feature_definition_pointer, name)
53
+ end
54
+
55
+ # @return [FFI::GDAL::OGRwkbGeometryType]
56
+ def geometry_type
57
+ FFI::GDAL.OGR_FD_GetGeomType(@feature_definition_pointer)
58
+ end
59
+
60
+ # @param new_type [FFI::GDAL::OGRwkbGeometryType]
61
+ def geometry_type=(new_type)
62
+ FFI::GDAL.OGR_FD_SetGeomType(@feature_definition_pointer, new_type)
63
+ end
64
+
65
+ # @return [Boolean]
66
+ def geometry_ignored?
67
+ FFI::GDAL.OGR_FD_IsGeometryIgnored(@feature_definition_pointer)
68
+ end
69
+
70
+ # @param ignore [Boolean]
71
+ def ignore_geometry!(ignore)
72
+ FFI::GDAL.OGR_FD_SetGeometryIgnored(@feature_definition_pointer, ignore)
73
+ end
74
+
75
+ # @return [Boolean]
76
+ def style_ignored?
77
+ FFI::GDAL.OGR_FD_IsStyleIgnored(@feature_definition_pointer)
78
+ end
79
+
80
+ # @param ignore [Boolean]
81
+ def ignore_style!(ignore)
82
+ FFI::GDAL.OGR_FD_SetStyleIgnored(@feature_definition_pointer, ignore)
83
+ end
84
+
85
+ # @return [Fixnum]
86
+ def geometry_field_count
87
+ FFI::GDAL.OGR_FD_GetGeomFieldCount(@feature_definition_pointer)
88
+ end
89
+
90
+ # @param index [Fixnum]
91
+ # @return [OGR::Field]
92
+ def geometry_field_definition(index)
93
+ field_ptr = FFI::GDAL.OGR_FD_GetGeomFieldDefn(@feature_definition_pointer, index)
94
+ return nil if field_ptr.null?
95
+
96
+ OGR::Field.new(field_ptr)
97
+ end
98
+
99
+ # @param name [String]
100
+ # @return [Fixnum]
101
+ def geometry_field_index(name)
102
+ FFI::GDAL.OGR_FD_GetGeomFieldIndex(@feature_definition_pointer, name)
103
+ end
104
+
105
+ # @param name [String]
106
+ # @return [OGR::Field]
107
+ def geometry_field_by_name(name)
108
+ geometry_field_definition(geometry_field_index(name))
109
+ end
110
+
111
+ # @param other_feature_defintion [OGR::Feature, FFI::Pointer]
112
+ # @return [Boolean]
113
+ def same?(other_feature_defintion)
114
+ fd_ptr = GDAL._pointer(OGR::FeatureDefinition, other_feature_defintion)
115
+
116
+ FFI::GDAL.OGR_FD_IsSame(@feature_definition_pointer, fd_ptr)
117
+ end
118
+ alias_method :==, :same?
119
+ end
120
+ end
@@ -0,0 +1,36 @@
1
+ require 'json'
2
+
3
+ module OGR
4
+ module FeatureDefinitionExtensions
5
+
6
+ # @return [Array<OGR::Field>]
7
+ def fields
8
+ 0.upto(field_count - 1).map do |i|
9
+ field(i)
10
+ end
11
+ end
12
+
13
+ # @param name [String]
14
+ # @return [OGR::Field]
15
+ def field_by_name(name)
16
+ field(field_index(name))
17
+ end
18
+
19
+ # @return [Hash]
20
+ def as_json
21
+ {
22
+ field_count: field_count,
23
+ fields: fields.map(&:as_json),
24
+ geometry_field_count: geometry_field_count,
25
+ geometry_type: geometry_type,
26
+ name: name,
27
+ is_style_ignored: style_ignored?
28
+ }
29
+ end
30
+
31
+ # @return [String]
32
+ def to_json
33
+ as_json.to_json
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ require 'json'
2
+
3
+ module OGR
4
+ module FeatureExtensions
5
+
6
+ # @return [Array<OGR::Field>]
7
+ def fields
8
+ 0.upto(field_count - 1).map do |i|
9
+ field(i)
10
+ end
11
+ end
12
+
13
+ # @return [Hash]
14
+ def as_json
15
+ {
16
+ definition: definition,
17
+ fid: fid,
18
+ field_count: field_count,
19
+ fields: fields.map(&:as_json),
20
+ geometry: geometry.as_json,
21
+ geometry_field_count: geometry_field_count,
22
+ style_string: style_string
23
+ }
24
+ end
25
+
26
+ # @return [String]
27
+ def to_json
28
+ as_json.to_json
29
+ end
30
+ end
31
+ end
data/lib/ogr/field.rb ADDED
@@ -0,0 +1,91 @@
1
+ require_relative '../ffi/ogr'
2
+ require_relative 'field_extensions'
3
+
4
+ module OGR
5
+ class Field
6
+ include FieldExtensions
7
+
8
+ # @param name [String]
9
+ # @param type [FFI::GDAL::OGRFieldType]
10
+ # @return [OGR::Field]
11
+ def self.create(name, type)
12
+ field_ptr = FFI::GDAL.OGR_Fld_Create(name, type)
13
+ return nil if field_ptr.null?
14
+
15
+ new(field_ptr)
16
+ end
17
+
18
+ # @param field [OGR::Field, FFI::Pointer]
19
+ def initialize(field)
20
+ @field_pointer = GDAL._pointer(OGR::Field, field)
21
+ end
22
+
23
+ def c_pointer
24
+ @field_pointer
25
+ end
26
+
27
+ def destroy!
28
+ FFI::GDAL.OGR_Fld_Destroy(@field_pointer)
29
+ end
30
+
31
+ # @return [String]
32
+ def name
33
+ FFI::GDAL.OGR_Fld_GetNameRef(@field_pointer)
34
+ end
35
+
36
+ # @param new_value [String]
37
+ def name=(new_value)
38
+ FFI::GDAL.OGR_Fld_SetName(@field_pointer, new_value)
39
+ end
40
+
41
+ # @return [FFI::GDAL::OGRJustification]
42
+ def justification
43
+ FFI::GDAL.OGR_Fld_GetJustify(@field_pointer)
44
+ end
45
+
46
+ # @param new_value [FFI::GDAL::OGRJustification]
47
+ def justification=(new_value)
48
+ FFI::GDAL.OGR_Fld_SetJustify(@field_pointer, new_value)
49
+ end
50
+
51
+ # @return [Fixnum]
52
+ def precision
53
+ FFI::GDAL.OGR_Fld_GetPrecision(@field_pointer)
54
+ end
55
+
56
+ # @param new_value [Fixnum]
57
+ def precision=(new_value)
58
+ FFI::GDAL.OGR_Fld_SetPrecision(@field_pointer, new_value)
59
+ end
60
+
61
+ # @return [FFI::GDAL::OGRFieldType]
62
+ def type
63
+ FFI::GDAL.OGR_Fld_GetType(@field_pointer)
64
+ end
65
+
66
+ # @param new_value [FFI::GDAL::OGRFieldType]
67
+ def type=(new_value)
68
+ FFI::GDAL.OGR_Fld_SetType(@field_pointer, new_value)
69
+ end
70
+
71
+ # @return [Fixnum]
72
+ def width
73
+ FFI::GDAL.OGR_Fld_GetWidth(@field_pointer)
74
+ end
75
+
76
+ # @param new_value [Fixnum]
77
+ def width=(new_value)
78
+ FFI::GDAL.OGR_Fld_SetWidth(@field_pointer, new_value)
79
+ end
80
+
81
+ # @return [Boolean]
82
+ def ignored?
83
+ FFI::GDAL.OGR_Fld_IsIgnored(@field_pointer)
84
+ end
85
+
86
+ # @param new_value [Boolean]
87
+ def ignore=(new_value)
88
+ FFI::GDAL.OGR_Fld_SetIgnored(@field_pointer, new_value)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,23 @@
1
+ require 'json'
2
+
3
+ module OGR
4
+ module FieldExtensions
5
+
6
+ # @return [Hash]
7
+ def as_json
8
+ {
9
+ is_ignored: ignored?,
10
+ justification: justification,
11
+ name: name,
12
+ precision: precision,
13
+ type: type,
14
+ width: width
15
+ }
16
+ end
17
+
18
+ # @return [String]
19
+ def to_json
20
+ as_json.to_json
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,84 @@
1
+ require_relative 'layer'
2
+
3
+ module OGR
4
+
5
+ # Geocode things! http://www.gdal.org/ogr__geocoding_8h.html
6
+ class GeocodingSession
7
+ # @param options [Hash]
8
+ # @option options cache_file [String] Name of the file to write the cache
9
+ # to.
10
+ # @option options read_cache [Boolean] Defaults to true.
11
+ # @option options write_cache [Boolean] Defaults to true.
12
+ # @option options service [String] "MAPQUEST_NOMINATIM", "YAHOO",
13
+ # "GEONAMES", "BING", or other value.
14
+ # @option options email [String] Required for the GEONAMES service.
15
+ # @option options key [String] Required for the BING service.
16
+ # @option options application [String] Sets the User-Agent request header.
17
+ # Defaults to the GDAL version string.
18
+ # @option options language [String] Sets the Accept-Language request
19
+ # header.
20
+ # @option options delay [Float] Minimum delay, in seconds, between
21
+ # consecutive requests. Defaults to 1.0.
22
+ # @option options query_template [String] URL template for GET requests.
23
+ # Must contain one and only one occurrence of %s. If not specified, the
24
+ # URL template is hard-coded.
25
+ # @option options reverse_query_template [String] Template to use for
26
+ # reverse geocoding.
27
+ def initialize(**options)
28
+ converted_options = options.each_with_object({}) do |(k, v), obj|
29
+ key = "OGR_GEOCODE_#{k.to_s.upcase}"
30
+ obj[key] = v
31
+ end
32
+
33
+ options_ptr = GDAL::Options.pointer(converted_options)
34
+
35
+ @geocoding_session_pointer = FFI::GDAL.OGRGeocodeCreateSession(options_ptr)
36
+ end
37
+
38
+ def c_pointer
39
+ @geocoding_session_pointer
40
+ end
41
+
42
+ def destroy!
43
+ FFI::GDAL.OGRGeocodeDestroySession(@geocoding_session_pointer)
44
+ end
45
+
46
+ # @param query [String]
47
+ # @param options [Hash]
48
+ # @option options addressdetails [Boolean] +true+ to include a breakdown of
49
+ # the adddress into elements. Only works with some geocoding services.
50
+ # @option options countrycodes [Array<String, Symbol>] Limit the search to a
51
+ # specific country or countries. Only works with some geocoding services.
52
+ # @option options limit [Fixnum] Limit the number of records returned. Only
53
+ # works with some geocoding services.
54
+ # @option options raw_feature ["YES"] Adds a raw feature to the returned
55
+ # feature that includes that raw XML response body.
56
+ # @option extra_query_parameters [String] Adds params to the GET request.
57
+ # @return [OGR::Layer, nil]
58
+ def geocode(query, **options)
59
+ options_ptr = GDAL::Options.pointer(options)
60
+ layer_ptr = FFI::GDAL.OGRGeocode(@geocoding_session_pointer, query, nil,
61
+ options_ptr)
62
+ return nil if layer_ptr.null?
63
+
64
+ OGR::Layer.new(layer_ptr)
65
+ end
66
+
67
+ # @param lon [Float]
68
+ # @param lat [Float]
69
+ # @param options [Hash]
70
+ # @option options zoom [Float] Only used by the Nominatim service.
71
+ # @option options raw_feature ["YES"] Adds a raw feature to the returned
72
+ # feature that includes that raw XML response body.
73
+ # @option extra_query_parameters [String] Adds params to the GET request.
74
+ # @return [OGR::Layer]
75
+ def reverse_geocode(lon, lat, **options)
76
+ options_ptr = GDAL::Options.pointer(options)
77
+ layer_ptr = FFI::GDAL.OGRGeocodeReverse(@geocoding_session_pointer, lon,
78
+ lat, options_ptr)
79
+ return nil if layer_ptr.null?
80
+
81
+ OGR::Layer.new(layer_ptr)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,617 @@
1
+ require_relative 'envelope'
2
+ require_relative 'geometry_extensions'
3
+
4
+ module OGR
5
+ class Geometry
6
+ include GDAL::Logger
7
+ include GeometryExtensions
8
+
9
+ # @param type [FFI::GDAL::OGRwkbGeometryType]
10
+ # @return [OGR::Geometry]
11
+ def self.create(type)
12
+ geometry_pointer = FFI::GDAL.OGR_G_CreateGeometry(type)
13
+ return nil if geometry_pointer.null?
14
+ geometry_pointer.autorelease = false
15
+
16
+ _to_geometry_type(geometry_pointer)
17
+ end
18
+
19
+ def self._to_geometry_type(geometry)
20
+ geometry = if geometry.kind_of?(OGR::Geometry)
21
+ geometry
22
+ else
23
+ new(geometry)
24
+ end
25
+ case geometry.name
26
+ when 'POINT' then OGR::Point.new(geometry.c_pointer)
27
+ when 'LINESTRING' then OGR::LineString.new(geometry.c_pointer)
28
+ when 'LINEARRING' then OGR::LinearRing.new(geometry.c_pointer)
29
+ when 'POLYGON' then OGR::Polygon.new(geometry.c_pointer)
30
+ when 'MULTIPOINT' then OGR::MultiPoint.new(geometry.c_pointer)
31
+ when 'MULTILINESTRING' then OGR::MultiLineString.new(geometry.c_pointer)
32
+ when 'MULTIPOLYGON' then OGR::MultiPolygon.new(geometry.c_pointer)
33
+ else
34
+ geometry
35
+ end
36
+ end
37
+
38
+ # @param wkt_data [String]
39
+ # @param spatial_reference [FFI::Pointer] Optional spatial reference
40
+ # to assign to the new geometry.
41
+ # @return [OGR::Geometry]
42
+ def self.create_from_wkt(wkt_data, spatial_reference=nil)
43
+ wkt_data_pointer = FFI::MemoryPointer.from_string(wkt_data)
44
+ wkt_pointer_pointer = FFI::MemoryPointer.new(:pointer)
45
+ wkt_pointer_pointer.write_pointer(wkt_data_pointer)
46
+
47
+ spatial_ref_pointer = if spatial_reference
48
+ GDAL._pointer(OGR::SpatialReference, spatial_reference)
49
+ else
50
+ FFI::MemoryPointer.new(:pointer)
51
+ end
52
+
53
+ geometry_ptr = FFI::MemoryPointer.new(:pointer)
54
+ geometry_ptr_ptr = FFI::MemoryPointer.new(:pointer)
55
+ geometry_ptr_ptr.write_pointer(geometry_ptr)
56
+
57
+ FFI::GDAL.OGR_G_CreateFromWkt(wkt_pointer_pointer,
58
+ spatial_ref_pointer, geometry_ptr_ptr)
59
+
60
+ return nil if geometry_ptr_ptr.null? ||
61
+ geometry_ptr_ptr.read_pointer.null?
62
+ geometry_ptr_ptr.read_pointer.nil?
63
+
64
+ # Not assigning here makes tests crash when using a #let.
65
+ geometry = _to_geometry_type(geometry_ptr_ptr.read_pointer)
66
+ end
67
+
68
+ # @param gml_data [String]
69
+ # @return [OGR::Geometry]
70
+ def self.create_from_gml(gml_data)
71
+ geometry_pointer = FFI::GDAL.OGR_G_CreateFromGML(gml_data)
72
+
73
+ new(geometry_pointer)
74
+ end
75
+
76
+ # @param json_data [String]
77
+ # @return [OGR::Geometry]
78
+ def self.create_from_json(json_data)
79
+ geometry_pointer = FFI::GDAL.OGR_G_CreateGeometryFromJson(json_data)
80
+
81
+ new(geometry_pointer)
82
+ end
83
+
84
+ # @return [String]
85
+ def self.type_to_name(type)
86
+ FFI::GDAL.OGRGeometryTypeToName(type)
87
+ end
88
+
89
+ # @param geometry [OGR::Geometry, FFI::Pointer]
90
+ def initialize(geometry)
91
+ @geometry_pointer = GDAL._pointer(OGR::Geometry, geometry)
92
+ @geometry_pointer.autorelease = false
93
+
94
+ close_me = -> {
95
+ if @geometry_pointer && !@geometry_pointer.null?
96
+ FFI::GDAL.OGR_G_DestroyGeometry(@geometry_pointer)
97
+ end
98
+ }
99
+ ObjectSpace.define_finalizer self, close_me
100
+ end
101
+
102
+ def c_pointer
103
+ @geometry_pointer
104
+ end
105
+
106
+ # If this geometry is a container, this adds +geometry+ to the container.
107
+ # If this is a Polygon, +geometry+ must be a LinearRing. If the Polygon is
108
+ # empty, the first added +geometry+ will be the exterior ring. Subsequent
109
+ # geometries added will be interior rings.
110
+ #
111
+ # @param sub_geometry [OGR::Geometry, FFI::Pointer]
112
+ # @return +true+ if successful, otherwise raises an OGR exception.
113
+ def add_geometry(sub_geometry)
114
+ ogr_err = FFI::GDAL.OGR_G_AddGeometry(@geometry_pointer, pointer_from(sub_geometry))
115
+
116
+ ogr_err.to_ruby
117
+ end
118
+
119
+ # @param sub_geometry [OGR::Geometry, FFI::Pointer]
120
+ # @return +true+ if successful, otherwise raises an OGR exception.
121
+ def add_directly(sub_geometry)
122
+ ogr_err = FFI::GDAL.OGR_G_AddGeometryDirectly(@geometry_pointer, pointer_from(sub_geometry))
123
+
124
+ ogr_err.to_ruby
125
+ end
126
+
127
+ # @param geometry_index [Fixnum]
128
+ # @param delete [Boolean]
129
+ # @return +true+ if successful, otherwise raises an OGR exception.
130
+ def remove!(geometry_index, delete=true)
131
+ ogr_err = FFI::GDAL.OGR_G_RemoveGeometry(@geometry_pointer, geometry_index, delete)
132
+
133
+ ogr_err.to_ruby
134
+ end
135
+
136
+ # Clears all information from the geometry.
137
+ def empty!
138
+ FFI::GDAL.OGR_G_Empty(@geometry_pointer)
139
+ end
140
+
141
+ # @return [Fixnum] 0 for points, 1 for lines, 2 for surfaces.
142
+ def dimension
143
+ FFI::GDAL.OGR_G_GetDimension(@geometry_pointer)
144
+ end
145
+
146
+ # The dimension of coordinates in this geometry (i.e. 2d vs 3d).
147
+ #
148
+ # @return [Fixnum] 2 or 3, but 0 in the case of an empty point.
149
+ def coordinate_dimension
150
+ FFI::GDAL.OGR_G_GetCoordinateDimension(@geometry_pointer)
151
+ end
152
+
153
+ # @param new_coordinate_dimension [Fixnum]
154
+ def coordinate_dimension=(new_coordinate_dimension)
155
+ unless [2, 3].include?(new_coordinate_dimension)
156
+ raise "Can't set coordinate to #{new_coordinate_dimension}. Must be 2 or 3."
157
+ end
158
+
159
+ FFI::GDAL.OGR_G_SetCoordinateDimension(@geometry_pointer, new_coordinate_dimension)
160
+ end
161
+
162
+ # @return [OGR::Envelope]
163
+ def envelope
164
+ return @envelope if @envelope
165
+
166
+ case coordinate_dimension
167
+ when 2
168
+ envelope = FFI::GDAL::OGREnvelope.new
169
+ FFI::GDAL.OGR_G_GetEnvelope(@geometry_pointer, envelope)
170
+ when 3
171
+ envelope = FFI::GDAL::OGREnvelope3D.new
172
+ FFI::GDAL.OGR_G_GetEnvelope3D(@geometry_pointer, envelope)
173
+ when 0
174
+ return nil
175
+ else
176
+ raise 'Unknown envelope dimension.'
177
+ end
178
+
179
+ return nil if envelope.null?
180
+
181
+ @envelope = OGR::Envelope.new(envelope)
182
+ end
183
+
184
+ # @return [FFI::GDAL::OGRwkbGeometryType]
185
+ def type
186
+ FFI::GDAL.OGR_G_GetGeometryType(@geometry_pointer)
187
+ end
188
+
189
+ # @return [String]
190
+ def type_to_name
191
+ FFI::GDAL.OGRGeometryTypeToName(type)
192
+ end
193
+
194
+ # @return [String]
195
+ def name
196
+ FFI::GDAL.OGR_G_GetGeometryName(@geometry_pointer)
197
+ end
198
+
199
+ # @return [Fixnum]
200
+ def count
201
+ FFI::GDAL.OGR_G_GetGeometryCount(@geometry_pointer)
202
+ end
203
+
204
+ # @return [Fixnum]
205
+ def point_count
206
+ return 0 if empty?
207
+
208
+ FFI::GDAL.OGR_G_GetPointCount(@geometry_pointer)
209
+ end
210
+
211
+ # @return [Fixnum]
212
+ # @todo This regularly crashes, so disabling it.
213
+ def centroid
214
+ raise NotImplementedError, '#centroid not yet implemented.'
215
+
216
+ point = OGR::Geometry.create(:wkbPoint)
217
+ FFI::GDAL.OGR_G_Centroid(@geometry_pointer, point.c_pointer)
218
+ return nil if point.c_pointer.null?
219
+
220
+ point
221
+ end
222
+
223
+ # # Dump as WKT to the give +file+.
224
+ #
225
+ # @param file [String] The text file to write to.
226
+ # @param prefix [String] The prefix to put on each line of output.
227
+ # @return [String]
228
+ def dump_readable(file, prefix=nil)
229
+ FFI::GDAL.OGR_G_DumpReadable(@geometry_pointer, file, prefix)
230
+ end
231
+
232
+ # Converts this geometry to a 2D geometry.
233
+ def flatten_to_2d!
234
+ FFI::GDAL.OGR_G_FlattenTo2D(@geometry_pointer)
235
+ end
236
+
237
+ # @param geometry [OGR::Geometry, FFI::Pointer]
238
+ # @return [Boolean]
239
+ def intersects?(geometry)
240
+ FFI::GDAL.OGR_G_Intersects(@geometry_pointer, pointer_from(geometry))
241
+ end
242
+
243
+ # @param geometry [OGR::Geometry, FFI::Pointer]
244
+ # @return [Boolean]
245
+ def equals?(geometry)
246
+ FFI::GDAL.OGR_G_Equals(@geometry_pointer, pointer_from(geometry))
247
+ end
248
+ alias_method :==, :equals?
249
+
250
+ # @param geometry [OGR::Geometry, FFI::Pointer]
251
+ # @return [Boolean]
252
+ def disjoint?(geometry)
253
+ FFI::GDAL.OGR_G_Disjoint(@geometry_pointer, pointer_from(geometry))
254
+ end
255
+
256
+ # @param geometry [OGR::Geometry, FFI::Pointer]
257
+ # @return [Boolean]
258
+ def touches?(geometry)
259
+ FFI::GDAL.OGR_G_Touches(@geometry_pointer, geometry.c_pointer)
260
+ end
261
+
262
+ # @param geometry [OGR::Geometry, FFI::Pointer]
263
+ # @return [Boolean]
264
+ def crosses?(geometry)
265
+ FFI::GDAL.OGR_G_Crosses(@geometry_pointer, pointer_from(geometry))
266
+ end
267
+
268
+ # @param geometry [OGR::Geometry, FFI::Pointer]
269
+ # @return [Boolean]
270
+ def within?(geometry)
271
+ FFI::GDAL.OGR_G_Within(@geometry_pointer, pointer_from(geometry))
272
+ end
273
+
274
+ # @param geometry [OGR::Geometry, FFI::Pointer]
275
+ # @return [Boolean]
276
+ def contains?(geometry)
277
+ FFI::GDAL.OGR_G_Contains(@geometry_pointer, pointer_from(geometry))
278
+ end
279
+
280
+ # @param geometry [OGR::Geometry, FFI::Pointer]
281
+ # @return [Boolean]
282
+ def overlaps?(geometry)
283
+ FFI::GDAL.OGR_G_Overlaps(@geometry_pointer, pointer_from(geometry))
284
+ end
285
+
286
+ # @return [Boolean]
287
+ def empty?
288
+ FFI::GDAL.OGR_G_IsEmpty(@geometry_pointer)
289
+ end
290
+
291
+ # @return [Boolean]
292
+ def valid?
293
+ FFI::GDAL.OGR_G_IsValid(@geometry_pointer)
294
+ end
295
+
296
+ # Returns TRUE if the geometry has no anomalous geometric points, such as
297
+ # self intersection or self tangency. The description of each instantiable
298
+ # geometric class will include the specific conditions that cause an
299
+ # instance of that class to be classified as not simple.
300
+ #
301
+ # @return [Boolean]
302
+ def simple?
303
+ FFI::GDAL.OGR_G_IsSimple(@geometry_pointer)
304
+ end
305
+
306
+ # TRUE if the geometry has no points, otherwise FALSE.
307
+ #
308
+ # @return [Boolean]
309
+ def ring?
310
+ FFI::GDAL.OGR_G_IsRing(@geometry_pointer)
311
+ end
312
+
313
+ # @param other_geometry [OGR::Geometry]
314
+ # @return [OGR::Geometry]
315
+ # @todo This regularly crashes, so disabling it.
316
+ def intersection(other_geometry)
317
+ raise NotImplementedError, '#intersection not yet implemented.'
318
+
319
+ return nil unless intersects?(other_geometry)
320
+
321
+ build_geometry do |ptr|
322
+ FFI::GDAL.OGR_G_Intersection(ptr, other_geometry.c_pointer)
323
+ end
324
+ end
325
+
326
+ # @param other_geometry [OGR::Geometry]
327
+ # @return [OGR::Geometry]
328
+ def union(other_geometry)
329
+ build_geometry do |ptr|
330
+ FFI::GDAL.OGR_G_Union(ptr, other_geometry.c_pointer)
331
+ end
332
+ end
333
+
334
+ # If this or any contained geometries has polygon rings that aren't closed,
335
+ # this closes them by adding the starting point at the end.
336
+ def close_rings!
337
+ FFI::GDAL.OGR_G_CloseRings(@geometry_pointer)
338
+ end
339
+
340
+ # Creates a polygon from a set of sparse edges. The newly created geometry
341
+ # will contain a collection of reassembled Polygons.
342
+ #
343
+ # @return [OGR::Geometry] nil if the current geometry isn't a
344
+ # MultiLineString or if it's impossible to reassemble due to topological
345
+ # inconsistencies.
346
+ def polygonize
347
+ build_geometry { |ptr| FFI::GDAL.OGR_G_Polygonize(ptr) }
348
+ end
349
+
350
+ # @param geometry [OGR::Geometry]
351
+ # @return [OGR::Geometry]
352
+ def difference(geometry)
353
+ new_geometry_ptr = FFI::GDAL.OGR_G_Difference(@geometry_pointer, geometry.c_pointer)
354
+ return nil if new_geometry_ptr.null?
355
+
356
+ self.class._to_geometry_type(new_geometry_ptr)
357
+ end
358
+ alias_method :-, :difference
359
+
360
+ # @param geometry [OGR::Geometry]
361
+ # @return [OGR::Geometry]
362
+ def symmetric_difference(geometry)
363
+ new_geometry_ptr = FFI::GDAL.OGR_G_SymDifference(@geometry_pointer, geometry.c_pointer)
364
+ return nil if new_geometry_ptr.null?
365
+
366
+ self.class._to_geometry_type(new_geometry_ptr)
367
+ end
368
+
369
+ # The shortest distance between the two geometries.
370
+ #
371
+ # @param geometry [OGR::Geometry]
372
+ # @return [Float] -1 if an error occurs.
373
+ def distance_to(geometry)
374
+ FFI::GDAL.OGR_G_Distance(@geometry_pointer, geometry.c_pointer)
375
+ end
376
+
377
+ # @return [OGR::SpatialReference]
378
+ def spatial_reference
379
+ return @spatial_reference if @spatial_reference
380
+
381
+ spatial_ref_ptr = FFI::GDAL.OGR_G_GetSpatialReference(@geometry_pointer)
382
+ return nil if spatial_ref_ptr.null?
383
+
384
+ @spatial_reference = OGR::SpatialReference.new(spatial_ref_ptr)
385
+ end
386
+
387
+ # Assigns a spatial reference to this geometry. Any existing spatial
388
+ # reference is replace, but this does not reproject the geometry.
389
+ #
390
+ # @param new_spatial_ref [OGR::SpatialReference, FFI::Pointer]
391
+ def spatial_reference=(new_spatial_ref)
392
+ new_spatial_ref_ptr = GDAL._pointer(OGR::SpatialReference, new_spatial_ref)
393
+
394
+ FFI::GDAL.OGR_G_AssignSpatialReference(@geometry_pointer, new_spatial_ref_ptr)
395
+ end
396
+
397
+ # Transforms the coordinates of this geometry in its current spatial
398
+ # reference system to a new spatial reference system. Normally this means
399
+ # reprojecting the vectors, but it could also include datum shifts, and
400
+ # changes of units.
401
+ #
402
+ # Note that this doesn't require the geometry to have an existing spatial
403
+ # reference system.
404
+ #
405
+ # @param coordinate_transformation [OGR::CoordinateTransformation,
406
+ # FFI::Pointer]
407
+ # @return [Boolean]
408
+ def transform!(coordinate_transformation)
409
+ coord_trans_ptr = GDAL._pointer(OGR::CoordinateTransformation,
410
+ coordinate_transformation)
411
+
412
+ return if coord_trans_ptr.nil? or coord_trans_ptr.null?
413
+
414
+ ogr_err = FFI::GDAL.OGR_G_Transform(@geometry_pointer, coord_trans_ptr)
415
+
416
+ ogr_err.to_ruby
417
+ end
418
+
419
+ # Similar to +#transform+, but this only works if the geometry already has an
420
+ # assigned spatial reference system _and_ is transformable to the target
421
+ # coordinate system.
422
+ #
423
+ # @param new_spatial_ref [OGR::SpatialReference, FFI::Pointer]
424
+ # @return [Boolean]
425
+ def transform_to!(new_spatial_ref)
426
+ new_spatial_ref_ptr = GDAL._pointer(OGR::SpatialReference, new_spatial_ref)
427
+ return nil if new_spatial_ref_ptr.null?
428
+
429
+ ogr_err = FFI::GDAL.OGR_G_TransformTo(@geometry_pointer, new_spatial_ref_ptr)
430
+
431
+ ogr_err.to_ruby
432
+ end
433
+
434
+ # Computes and returns a new, simplified geometry.
435
+ #
436
+ # NOTE: this relies on GDAL having been built against GEOS. If it wasn't,
437
+ # this will fail.
438
+ #
439
+ # @param distance_tolerance [Float]
440
+ # @return [OGR::Geometry]
441
+ def simplify(distance_tolerance)
442
+ build_geometry do |ptr|
443
+ FFI::GDAL.OGR_G_Simplify(ptr, distance_tolerance)
444
+ end
445
+ end
446
+
447
+ # Like +#simplify+, but preserves the geometry's topology.
448
+ #
449
+ # @param distance_tolerance [Float]
450
+ # @return [OGR::Geometry]
451
+ def simplify_preserve_topology(distance_tolerance)
452
+ build_geometry do |ptr|
453
+ FFI::GDAL.OGR_G_SimplifyPreserveTopology(ptr, distance_tolerance)
454
+ end
455
+ end
456
+
457
+ # Modify the geometry so that it has no segments longer than +max_length+.
458
+ #
459
+ # @param max_length [Float]
460
+ def segmentize!(max_length)
461
+ FFI::GDAL.OGR_G_Segmentize(@geometry_pointer, max_length)
462
+ end
463
+
464
+ # @return [OGR::Geometry]
465
+ def boundary
466
+ build_geometry { |ptr| FFI::GDAL.OGR_G_Boundary(ptr) }
467
+ end
468
+
469
+ # @param distance [Float] The buffer distance to be applied.
470
+ # @param quad_segments [Fixnum] The number of segments to use to approximate
471
+ # a 90 degree (quadrant) of curvature.
472
+ # @return [OGR::Geometry]
473
+ def buffer(distance, quad_segments)
474
+ build_geometry do |ptr|
475
+ FFI::GDAL.OGR_G_Buffer(ptr, distance, quad_segments)
476
+ end
477
+ end
478
+
479
+ # @return [OGR::Geometry]
480
+ def convex_hull
481
+ build_geometry { |ptr| FFI::GDAL.OGR_G_ConvexHull(ptr) }
482
+ end
483
+
484
+ # TODO: should this be a class method?
485
+ # @param wkb_data [String] Binary WKB data.
486
+ # @return +true+ if successful, otherwise raises an OGR exception.
487
+ def from_wkb(wkb_data)
488
+ ogr_err = FFI::GDAL.OGR_G_ImportFromWkb(@geometry_pointer, wkb_data, wkb_data.length)
489
+
490
+ ogr_err.to_ruby
491
+ end
492
+
493
+ # The exact number of bytes required to hold the WKB of this object.
494
+ #
495
+ # @return [Fixnum]
496
+ def wkb_size
497
+ FFI::GDAL.OGR_G_WkbSize(@geometry_pointer)
498
+ end
499
+
500
+ # @return [String]
501
+ def to_wkb(byte_order=:wkbXDR)
502
+ output = FFI::MemoryPointer.new(:uchar, wkb_size)
503
+ ogr_err = FFI::GDAL.OGR_G_ExportToWkb(@geometry_pointer, byte_order, output)
504
+ ogr_err.to_ruby
505
+
506
+ output.read_bytes(wkb_size)
507
+ end
508
+
509
+ # TODO: should this be a class method?
510
+ # @param wkt_data [String]
511
+ def from_wkt(wkt_data)
512
+ wkt_data_pointer = FFI::MemoryPointer.from_string(wkt_data)
513
+ wkt_pointer_pointer = FFI::MemoryPointer.new(:pointer)
514
+ wkt_pointer_pointer.write_pointer(wkt_data_pointer)
515
+ ogr_err = FFI::GDAL.OGR_G_ImportFromWkt(@geometry_pointer, wkt_pointer_pointer)
516
+
517
+ ogr_err.to_ruby
518
+ end
519
+
520
+ # @return [String]
521
+ def to_wkt
522
+ output = FFI::MemoryPointer.new(:string)
523
+ ogr_err = FFI::GDAL.OGR_G_ExportToWkt(@geometry_pointer, output)
524
+ ogr_err.to_ruby
525
+
526
+ output.read_pointer.read_string
527
+ end
528
+
529
+ # This geometry expressed as GML in GML basic data types.
530
+ #
531
+ # @return [String]
532
+ def to_gml
533
+ FFI::GDAL.OGR_G_ExportToGML(@geometry_pointer)
534
+ end
535
+
536
+ # @param altitude_mode [String] Value to write in the +altitudeMode+
537
+ # element.
538
+ # @return [String]
539
+ def to_kml(altitude_mode=nil)
540
+ FFI::GDAL.OGR_G_ExportToKML(@geometry_pointer, altitude_mode)
541
+ end
542
+
543
+ # @return [String]
544
+ def to_geo_json
545
+ FFI::GDAL.OGR_G_ExportToJson(@geometry_pointer)
546
+ end
547
+
548
+ # Converts the current geometry to a Polygon geometry. The returned object
549
+ # is a new OGR::Geometry instance.
550
+ #
551
+ # @return [OGR::Geometry]
552
+ def to_polygon
553
+ build_geometry { |ptr| FFI::GDAL.OGR_G_ForceToPolygon(ptr) }
554
+ end
555
+
556
+ # Converts the current geometry to a LineString geometry. The returned
557
+ # object is a new OGR::Geometry instance.
558
+ #
559
+ # @return [OGR::Geometry]
560
+ def to_line_string
561
+ build_geometry { |ptr| FFI::GDAL.OGR_G_ForceToLineString(ptr) }
562
+ end
563
+
564
+ # Converts the current geometry to a MultiPolygon geometry. The returned
565
+ # object is a new OGR::Geometry instance.
566
+ #
567
+ # @return [OGR::Geometry]
568
+ def to_multi_polygon
569
+ build_geometry { |ptr| FFI::GDAL.OGR_G_ForceToMultiPolygon(ptr) }
570
+ end
571
+
572
+ # Converts the current geometry to a MultiPoint geometry. The returned
573
+ # object is a new OGR::Geometry instance.
574
+ #
575
+ # @return [OGR::Geometry]
576
+ def to_multi_point
577
+ build_geometry { |ptr| FFI::GDAL.OGR_G_ForceToMultiPoint(ptr) }
578
+ end
579
+
580
+ # Converts the current geometry to a MultiLineString geometry. The returned
581
+ # object is a new OGR::Geometry instance.
582
+ #
583
+ # @return [OGR::Geometry]
584
+ def to_multi_line_string
585
+ build_geometry { |ptr| FFI::GDAL.OGR_G_ForceToMultiLineString(ptr) }
586
+ end
587
+
588
+ private
589
+
590
+ def build_geometry
591
+ geometry_ptr = yield(@geometry_pointer)
592
+ return nil if geometry_ptr.null?
593
+
594
+ if geometry_ptr == @geometry_pointer
595
+ log 'Newly created geometry and current geometry are the same.'
596
+ end
597
+
598
+ self.class._to_geometry_type(geometry_ptr)
599
+ end
600
+
601
+ def pointer_from(geometry)
602
+ if geometry.is_a? OGR::Geometry
603
+ geometry.c_pointer
604
+ elsif geometry.kind_of? FFI::Pointer
605
+ geometry
606
+ end
607
+ end
608
+
609
+ def object_from(geometry)
610
+ if geometry.is_a? OGR::Geometry
611
+ geometry
612
+ elsif geometry.kind_of? FFI::Pointer
613
+ geometry.c_pointer
614
+ end
615
+ end
616
+ end
617
+ end