ffi-ogr 0.0.1.pre → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +22 -12
- data/lib/ffi-ogr/coordinate_transformation.rb +30 -0
- data/lib/ffi-ogr/data_source.rb +158 -19
- data/lib/ffi-ogr/envelope.rb +33 -0
- data/lib/ffi-ogr/feature.rb +20 -7
- data/lib/ffi-ogr/geometry.rb +49 -4
- data/lib/ffi-ogr/layer.rb +41 -6
- data/lib/ffi-ogr/options_struct.rb +10 -0
- data/lib/ffi-ogr/spatial_reference.rb +81 -0
- data/lib/ffi-ogr/tools.rb +19 -12
- data/lib/ffi-ogr/version.rb +1 -1
- data/lib/ffi-ogr/writer.rb +4 -4
- data/lib/ffi-ogr.rb +41 -3
- metadata +13 -9
data/README.md
CHANGED
@@ -6,33 +6,46 @@ To run: `bin/ogr_console`
|
|
6
6
|
To read a shapefile:
|
7
7
|
|
8
8
|
```ruby
|
9
|
+
shp = OGR::ShpReader.new.read './spec/data/ne_110m_coastline/ne_110m_coastline.shp'
|
10
|
+
# => #<OGR::DataSource:0x007fba4d19c328 @ptr=#<FFI::AutoPointer address=0x007fba4c4cdc50>>
|
11
|
+
|
12
|
+
shp.to_geojson '~/Desktop/output.geojson'
|
13
|
+
# => Output GeoJSON to specified file
|
14
|
+
```
|
15
|
+
|
16
|
+
To reproject a shapefile:
|
9
17
|
|
18
|
+
```ruby
|
10
19
|
shp = OGR::ShpReader.new.read './spec/data/ne_110m_coastline/ne_110m_coastline.shp'
|
11
|
-
# => #<OGR::DataSource:0x007fba4d19c328 @
|
20
|
+
# => #<OGR::DataSource:0x007fba4d19c328 @ptr=#<FFI::AutoPointer address=0x007fba4c4cdc50>>
|
21
|
+
|
22
|
+
shp.to_json
|
23
|
+
# => Output GeoJSON string
|
24
|
+
|
25
|
+
shp.to_json true
|
26
|
+
# => Output GeoJSON string (pretty print)
|
12
27
|
|
13
|
-
|
14
|
-
|
28
|
+
# from_epsg(integer), from_proj4(string), from_wkt(string)
|
29
|
+
new_sr = OGR::SpatialReference.from_epsg 3857
|
30
|
+
# => #<OGR::SpatialReference:0x007fd859a0e6f8 @ptr=#<FFI::AutoPointer address=0x007fd85a11c100>>
|
15
31
|
|
16
|
-
shp.
|
17
|
-
# =>
|
32
|
+
shp.to_shp '~/Desktop/reprojected_shp.shp', {spatial_ref: new_sr}
|
33
|
+
# => Output reprojected SHP to specified file
|
18
34
|
```
|
19
35
|
|
20
36
|
A reader may also be inferred by file extension (currently works for shp and json/geojson):
|
21
37
|
|
22
38
|
```ruby
|
23
|
-
|
24
39
|
shp = OGR::Reader.from_file_type './spec/data/ne_110m_coastline/ne_110m_coastline.shp'
|
25
|
-
|
26
40
|
```
|
27
41
|
|
28
42
|
To create a shapefile:
|
29
43
|
|
30
44
|
```ruby
|
31
|
-
|
32
45
|
writer = OGR::ShpWriter.new
|
33
46
|
writer.set_output '~/Documents/shapefiles/my_new.shp'
|
34
47
|
|
35
|
-
shp = writer.
|
48
|
+
shp = writer.ptr
|
36
49
|
|
37
50
|
# add layer to shp : add_layer(name, geometry_type, spatial_reference)
|
38
51
|
# currently does not handle spatial reference, will automatically be nil
|
@@ -58,15 +71,12 @@ layer.add_feature feature
|
|
58
71
|
|
59
72
|
# sync to disk
|
60
73
|
layer.sync
|
61
|
-
|
62
74
|
```
|
63
75
|
|
64
76
|
A writer may also be inferred by file extension (currently works for shp and json/geojson):
|
65
77
|
|
66
78
|
```ruby
|
67
|
-
|
68
79
|
writer = OGR::Writer.from_file_type '~/Documents/shapefiles/my_new.shp'
|
69
|
-
|
70
80
|
```
|
71
81
|
|
72
82
|
Tested on: MRI 1.9.3-p392 and JRuby 1.7.3
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module OGR
|
2
|
+
class CoordinateTransformation
|
3
|
+
attr_accessor :ptr
|
4
|
+
|
5
|
+
def initialize(ptr)
|
6
|
+
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
7
|
+
@ptr.autorelease = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.release(ptr);end
|
11
|
+
|
12
|
+
def free
|
13
|
+
FFIOGR.OCTDestroyCoordinateTransformation(@ptr)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find_transformation(in_sr, out_sr)
|
17
|
+
bad_sr = []
|
18
|
+
|
19
|
+
if !in_sr.instance_of?(OGR::SpatialReference)
|
20
|
+
bad_sr << 'Input SR'
|
21
|
+
elsif !out_sr.instance_of?(OGR::SpatialReference)
|
22
|
+
bad_sr << 'Output SR'
|
23
|
+
end
|
24
|
+
|
25
|
+
raise RuntimeError.new("Invalid Spatial Reference(s): #{bad_sr.join(', ')}") if bad_sr.size > 0
|
26
|
+
|
27
|
+
FFIOGR.OCTNewCoordinateTransformation(in_sr.ptr, out_sr.ptr)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/ffi-ogr/data_source.rb
CHANGED
@@ -2,31 +2,108 @@ module OGR
|
|
2
2
|
class DataSource
|
3
3
|
include FFIOGR
|
4
4
|
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :ptr
|
6
6
|
|
7
|
-
def initialize(ptr
|
8
|
-
@
|
9
|
-
@
|
7
|
+
def initialize(ptr)
|
8
|
+
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
9
|
+
@ptr.autorelease = false
|
10
10
|
end
|
11
11
|
|
12
|
-
def self.release(ptr)
|
13
|
-
|
12
|
+
def self.release(ptr);end
|
13
|
+
|
14
|
+
def free
|
15
|
+
FFIOGR.OGR_DS_Destroy(@ptr)
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy(output_type, output_path, driver_options=nil)
|
19
|
+
driver = OGRGetDriverByName(OGR::DRIVER_TYPES[output_type.downcase])
|
20
|
+
new_ds = FFIOGR.OGR_Dr_CopyDataSource(driver, @ptr, File.expand_path(output_path), driver_options)
|
21
|
+
FFIOGR.OGR_DS_Destroy(new_ds)
|
22
|
+
end
|
23
|
+
|
24
|
+
def copy_with_transform(output_type, output_path, spatial_ref=nil, driver_options=nil)
|
25
|
+
writer = OGR::GenericWriter.new(OGR::DRIVER_TYPES[output_type.downcase])
|
26
|
+
writer.set_output(output_path)
|
27
|
+
out = writer.ptr
|
28
|
+
|
29
|
+
layers.each do |layer|
|
30
|
+
name = layer.name
|
31
|
+
geometry_type = layer.geometry_type
|
32
|
+
old_sr = layer.spatial_ref
|
33
|
+
|
34
|
+
ct = OGR::CoordinateTransformation.find_transformation(old_sr, spatial_ref) unless spatial_ref.nil? || (spatial_ref == old_sr)
|
35
|
+
|
36
|
+
sr = spatial_ref.nil? ? nil : spatial_ref.ptr
|
37
|
+
|
38
|
+
new_layer = out.add_layer name, geometry_type, sr, driver_options
|
39
|
+
|
40
|
+
ptr = layer.ptr
|
41
|
+
|
42
|
+
layer_definition = FFIOGR.OGR_L_GetLayerDefn(ptr)
|
43
|
+
field_count = FFIOGR.OGR_FD_GetFieldCount(layer_definition)
|
44
|
+
|
45
|
+
for i in (0...field_count)
|
46
|
+
fd = FFIOGR.OGR_FD_GetFieldDefn(layer_definition, i)
|
47
|
+
name = FFIOGR.OGR_Fld_GetNameRef(fd)
|
48
|
+
type = FFIOGR.OGR_Fld_GetType(fd)
|
49
|
+
|
50
|
+
opts = {}
|
51
|
+
|
52
|
+
opts[:precision] = FFIOGR.OGR_Fld_GetPrecision(fd) if type == :real
|
53
|
+
opts[:width] = FFIOGR.OGR_Fld_GetWidth(fd) if type == :string
|
54
|
+
|
55
|
+
new_layer.add_field name, type
|
56
|
+
end
|
57
|
+
|
58
|
+
layer.features.each do |feature|
|
59
|
+
geometry = OGR::Tools.cast_geometry(feature.geometry)
|
60
|
+
geometry.transform ct if ct
|
61
|
+
|
62
|
+
new_feature = new_layer.create_feature
|
63
|
+
new_feature.add_geometry geometry
|
64
|
+
|
65
|
+
ptr = feature.ptr
|
66
|
+
field_count = FFIOGR.OGR_F_GetFieldCount(ptr)
|
67
|
+
|
68
|
+
for i in (0...field_count)
|
69
|
+
fd = FFIOGR.OGR_F_GetFieldDefnRef(ptr, i)
|
70
|
+
field_name = FFIOGR.OGR_Fld_GetNameRef(fd)
|
71
|
+
field_type = FFIOGR.OGR_Fld_GetType(fd)
|
72
|
+
|
73
|
+
case field_type
|
74
|
+
when :integer
|
75
|
+
field_value = FFIOGR.OGR_F_GetFieldAsInteger(ptr, i)
|
76
|
+
when :real
|
77
|
+
field_value = FFIOGR.OGR_F_GetFieldAsDouble(ptr, i)
|
78
|
+
else
|
79
|
+
field_value = FFIOGR.OGR_F_GetFieldAsString(ptr, i)
|
80
|
+
end
|
81
|
+
|
82
|
+
new_feature.set_field_value field_name, field_value, field_type
|
83
|
+
end
|
84
|
+
|
85
|
+
new_layer.add_feature new_feature
|
86
|
+
end
|
87
|
+
|
88
|
+
new_layer.sync
|
89
|
+
end
|
90
|
+
out.free
|
14
91
|
end
|
15
92
|
|
16
|
-
def add_layer(name, geometry_type, spatial_ref=nil, options=
|
17
|
-
|
18
|
-
# need to add options as StringList ...
|
19
|
-
layer = FFIOGR.OGR_DS_CreateLayer(@ds, name, spatial_ref, geometry_type.to_sym, nil)
|
93
|
+
def add_layer(name, geometry_type, spatial_ref=nil, options=nil)
|
94
|
+
layer = FFIOGR.OGR_DS_CreateLayer(@ptr, name, spatial_ref, geometry_type.to_sym, options)
|
20
95
|
OGR::Tools.cast_layer(layer)
|
21
96
|
end
|
22
97
|
|
98
|
+
def num_layers
|
99
|
+
FFIOGR.OGR_DS_GetLayerCount(@ptr)
|
100
|
+
end
|
101
|
+
|
23
102
|
def get_layers
|
24
103
|
layers = []
|
25
104
|
|
26
|
-
num_layers = OGR_DS_GetLayerCount(@ds)
|
27
|
-
|
28
105
|
for i in (0...num_layers) do
|
29
|
-
layers << OGR::Tools.cast_layer(OGR_DS_GetLayer(@
|
106
|
+
layers << OGR::Tools.cast_layer(OGR_DS_GetLayer(@ptr, i))
|
30
107
|
end
|
31
108
|
|
32
109
|
layers
|
@@ -34,22 +111,84 @@ module OGR
|
|
34
111
|
alias_method :layers, :get_layers
|
35
112
|
|
36
113
|
def get_features
|
37
|
-
layers.map {|l| l.features}
|
114
|
+
layers.map {|l| l.features}
|
38
115
|
end
|
39
116
|
alias_method :features, :get_features
|
40
117
|
|
41
|
-
def get_geometries
|
42
|
-
|
118
|
+
def get_geometries(as_geojson=false)
|
119
|
+
unless as_geojson
|
120
|
+
features.map {|feature| feature.map {|f| OGR::Tools.cast_geometry(f.geometry)}}
|
121
|
+
else
|
122
|
+
features.map {|feature| feature.map {|f| OGR::Tools.cast_geometry(f.geometry).to_geojson}}
|
123
|
+
end
|
43
124
|
end
|
44
125
|
alias_method :geometries, :get_geometries
|
45
126
|
|
46
127
|
def get_fields
|
47
|
-
features.map {|f| f.fields}
|
128
|
+
features.map {|feature| feature.map {|f| f.fields}}
|
48
129
|
end
|
49
130
|
alias_method :fields, :get_fields
|
50
131
|
|
51
|
-
def
|
52
|
-
|
132
|
+
def to_shp(output_path, spatial_ref=nil)
|
133
|
+
raise RuntimeError.new("Output path not specified.") if output_path.nil?
|
134
|
+
|
135
|
+
# TODO: handle parsing of spatial_ref -> copy options
|
136
|
+
|
137
|
+
if spatial_ref.instance_of? OGR::SpatialReference
|
138
|
+
copy_with_transform('shapefile', output_path, spatial_ref)
|
139
|
+
elsif spatial_ref.nil?
|
140
|
+
copy('shapefile', output_path, spatial_ref)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def to_geojson(output_path, options=nil)
|
145
|
+
raise RuntimeError.new("Output path not specified.") if output_path.nil?
|
146
|
+
|
147
|
+
unless options.nil?
|
148
|
+
spatial_ref = options[:spatial_ref] ? options[:spatial_ref] : nil
|
149
|
+
|
150
|
+
if options[:bbox]
|
151
|
+
# this segfaults -- working on solution
|
152
|
+
bbox = FFI::MemoryPointer.from_string "WRITE_BBOX=YES"
|
153
|
+
driver_options = FFI::MemoryPointer.new :pointer, 1
|
154
|
+
driver_options[0].put_pointer 0, bbox
|
155
|
+
else
|
156
|
+
driver_options = nil
|
157
|
+
end
|
158
|
+
|
159
|
+
if spatial_ref
|
160
|
+
copy_with_transform('geojson', output_path, spatial_ref, driver_options)
|
161
|
+
else
|
162
|
+
copy('geojson', output_path, driver_options)
|
163
|
+
end
|
164
|
+
else
|
165
|
+
copy('geojson', output_path, nil)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def to_json(pretty=false)
|
170
|
+
h = {
|
171
|
+
type: 'FeatureCollection',
|
172
|
+
bbox: nil,
|
173
|
+
features: []
|
174
|
+
}
|
175
|
+
|
176
|
+
layers.each do |layer|
|
177
|
+
h[:bbox] = layer.envelope.to_a true
|
178
|
+
geometry_type = layer.geometry_type.to_s.capitalize
|
179
|
+
|
180
|
+
layer.features.each do |feature|
|
181
|
+
properties = feature.fields
|
182
|
+
geometry = OGR::Tools.cast_geometry(feature.geometry).to_geojson
|
183
|
+
h[:features] << {type: geometry_type, geometry: geometry, properties: properties}
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
unless pretty
|
188
|
+
MultiJson.dump(h)
|
189
|
+
else
|
190
|
+
MultiJson.dump(h, pretty: true)
|
191
|
+
end
|
53
192
|
end
|
54
193
|
end
|
55
194
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module OGR
|
2
|
+
class Envelope
|
3
|
+
attr_accessor :min_x, :max_x, :min_y, :max_y
|
4
|
+
|
5
|
+
def initialize(env)
|
6
|
+
raise RuntimeError.new("Invalid envelope specified") unless env.size == 4
|
7
|
+
|
8
|
+
@min_x, @max_x = env[0], env[1]
|
9
|
+
@min_y, @max_y = env[2], env[3]
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_a(se_nw=false)
|
13
|
+
unless se_nw
|
14
|
+
[@min_x, @max_x, @min_y, @max_y]
|
15
|
+
else
|
16
|
+
[@min_x, @min_y, @max_x, @max_y]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
{min_x: @min_x, max_x: @max_x, min_y: @min_y, max_y: @max_y}
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_json
|
25
|
+
MultiJson.dump(to_hash)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_polygon
|
29
|
+
coords = [[[@min_x, @min_y], [@min_x, @max_y], [@max_x, @max_y], [@max_x, @min_y], [@min_x, @min_y]]]
|
30
|
+
OGR::Polygon.create coords
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/ffi-ogr/feature.rb
CHANGED
@@ -2,13 +2,16 @@ module OGR
|
|
2
2
|
class Feature
|
3
3
|
attr_accessor :ptr
|
4
4
|
|
5
|
-
def initialize(ptr
|
5
|
+
def initialize(ptr)
|
6
6
|
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
7
|
-
|
7
|
+
#@ptr = FFI::AutoPointer.new(ptr)
|
8
|
+
@ptr.autorelease = false
|
8
9
|
end
|
9
10
|
|
10
|
-
def self.release(ptr)
|
11
|
-
|
11
|
+
def self.release(ptr);end
|
12
|
+
|
13
|
+
def free
|
14
|
+
FFIOGR.OGR_F_Destroy(@ptr)
|
12
15
|
end
|
13
16
|
|
14
17
|
def set_field_value(name, value, field_type=nil)
|
@@ -25,7 +28,10 @@ module OGR
|
|
25
28
|
when :integer
|
26
29
|
FFIOGR.OGR_F_SetFieldInteger(@ptr, field_index, Integer(value))
|
27
30
|
when :real
|
28
|
-
|
31
|
+
#dbl_ptr = FFI::MemoryPointer.new(:double, 1)
|
32
|
+
#dbl_ptr.write_double(Float(value))
|
33
|
+
|
34
|
+
FFIOGR.OGR_F_SetFieldDouble(@ptr, field_index, value)
|
29
35
|
when :string
|
30
36
|
FFIOGR.OGR_F_SetFieldString(@ptr, field_index, String(value))
|
31
37
|
when :binary
|
@@ -34,8 +40,8 @@ module OGR
|
|
34
40
|
end
|
35
41
|
|
36
42
|
def add_geometry(geometry)
|
37
|
-
FFIOGR.OGR_F_SetGeometry(@ptr, geometry.ptr)
|
38
|
-
|
43
|
+
#FFIOGR.OGR_F_SetGeometry(@ptr, geometry.ptr)
|
44
|
+
FFIOGR.OGR_F_SetGeometryDirectly(@ptr, geometry.ptr)
|
39
45
|
end
|
40
46
|
|
41
47
|
def get_geometry
|
@@ -72,6 +78,13 @@ module OGR
|
|
72
78
|
end
|
73
79
|
alias_method :fields, :get_fields
|
74
80
|
|
81
|
+
def transform_to(out_sr)
|
82
|
+
geom = OGR::Tools.cast_geometry(geometry)
|
83
|
+
geom.transform(out_sr)
|
84
|
+
p geom.ptr
|
85
|
+
add_geometry(geom)
|
86
|
+
end
|
87
|
+
|
75
88
|
def to_geojson
|
76
89
|
{type: 'Feature', geometry: OGR::Tools.cast_geometry(geometry).to_geojson, properties: fields}
|
77
90
|
end
|
data/lib/ffi-ogr/geometry.rb
CHANGED
@@ -1,21 +1,46 @@
|
|
1
1
|
module OGR
|
2
2
|
class Geometry
|
3
|
-
|
3
|
+
attr_accessor :ptr
|
4
4
|
|
5
|
-
def initialize(ptr
|
5
|
+
def initialize(ptr)
|
6
6
|
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
7
|
-
#@ptr
|
7
|
+
#@ptr = FFI::AutoPointer.new(ptr)
|
8
|
+
@ptr.autorelease = false
|
8
9
|
end
|
9
10
|
|
10
11
|
def self.release(ptr);end
|
11
12
|
|
13
|
+
def free
|
14
|
+
FFIOGR.OGR_G_DestroyGeometry(@ptr)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_geojson(geojson)
|
18
|
+
if geojson.instance_of? String
|
19
|
+
geojson = MultiJson.load(geojson)
|
20
|
+
end
|
21
|
+
|
22
|
+
coords = geojson['coordinates']
|
23
|
+
|
24
|
+
case geojson['type']
|
25
|
+
when 'Point'
|
26
|
+
OGR::Point.create coords
|
27
|
+
when 'LineString'
|
28
|
+
OGR::LineString.create coords
|
29
|
+
when 'Polygon'
|
30
|
+
OGR::Polygon.create coords
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
12
34
|
def self.create_empty(geometry_type)
|
13
35
|
OGR::Tools.cast_geometry(FFIOGR.OGR_G_CreateGeometry(geometry_type))
|
14
36
|
end
|
15
37
|
|
16
38
|
def add_geometry(geometry)
|
17
39
|
FFIOGR.OGR_G_AddGeometry(@ptr, geometry.ptr)
|
18
|
-
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_geometry_directly(geometry)
|
43
|
+
FFIOGR.OGR_G_AddGeometryDirectly(@ptr, geometry.ptr)
|
19
44
|
end
|
20
45
|
|
21
46
|
def add_point(coords)
|
@@ -44,6 +69,10 @@ module OGR
|
|
44
69
|
end
|
45
70
|
end
|
46
71
|
|
72
|
+
def is_3d?
|
73
|
+
!!(geometry_type.to_s =~ /_25d/)
|
74
|
+
end
|
75
|
+
|
47
76
|
def flatten
|
48
77
|
FFIOGR.OGR_G_FlattenTo2D(@ptr)
|
49
78
|
end
|
@@ -53,6 +82,15 @@ module OGR
|
|
53
82
|
end
|
54
83
|
alias_method :geometry_type, :get_geometry_type
|
55
84
|
|
85
|
+
def get_spatial_ref
|
86
|
+
OGR::Tools.cast_spatial_reference(FFIOGR.OGR_G_GetSpatialReference(@ptr))
|
87
|
+
end
|
88
|
+
alias_method :spatial_ref, :get_spatial_ref
|
89
|
+
|
90
|
+
def transform(ct)
|
91
|
+
FFIOGR.OGR_G_Transform(@ptr, ct)
|
92
|
+
end
|
93
|
+
|
56
94
|
def get_length
|
57
95
|
FFIOGR.OGR_G_Length(@ptr)
|
58
96
|
end
|
@@ -68,6 +106,13 @@ module OGR
|
|
68
106
|
end
|
69
107
|
alias_method :boundary, :get_boundary
|
70
108
|
|
109
|
+
def get_envelope
|
110
|
+
envelope = FFI::MemoryPointer.new :pointer, 4
|
111
|
+
FFIOGR.OGR_G_GetEnvelope(@ptr, envelope)
|
112
|
+
OGR::Envelope.new(envelope.read_array_of_double(4))
|
113
|
+
end
|
114
|
+
alias_method :envelope, :get_envelope
|
115
|
+
|
71
116
|
def to_geojson
|
72
117
|
MultiJson.load(FFIOGR.OGR_G_ExportToJson(@ptr))
|
73
118
|
end
|
data/lib/ffi-ogr/layer.rb
CHANGED
@@ -2,22 +2,57 @@ module OGR
|
|
2
2
|
class Layer
|
3
3
|
attr_accessor :ptr, :name, :geometry_type
|
4
4
|
|
5
|
-
def initialize(ptr
|
5
|
+
def initialize(ptr)
|
6
6
|
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
7
|
-
|
8
|
-
@
|
9
|
-
#@ptr.autorelease = auto_free
|
7
|
+
#@ptr = FFI::AutoPointer.new(ptr)
|
8
|
+
@ptr.autorelease = false
|
10
9
|
end
|
11
10
|
|
12
11
|
def self.release(ptr);end
|
13
12
|
|
13
|
+
def free
|
14
|
+
@ptr.free
|
15
|
+
end
|
16
|
+
|
14
17
|
def sync
|
15
18
|
FFIOGR.OGR_L_SyncToDisk(@ptr)
|
16
19
|
end
|
17
20
|
|
18
|
-
def
|
21
|
+
def get_envelope
|
22
|
+
envelope = FFI::MemoryPointer.new :pointer, 4
|
23
|
+
FFIOGR.OGR_L_GetExtent(@ptr, envelope, 0)
|
24
|
+
OGR::Envelope.new(envelope.read_array_of_double(4))
|
25
|
+
end
|
26
|
+
alias_method :envelope, :get_envelope
|
27
|
+
|
28
|
+
def get_name
|
29
|
+
FFIOGR.OGR_L_GetName(@ptr)
|
30
|
+
end
|
31
|
+
alias_method :name, :get_name
|
32
|
+
|
33
|
+
def get_geometry_type
|
34
|
+
FFIOGR.OGR_L_GetGeomType(@ptr)
|
35
|
+
end
|
36
|
+
alias_method :geometry_type, :get_geometry_type
|
37
|
+
|
38
|
+
def get_spatial_ref
|
39
|
+
OGR::Tools.cast_spatial_reference(FFIOGR.OGR_L_GetSpatialRef(@ptr))
|
40
|
+
end
|
41
|
+
alias_method :spatial_ref, :get_spatial_ref
|
42
|
+
|
43
|
+
def add_field(name, field_type, options={})
|
44
|
+
type = field_type.to_sym
|
45
|
+
precision = options[:precision] || 1
|
46
|
+
width = options[:width] || 32
|
47
|
+
|
19
48
|
field = FFIOGR.OGR_Fld_Create(name, field_type.to_sym)
|
20
|
-
|
49
|
+
|
50
|
+
if type == :real
|
51
|
+
FFIOGR.OGR_Fld_SetPrecision(field, precision)
|
52
|
+
else
|
53
|
+
FFIOGR.OGR_Fld_SetWidth(field, width)
|
54
|
+
end
|
55
|
+
|
21
56
|
FFIOGR.OGR_L_CreateField(@ptr, field, 1)
|
22
57
|
FFIOGR.OGR_Fld_Destroy(field)
|
23
58
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module OGR
|
2
|
+
class SpatialReference
|
3
|
+
attr_accessor :ptr
|
4
|
+
|
5
|
+
def initialize(ptr)
|
6
|
+
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
7
|
+
@ptr.autorelease = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.release(ptr);end
|
11
|
+
|
12
|
+
def free
|
13
|
+
FFIOGR.OSRDestroySpatialReference(@ptr)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.create
|
17
|
+
OGR::Tools.cast_spatial_reference(FFIOGR.OSRNewSpatialReference(nil))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.from_wkt(wkt)
|
21
|
+
sr = OGR::Tools.cast_spatial_reference(FFIOGR.OSRNewSpatialReference(nil))
|
22
|
+
sr.import_wkt(wkt)
|
23
|
+
sr
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.from_proj4(proj4)
|
27
|
+
sr = OGR::Tools.cast_spatial_reference(FFIOGR.OSRNewSpatialReference(nil))
|
28
|
+
sr.import_proj4(proj4)
|
29
|
+
sr
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.from_epsg(epsg_code)
|
33
|
+
sr = OGR::Tools.cast_spatial_reference(FFIOGR.OSRNewSpatialReference(nil))
|
34
|
+
sr.import_epsg(epsg_code)
|
35
|
+
sr
|
36
|
+
end
|
37
|
+
|
38
|
+
def import_wkt(wkt)
|
39
|
+
wkt_ptr = FFI::MemoryPointer.from_string wkt
|
40
|
+
wkt_ptr_ptr = FFI::MemoryPointer.new :pointer
|
41
|
+
wkt_ptr_ptr.put_pointer 0, wkt_ptr
|
42
|
+
FFIOGR.OSRImportFromWkt(@ptr, wkt_ptr_ptr)
|
43
|
+
end
|
44
|
+
|
45
|
+
def import_proj4(proj4)
|
46
|
+
FFIOGR.OSRImportFromProj4(@ptr, proj4)
|
47
|
+
end
|
48
|
+
|
49
|
+
def import_epsg(epsg_code)
|
50
|
+
FFIOGR.OSRImportFromEPSG(@ptr, epsg_code)
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_wkt(pretty=false)
|
54
|
+
ptr = FFI::MemoryPointer.new :pointer
|
55
|
+
|
56
|
+
unless pretty
|
57
|
+
FFIOGR.OSRExportToWkt(@ptr, ptr)
|
58
|
+
else
|
59
|
+
FFIOGR.OSRExportToPrettyWkt(@ptr, ptr, 4)
|
60
|
+
end
|
61
|
+
str_ptr = ptr.read_pointer
|
62
|
+
|
63
|
+
return str_ptr.null? ? nil : str_ptr.read_string
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_proj4
|
67
|
+
ptr = FFI::MemoryPointer.new :pointer
|
68
|
+
FFIOGR.OSRExportToProj4(@ptr, ptr)
|
69
|
+
str_ptr = ptr.read_pointer
|
70
|
+
return str_ptr.null? ? nil: str_ptr.read_string
|
71
|
+
end
|
72
|
+
|
73
|
+
def ==(other)
|
74
|
+
self.to_wkt == other.to_wkt
|
75
|
+
end
|
76
|
+
|
77
|
+
def find_transformation(out_sr)
|
78
|
+
CoordinateTransformation.find_transformation self, out_sr
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/ffi-ogr/tools.rb
CHANGED
@@ -1,26 +1,33 @@
|
|
1
1
|
module OGR
|
2
2
|
module Tools
|
3
3
|
class << self
|
4
|
-
def
|
5
|
-
|
4
|
+
def cast_spatial_reference(sr_ptr, auto_free=true)
|
5
|
+
raise RuntimeError.new("Spatial Reference pointer is NULL") if sr_ptr.null?
|
6
|
+
SpatialReference.new sr_ptr
|
7
|
+
end
|
8
|
+
|
9
|
+
def cast_coordinate_transformation(ct_ptr, auto_free=true)
|
10
|
+
raise RuntimeError.new("Coordinate Transformation pointer is NULL") if ct_ptr.null?
|
11
|
+
CoordinateTransformation.new ct_ptr
|
12
|
+
end
|
13
|
+
|
14
|
+
def cast_data_source(ds_ptr, auto_free=true)
|
6
15
|
raise RuntimeError.new("Data Source pointer is NULL") if ds_ptr.null?
|
7
|
-
DataSource.new ds_ptr
|
16
|
+
DataSource.new ds_ptr
|
8
17
|
end
|
9
18
|
|
10
|
-
def cast_layer(l_ptr,
|
11
|
-
options = {auto_free: true}.merge(options)
|
19
|
+
def cast_layer(l_ptr, auto_free=true)
|
12
20
|
raise RuntimeError.new("Layer pointer is NULL") if l_ptr.null?
|
13
|
-
Layer.new l_ptr
|
21
|
+
Layer.new l_ptr
|
14
22
|
end
|
15
23
|
|
16
|
-
def cast_feature(f_ptr,
|
17
|
-
options = {auto_free: true}.merge(options)
|
24
|
+
def cast_feature(f_ptr, auto_free=true)
|
18
25
|
raise RuntimeError.new("Feature pointer is NULL") if f_ptr.null?
|
19
|
-
Feature.new f_ptr
|
26
|
+
Feature.new f_ptr
|
20
27
|
end
|
21
28
|
|
22
|
-
def cast_geometry(geom_ptr,
|
23
|
-
options = {auto_free: true}.merge(options)
|
29
|
+
def cast_geometry(geom_ptr, auto_free=true)
|
30
|
+
#options = {auto_free: true}.merge(options)
|
24
31
|
raise RuntimeError.new("Geometry pointer is NULL") if geom_ptr.null?
|
25
32
|
|
26
33
|
geom_type = FFIOGR.OGR_G_GetGeometryType(geom_ptr)
|
@@ -58,7 +65,7 @@ module OGR
|
|
58
65
|
OGR::GeometryCollection25D
|
59
66
|
end
|
60
67
|
|
61
|
-
klass.new(geom_ptr
|
68
|
+
klass.new(geom_ptr)
|
62
69
|
end
|
63
70
|
end
|
64
71
|
end
|
data/lib/ffi-ogr/version.rb
CHANGED
data/lib/ffi-ogr/writer.rb
CHANGED
@@ -2,15 +2,15 @@ module OGR
|
|
2
2
|
class Writer
|
3
3
|
include OGR::FFIOGR
|
4
4
|
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :ptr
|
6
6
|
|
7
7
|
def initialize;end
|
8
8
|
|
9
9
|
def set_output(path, options={})
|
10
10
|
path = File.expand_path(path)
|
11
11
|
ds = OGR_Dr_CreateDataSource(@driver, path, nil)
|
12
|
-
@
|
13
|
-
@
|
12
|
+
@ptr = OGR::Tools.cast_data_source(ds)
|
13
|
+
@ptr
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.from_file_type(path)
|
@@ -36,7 +36,7 @@ module OGR
|
|
36
36
|
writer = Writer.from_file_type output_path
|
37
37
|
data_source = writer.ds
|
38
38
|
|
39
|
-
# @
|
39
|
+
# @ptr -> data_source
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
data/lib/ffi-ogr.rb
CHANGED
@@ -4,6 +4,11 @@ require 'multi_json'
|
|
4
4
|
module OGR
|
5
5
|
OGR_BASE = File.join(File.dirname(__FILE__), 'ffi-ogr')
|
6
6
|
|
7
|
+
DRIVER_TYPES = {
|
8
|
+
'shapefile' => 'ESRI Shapefile',
|
9
|
+
'geojson' => 'GeoJSON'
|
10
|
+
}
|
11
|
+
|
7
12
|
autoload :Reader, File.join(OGR_BASE, 'reader')
|
8
13
|
autoload :GenericReader, File.join(OGR_BASE, 'generic_reader')
|
9
14
|
autoload :ShpReader, File.join(OGR_BASE, 'shp_reader')
|
@@ -34,6 +39,10 @@ module OGR
|
|
34
39
|
autoload :MultiLineString25D, File.join(OGR_BASE, 'multi_line_string_25d')
|
35
40
|
autoload :MultiPolygon25D, File.join(OGR_BASE, 'multi_polygon_25d')
|
36
41
|
autoload :GeometryCollection25D, File.join(OGR_BASE, 'geometry_collection_25d')
|
42
|
+
autoload :Envelope, File.join(OGR_BASE, 'envelope')
|
43
|
+
autoload :SpatialReference, File.join(OGR_BASE, 'spatial_reference')
|
44
|
+
autoload :CoordinateTransformation, File.join(OGR_BASE, 'coordinate_transformation')
|
45
|
+
autoload :OptionsStruct, File.join(OGR_BASE, 'options_struct')
|
37
46
|
|
38
47
|
module FFIOGR
|
39
48
|
def self.search_paths
|
@@ -109,12 +118,17 @@ module OGR
|
|
109
118
|
:right, 2
|
110
119
|
]
|
111
120
|
|
121
|
+
attach_function :GDALVersionInfo, [:string], :string
|
122
|
+
|
123
|
+
attach_function :CPLSetConfigOption, [:string, :string], :void
|
124
|
+
attach_function :CPLSetThreadLocalConfigOption, [:string, :string], :void
|
125
|
+
|
112
126
|
attach_function :OGRRegisterAll, [], :void
|
113
127
|
attach_function :OGR_Dr_GetName, [:pointer], :string
|
114
128
|
attach_function :OGR_Dr_Open, [:pointer, :string, :int], :pointer
|
115
129
|
attach_function :OGR_Dr_TestCapability, [:pointer, :string], :int
|
116
|
-
attach_function :OGR_Dr_CreateDataSource, [:pointer, :string, :
|
117
|
-
attach_function :OGR_Dr_CopyDataSource, [:pointer, :pointer, :string, :
|
130
|
+
attach_function :OGR_Dr_CreateDataSource, [:pointer, :string, :pointer], :pointer
|
131
|
+
attach_function :OGR_Dr_CopyDataSource, [:pointer, :pointer, :string, :pointer], :pointer
|
118
132
|
attach_function :OGR_Dr_DeleteDataSource, [:pointer, :string], :pointer
|
119
133
|
attach_function :OGRGetDriverCount, [], :int
|
120
134
|
attach_function :OGRGetDriver, [:int], :pointer
|
@@ -127,7 +141,7 @@ module OGR
|
|
127
141
|
attach_function :OGR_DS_GetLayerByName, [:pointer, :string], :pointer
|
128
142
|
attach_function :OGR_DS_DeleteLayer, [:pointer, :int], :pointer
|
129
143
|
attach_function :OGR_DS_GetDriver, [:pointer], :pointer
|
130
|
-
attach_function :OGR_DS_CreateLayer, [:pointer, :string, :pointer, :ogr_geometry_type, :
|
144
|
+
attach_function :OGR_DS_CreateLayer, [:pointer, :string, :pointer, :ogr_geometry_type, :pointer], :pointer
|
131
145
|
attach_function :OGR_DS_CopyLayer, [:pointer, :pointer, :string, :string], :pointer
|
132
146
|
attach_function :OGR_DS_TestCapability, [:pointer, :string], :int
|
133
147
|
attach_function :OGR_DS_ExecuteSQL, [:pointer, :string, :pointer, :string], :pointer
|
@@ -195,6 +209,7 @@ module OGR
|
|
195
209
|
attach_function :OGR_F_GetGeometryRef, [:pointer], :pointer
|
196
210
|
attach_function :OGR_F_GetFID, [:pointer], :long
|
197
211
|
attach_function :OGR_F_SetFID, [:pointer, :long], :pointer
|
212
|
+
attach_function :OGR_F_StealGeometry, [:pointer], :pointer
|
198
213
|
attach_function :OGR_F_SetGeometry, [:pointer, :pointer], :pointer
|
199
214
|
attach_function :OGR_F_SetGeometryDirectly, [:pointer, :pointer], :pointer
|
200
215
|
attach_function :OGR_G_CreateFromWkb, [:pointer, :pointer, :pointer, :int], :pointer
|
@@ -279,13 +294,36 @@ module OGR
|
|
279
294
|
attach_function :OGR_G_AddGeometryDirectly, [:pointer, :pointer], :pointer
|
280
295
|
attach_function :OGR_G_RemoveGeometry, [:pointer, :int, :int], :pointer
|
281
296
|
attach_function :OGR_F_Destroy, [:pointer], :void
|
297
|
+
|
298
|
+
# SRS Functions
|
299
|
+
|
300
|
+
attach_function :OSRNewSpatialReference, [:pointer], :pointer
|
301
|
+
attach_function :OSRImportFromWkt, [:pointer, :pointer], :pointer
|
302
|
+
attach_function :OSRImportFromProj4, [:pointer, :string], :pointer
|
303
|
+
attach_function :OSRImportFromEPSG, [:pointer, :int], :pointer
|
304
|
+
attach_function :OSRExportToWkt, [:pointer, :pointer], :pointer
|
305
|
+
attach_function :OSRExportToPrettyWkt, [:pointer, :pointer, :int], :pointer
|
306
|
+
attach_function :OSRExportToProj4, [:pointer, :pointer], :pointer
|
307
|
+
attach_function :OSRDestroySpatialReference, [:pointer], :void
|
308
|
+
attach_function :OCTNewCoordinateTransformation, [:pointer, :pointer], :pointer
|
309
|
+
attach_function :OCTDestroyCoordinateTransformation, [:pointer], :void
|
310
|
+
|
311
|
+
OGRRegisterAll() # register all available OGR drivers
|
282
312
|
end
|
283
313
|
|
284
314
|
class << self
|
315
|
+
def gdal_version
|
316
|
+
FFIOGR.GDALVersionInfo('RELEASE_NAME')
|
317
|
+
end
|
318
|
+
|
285
319
|
def to_binary(data)
|
286
320
|
buf = FFI::MemoryPointer.new(:char, value.size)
|
287
321
|
buf.put_bytes(0, data)
|
288
322
|
buf
|
289
323
|
end
|
324
|
+
|
325
|
+
def string_to_pointer(str)
|
326
|
+
FFI::MemoryPointer.from_string(str)
|
327
|
+
end
|
290
328
|
end
|
291
329
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-ogr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Scooter Wadsworth
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-04-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.
|
21
|
+
version: 1.6.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,23 +26,23 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 1.
|
29
|
+
version: 1.6.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: multi_json
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
|
-
- -
|
35
|
+
- - '='
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
37
|
+
version: 1.7.2
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
|
-
- -
|
43
|
+
- - '='
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
45
|
+
version: 1.7.2
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: rake
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -85,7 +85,9 @@ extra_rdoc_files: []
|
|
85
85
|
files:
|
86
86
|
- README.md
|
87
87
|
- bin/ogr_console
|
88
|
+
- lib/ffi-ogr/coordinate_transformation.rb
|
88
89
|
- lib/ffi-ogr/data_source.rb
|
90
|
+
- lib/ffi-ogr/envelope.rb
|
89
91
|
- lib/ffi-ogr/feature.rb
|
90
92
|
- lib/ffi-ogr/generic_reader.rb
|
91
93
|
- lib/ffi-ogr/generic_writer.rb
|
@@ -105,6 +107,7 @@ files:
|
|
105
107
|
- lib/ffi-ogr/multi_point_25d.rb
|
106
108
|
- lib/ffi-ogr/multi_polygon.rb
|
107
109
|
- lib/ffi-ogr/multi_polygon_25d.rb
|
110
|
+
- lib/ffi-ogr/options_struct.rb
|
108
111
|
- lib/ffi-ogr/point.rb
|
109
112
|
- lib/ffi-ogr/point_25d.rb
|
110
113
|
- lib/ffi-ogr/polygon.rb
|
@@ -113,6 +116,7 @@ files:
|
|
113
116
|
- lib/ffi-ogr/shapefile.rb
|
114
117
|
- lib/ffi-ogr/shp_reader.rb
|
115
118
|
- lib/ffi-ogr/shp_writer.rb
|
119
|
+
- lib/ffi-ogr/spatial_reference.rb
|
116
120
|
- lib/ffi-ogr/tools.rb
|
117
121
|
- lib/ffi-ogr/version.rb
|
118
122
|
- lib/ffi-ogr/writer.rb
|