ffi-geos 0.0.1.beta1

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.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2011 J Smith <dark.panda@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,135 @@
1
+
2
+ = GEOS Ruby Bindings in FFI
3
+
4
+ == Requirements
5
+
6
+ * the ffi extension for Ruby.
7
+ * GEOS version 3.3.0 or greater. GEOS 3.2.2 and below will work to an extent,
8
+ but some features and methods will be disabled or missing.
9
+
10
+ Ruby versions known to work:
11
+
12
+ * Ruby MRI 1.8.7 and 1.9.2, x86_64, OSX 10.6.5+
13
+ * Ruby MRI 1.8.7 and 1.9.2, i386, linux
14
+ * Ruby MRI 1.8.7, x86_64, linux
15
+ * JRuby 1.5 and 1.6 using JRE 1.6.0_22, x86_64, OSX 10.6.5+
16
+ * JRuby 1.5 and 1.6 using JRE 1.6.0_18, i386, linux
17
+
18
+ == Features
19
+
20
+ ffi-geos supports all of the features found in the binary SWIG-based GEOS
21
+ Ruby bindings along with the following enhancements and additions:
22
+
23
+ * support for prepared geometries via Geos::Geometry#to_prepared.
24
+
25
+ * an implementation of Geos::STRtree.
26
+
27
+ * use of GEOS's re-entrant interface for thread-safety.
28
+
29
+ * new options for controlling WKT output like trim and rounding precision.
30
+
31
+ * many new methods on geometry types. See below for a list.
32
+
33
+ * Geos::LineString, Geos::LinearRing, Geos::CoordinateSequence and
34
+ Geos::GeometryCollection and its descendants are now enumerable.
35
+
36
+ * The aforementioned enumerable classes also define some additional Array-like
37
+ methods such as [] and slice.
38
+
39
+ * Geos::WkbWriter and Geos::WktWriter have had their constructors extended
40
+ to allow for settings via an options Hash.
41
+
42
+ * Geos::WkbWriter#write, Geos::WkbWriter#write_hex and Geos::WktWriter#write
43
+ have been enhanced to take options Hashes allowing you to set per-write
44
+ settings.
45
+
46
+ == New Methods and Additions
47
+
48
+ === Geos
49
+
50
+ * Geos.create_multi_point
51
+
52
+ * Geos.create_multi_line_string
53
+
54
+ * Geos.create_multi_polygon
55
+
56
+ * Geos.create_geometry_collection
57
+
58
+ * Geos.create_collection
59
+
60
+ * Geos.create_empty_point
61
+
62
+ * Geos.create_empty_polygon
63
+
64
+ * Geos.create_empty_line_string
65
+
66
+ * Geos.create_empty_multi_point
67
+
68
+ * Geos.create_empty_multi_line_string
69
+
70
+ * Geos.create_empty_multi_polygon
71
+
72
+ * Geos.create_empty_geometry_collection
73
+
74
+ === Geos::Geometry
75
+
76
+ * Geos::Geometry#buffer_with_style
77
+
78
+ * Geos::Geometry#num_coordinates
79
+
80
+ * Geos::Geometry#union_cascaded. Geos::Geometry#union can also be called
81
+ without a geometry argument to produce the same effect.
82
+
83
+ * Geos::Geometry#extract_unique_points (aliased to Geos::Geometry#unique_points)
84
+
85
+ * Geos::Geometry#valid_reason
86
+
87
+ * Geos::Geometry#valid_detail
88
+
89
+ * Geos::Geometry#project
90
+
91
+ * Geos::Geometry#project_normalized
92
+
93
+ * Geos::Geometry#interpolate
94
+
95
+ * Geos::Geometry#interpolate_normalized
96
+
97
+ * Geos::Geometry#start_point
98
+
99
+ * Geos::Geometry#end_point
100
+
101
+ * Geos::Geometry#hausdorff_distance
102
+
103
+ * Geos::Geometry#snap
104
+
105
+ * Geos::Geometry#shared_paths
106
+
107
+ * Geos::Geometry#polygonize_full
108
+
109
+ * Geos::Geometry#polygonize
110
+
111
+ * Geos::Geometry#polygonize_cut_edges
112
+
113
+ * Geos::Geometry#to_prepared
114
+
115
+ === Geos::LineString and Geos::LinearRing
116
+
117
+ * Geos::LineString#num_points
118
+
119
+ * Geos::LineString#point_n
120
+
121
+ * Geos::LineString#buffer_single_sided
122
+
123
+ * Geos::LineString#closed?
124
+
125
+ === Geos::WktWriter
126
+
127
+ * Geos::WktWriter#trim=
128
+
129
+ * Geos::WktWriter#rounding_precision=
130
+
131
+ * Geos::WktWriter#old_3d=
132
+
133
+ === Geos::Utils
134
+
135
+ * Geos::Utils.orientation_index
@@ -0,0 +1,41 @@
1
+
2
+ # -*- ruby -*-
3
+
4
+ require 'rubygems'
5
+ require 'rake/gempackagetask'
6
+ require 'rake/testtask'
7
+ require 'rake/rdoctask'
8
+
9
+ $:.push 'lib'
10
+
11
+ version = File.read('VERSION') rescue ''
12
+
13
+ begin
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ gem.name = "ffi-geos"
17
+ gem.summary = "An ffi wrapper for GEOS, a C++ port of the Java Topology Suite (JTS)."
18
+ gem.description = gem.summary
19
+ gem.email = "dark.panda@gmail.com"
20
+ gem.homepage = "http://github.com/dark-panda/ffi-geos"
21
+ gem.authors = [ "J Smith" ]
22
+ end
23
+ Jeweler::GemcutterTasks.new
24
+ rescue LoadError
25
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
26
+ end
27
+
28
+ desc 'Test GEOS interface'
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.pattern = 'test/**/*_tests.rb'
31
+ t.verbose = !!ENV['VERBOSE_TESTS']
32
+ end
33
+
34
+ desc 'Build docs'
35
+ Rake::RDocTask.new do |t|
36
+ require 'rdoc'
37
+ t.title = "ffi-geos #{version}"
38
+ t.main = 'README.rdoc'
39
+ t.rdoc_dir = 'doc'
40
+ t.rdoc_files.include('README.rdoc', 'MIT-LICENSE', 'lib/**/*.rb')
41
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1.beta1
@@ -0,0 +1,126 @@
1
+
2
+ module Geos
3
+
4
+ # A CoordinateSequence is a list of coordinates in a Geometry.
5
+ class CoordinateSequence
6
+ include Enumerable
7
+
8
+ attr_reader :ptr
9
+
10
+ # :call-seq:
11
+ # new(ptr, auto_free = true)
12
+ # new(size, dims = 0)
13
+ #
14
+ # The ptr version of the initializer is for internal use.
15
+ def initialize(*args)
16
+ ptr, auto_free = if args.first.is_a?(FFI::Pointer)
17
+ [ args.first, args[1] ]
18
+ else
19
+ size, dims = if !args.length.between?(1, 2)
20
+ raise ArgumentError.new("wrong number of arguments (#{args.length} for 1-2)")
21
+ else
22
+ [ args[0], args[1] || 0]
23
+ end
24
+
25
+ [ FFIGeos.GEOSCoordSeq_create_r(Geos.current_handle, size, dims), true ]
26
+ end
27
+
28
+ @ptr = FFI::AutoPointer.new(
29
+ ptr,
30
+ auto_free ? self.class.method(:release) : self.class.method(:no_release)
31
+ )
32
+ end
33
+
34
+ def self.no_release(ptr) #:nodoc:
35
+ end
36
+
37
+ def self.release(ptr) #:nodoc:
38
+ FFIGeos.GEOSCoordSeq_destroy_r(Geos.current_handle, ptr)
39
+ end
40
+
41
+ def clone
42
+ self.class.new(FFIGeos.GEOSCoordSeq_clone_r(Geos.current_handle, self.ptr))
43
+ end
44
+
45
+ # Yields coordinates as [ x, y, z ]. The z coordinate may be omitted for
46
+ # 2-dimensional CoordinateSequences.
47
+ def each
48
+ self.length.times do |n|
49
+ yield [
50
+ self.get_x(n),
51
+ (self.dimensions >= 2 ? self.get_y(n) : nil),
52
+ (self.dimensions >= 3 ? self.get_z(n) : nil)
53
+ ].compact
54
+ end
55
+ end
56
+
57
+ def set_x(idx, val)
58
+ self.check_bounds(idx)
59
+ FFIGeos.GEOSCoordSeq_setX_r(Geos.current_handle, self.ptr, idx, val)
60
+ end
61
+
62
+ def set_y(idx, val)
63
+ self.check_bounds(idx)
64
+ FFIGeos.GEOSCoordSeq_setY_r(Geos.current_handle, self.ptr, idx, val)
65
+ end
66
+
67
+ def set_z(idx, val)
68
+ self.check_bounds(idx)
69
+ FFIGeos.GEOSCoordSeq_setZ_r(Geos.current_handle, self.ptr, idx, val)
70
+ end
71
+
72
+ def set_ordinate(idx, dim, val)
73
+ self.check_bounds(idx)
74
+ FFIGeos.GEOSCoordSeq_setOrdinate_r(Geos.current_handle, self.ptr, idx, dim, val)
75
+ end
76
+
77
+ def get_x(idx)
78
+ self.check_bounds(idx)
79
+ FFI::MemoryPointer.new(:double).tap { |ret|
80
+ FFIGeos.GEOSCoordSeq_getX_r(Geos.current_handle, self.ptr, idx, ret)
81
+ }.read_double
82
+ end
83
+
84
+ def get_y(idx)
85
+ self.check_bounds(idx)
86
+ FFI::MemoryPointer.new(:double).tap { |ret|
87
+ FFIGeos.GEOSCoordSeq_getY_r(Geos.current_handle, self.ptr, idx, ret)
88
+ }.read_double
89
+ end
90
+
91
+ def get_z(idx)
92
+ self.check_bounds(idx)
93
+ FFI::MemoryPointer.new(:double).tap { |ret|
94
+ FFIGeos.GEOSCoordSeq_getZ_r(Geos.current_handle, self.ptr, idx, ret)
95
+ }.read_double
96
+ end
97
+
98
+ def get_ordinate(idx, dim)
99
+ self.check_bounds(idx)
100
+ FFI::MemoryPointer.new(:double).tap { |ret|
101
+ FFIGeos.GEOSCoordSeq_getOrdinate_r(Geos.current_handle, self.ptr, idx, dim, ret)
102
+ }.read_double
103
+ end
104
+
105
+ def length
106
+ FFI::MemoryPointer.new(:int).tap { |ret|
107
+ FFIGeos.GEOSCoordSeq_getSize_r(Geos.current_handle, self.ptr, ret)
108
+ }.read_int
109
+ end
110
+ alias :size :length
111
+
112
+ def dimensions
113
+ @dimensions ||= FFI::MemoryPointer.new(:int).tap { |ret|
114
+ FFIGeos.GEOSCoordSeq_getDimensions_r(Geos.current_handle, self.ptr, ret)
115
+ }.read_int
116
+ end
117
+
118
+ protected
119
+
120
+ def check_bounds(idx) #:nodoc:
121
+ if idx < 0 || idx >= self.length
122
+ raise RuntimeError.new("Index out of bounds")
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,810 @@
1
+
2
+ require 'ffi'
3
+ require 'rbconfig'
4
+
5
+ module Geos
6
+ GEOS_BASE = File.dirname(__FILE__)
7
+
8
+ autoload :WktReader,
9
+ File.join(GEOS_BASE, 'wkt_reader')
10
+ autoload :WktWriter,
11
+ File.join(GEOS_BASE, 'wkt_writer')
12
+ autoload :WkbReader,
13
+ File.join(GEOS_BASE, 'wkb_reader')
14
+ autoload :WkbWriter,
15
+ File.join(GEOS_BASE, 'wkb_writer')
16
+ autoload :CoordinateSequence,
17
+ File.join(GEOS_BASE, 'coordinate_sequence')
18
+ autoload :Geometry,
19
+ File.join(GEOS_BASE, 'geometry')
20
+ autoload :PreparedGeometry,
21
+ File.join(GEOS_BASE, 'prepared_geometry')
22
+ autoload :GeometryCollection,
23
+ File.join(GEOS_BASE, 'geometry_collection')
24
+ autoload :LineString,
25
+ File.join(GEOS_BASE, 'line_string')
26
+ autoload :LinearRing,
27
+ File.join(GEOS_BASE, 'linear_ring')
28
+ autoload :MultiLineString,
29
+ File.join(GEOS_BASE, 'multi_line_string')
30
+ autoload :MultiPoint,
31
+ File.join(GEOS_BASE, 'multi_point')
32
+ autoload :MultiPolygon,
33
+ File.join(GEOS_BASE, 'multi_polygon')
34
+ autoload :Polygon,
35
+ File.join(GEOS_BASE, 'polygon')
36
+ autoload :Point,
37
+ File.join(GEOS_BASE, 'point')
38
+ autoload :STRtree,
39
+ File.join(GEOS_BASE, 'strtree')
40
+ autoload :Tools,
41
+ File.join(GEOS_BASE, 'tools')
42
+ autoload :Utils,
43
+ File.join(GEOS_BASE, 'utils')
44
+
45
+ module FFIGeos
46
+ def self.geos_library_paths
47
+ return @geos_library_paths if @geos_library_paths
48
+
49
+ paths = if ENV['GEOS_LIBRARY_PATH']
50
+ [ ENV['GEOS_LIBRARY_PATH'] ]
51
+ else
52
+ [ '/usr/local/{lib64,lib}', '/opt/local/{lib64,lib}', '/usr/{lib64,lib}' ]
53
+ end
54
+
55
+ libs = if [
56
+ Config::CONFIG['arch'],
57
+ Config::CONFIG['host_os']
58
+ ].detect { |c| c =~ /darwin/ }
59
+ %w{ libgeos_c.dylib libgeos.dylib }
60
+ else
61
+ %w{ libgeos.so libgeos_c.so }
62
+ end
63
+
64
+ @geos_library_paths = libs.collect { |lib|
65
+ Dir.glob(paths.collect { |path|
66
+ "#{path}/#{lib}"
67
+ }).first
68
+ }
69
+ end
70
+
71
+ extend ::FFI::Library
72
+
73
+ ffi_lib(*geos_library_paths)
74
+
75
+ Geos::DimensionTypes = enum(:dimension_type, [
76
+ :dontcare, -3,
77
+ :non_empty, -2,
78
+ :empty, -1,
79
+ :point, 0,
80
+ :curve, 1,
81
+ :surface, 2
82
+ ])
83
+
84
+ Geos::ByteOrders = enum(:byte_order, [
85
+ :xdr, 0, # Big Endian
86
+ :ndr, 1 # Little Endian
87
+ ])
88
+
89
+ Geos::BufferCapStyles = enum(:buffer_cap_style, [
90
+ :round, 1,
91
+ :flat, 2,
92
+ :square, 3
93
+ ])
94
+
95
+ Geos::BufferJoinStyles = enum(:buffer_join_style, [
96
+ :round, 1,
97
+ :mitre, 2,
98
+ :bevel, 3
99
+ ])
100
+
101
+ Geos::ValidFlags = enum(:valid_flag, [
102
+ :allow_selftouching_ring_forming_hole, 1
103
+ ])
104
+
105
+ Geos::RelateBoundaryNodeRules = enum(:relate_boundary_node_rule, [
106
+ :mod2, 1,
107
+ :ogc, 1,
108
+ :endpoint, 2,
109
+ :multivalent_endpoint, 3,
110
+ :monovalent_endpoint, 4
111
+ ])
112
+
113
+ FFI_LAYOUT = {
114
+ #### Utility functions ####
115
+ :initGEOS_r => [
116
+ :pointer,
117
+ callback([ :string, :string ], :void),
118
+ callback([ :string, :string ], :void)
119
+ ],
120
+
121
+ :finishGEOS_r => [
122
+ :void, :pointer
123
+ ],
124
+
125
+ :GEOSversion => [
126
+ :string
127
+ ],
128
+
129
+ :GEOSjtsport => [
130
+ :string
131
+ ],
132
+
133
+ :GEOSPolygonize_r => [
134
+ :pointer, :pointer, :pointer, :uint
135
+ ],
136
+
137
+ :GEOSPolygonizer_getCutEdges_r => [
138
+ :pointer, :pointer, :pointer, :uint
139
+ ],
140
+
141
+ :GEOSPolygonize_full_r => [
142
+ :pointer, :pointer, :pointer, :pointer, :pointer, :pointer
143
+ ],
144
+
145
+ :GEOSGeom_createPoint_r => [
146
+ :pointer, :pointer, :pointer
147
+ ],
148
+
149
+ :GEOSGeom_createEmptyPoint_r => [
150
+ :pointer, :pointer
151
+ ],
152
+
153
+ :GEOSGeom_createEmptyLineString_r => [
154
+ :pointer, :pointer
155
+ ],
156
+
157
+ :GEOSGeom_createLinearRing_r => [
158
+ :pointer, :pointer, :pointer
159
+ ],
160
+
161
+ :GEOSGeom_createLineString_r => [
162
+ :pointer, :pointer, :pointer
163
+ ],
164
+
165
+ :GEOSGeom_createPolygon_r => [
166
+ :pointer, :pointer, :pointer, :pointer, :uint
167
+ ],
168
+
169
+ :GEOSGeom_createEmptyPolygon_r => [
170
+ :pointer, :pointer
171
+ ],
172
+
173
+ :GEOSGeom_createCollection_r => [
174
+ :pointer, :pointer, :int, :pointer, :uint
175
+ ],
176
+
177
+ :GEOSGeom_createEmptyCollection_r => [
178
+ :pointer, :pointer, :int
179
+ ],
180
+ #### /Utility functions ####
181
+
182
+ #### CoordinateSequence functions ####
183
+ :GEOSCoordSeq_create_r => [
184
+ :pointer, :pointer, :uint, :uint
185
+ ],
186
+
187
+ :GEOSCoordSeq_destroy_r => [
188
+ :void, :pointer, :pointer
189
+ ],
190
+
191
+ :GEOSCoordSeq_clone_r => [
192
+ :pointer, :pointer, :pointer
193
+ ],
194
+
195
+ :GEOSCoordSeq_setX_r => [
196
+ :int, :pointer, :pointer, :uint, :double
197
+ ],
198
+
199
+ :GEOSCoordSeq_setY_r => [
200
+ :int, :pointer, :pointer, :uint, :double
201
+ ],
202
+
203
+ :GEOSCoordSeq_setZ_r => [
204
+ :int, :pointer, :pointer, :uint, :double
205
+ ],
206
+
207
+ :GEOSCoordSeq_setOrdinate_r => [
208
+ :int, :pointer, :pointer, :uint, :uint, :double
209
+ ],
210
+
211
+ :GEOSCoordSeq_getX_r => [
212
+ :int, :pointer, :pointer, :uint, :pointer
213
+ ],
214
+
215
+ :GEOSCoordSeq_getY_r => [
216
+ :int, :pointer, :pointer, :uint, :pointer
217
+ ],
218
+
219
+ :GEOSCoordSeq_getZ_r => [
220
+ :int, :pointer, :pointer, :uint, :pointer
221
+ ],
222
+
223
+ :GEOSCoordSeq_getOrdinate_r => [
224
+ :int, :pointer, :pointer, :uint, :uint, :pointer
225
+ ],
226
+
227
+ :GEOSCoordSeq_getSize_r => [
228
+ :int, :pointer, :pointer, :pointer
229
+ ],
230
+
231
+ :GEOSNormalize_r => [
232
+ :int, :pointer, :pointer
233
+ ],
234
+
235
+ :GEOSCoordSeq_getDimensions_r => [
236
+ :int, :pointer, :pointer, :pointer
237
+ ],
238
+ #### /CoordinateSequence functions ####
239
+
240
+ #### Geometry functions ####
241
+ :GEOSGeom_destroy_r => [
242
+ :void, :pointer, :pointer
243
+ ],
244
+
245
+ :GEOSGeom_clone_r => [
246
+ :pointer, :pointer, :pointer
247
+ ],
248
+
249
+ :GEOSGeomTypeId_r => [
250
+ :int, :pointer, :pointer
251
+ ],
252
+
253
+ :GEOSGeomType_r => [
254
+ :string, :pointer, :pointer
255
+ ],
256
+
257
+ :GEOSGetSRID_r => [
258
+ :int, :pointer, :pointer
259
+ ],
260
+
261
+ :GEOSSetSRID_r => [
262
+ :void, :pointer, :pointer, :int
263
+ ],
264
+
265
+ :GEOSGeom_getDimensions_r => [
266
+ :int, :pointer, :pointer
267
+ ],
268
+
269
+ :GEOSGetNumGeometries_r => [
270
+ :int, :pointer, :pointer
271
+ ],
272
+
273
+ :GEOSGetNumCoordinates_r => [
274
+ :int, :pointer, :pointer
275
+ ],
276
+
277
+ :GEOSGeom_getCoordSeq_r => [
278
+ :pointer, :pointer, :pointer
279
+ ],
280
+
281
+ :GEOSIntersection_r => [
282
+ :pointer, :pointer, :pointer, :pointer
283
+ ],
284
+
285
+ :GEOSBuffer_r => [
286
+ :pointer, :pointer, :pointer, :double, :int
287
+ ],
288
+
289
+ :GEOSBufferWithStyle_r => [
290
+ :pointer, :pointer, :pointer, :double, :int, :buffer_cap_style, :buffer_join_style, :double
291
+ ],
292
+
293
+ :GEOSSingleSidedBuffer_r => [
294
+ :pointer, :pointer, :pointer, :double, :int, :buffer_join_style, :double, :int
295
+ ],
296
+
297
+ :GEOSConvexHull_r => [
298
+ :pointer, :pointer, :pointer
299
+ ],
300
+
301
+ :GEOSDifference_r => [
302
+ :pointer, :pointer, :pointer, :pointer
303
+ ],
304
+
305
+ :GEOSSymDifference_r => [
306
+ :pointer, :pointer, :pointer, :pointer
307
+ ],
308
+
309
+ :GEOSBoundary_r => [
310
+ :pointer, :pointer, :pointer
311
+ ],
312
+
313
+ :GEOSUnion_r => [
314
+ :pointer, :pointer, :pointer, :pointer
315
+ ],
316
+
317
+ :GEOSUnaryUnion_r => [
318
+ :pointer, :pointer, :pointer
319
+ ],
320
+
321
+ :GEOSUnionCascaded_r => [
322
+ :pointer, :pointer, :pointer
323
+ ],
324
+
325
+ :GEOSPointOnSurface_r => [
326
+ :pointer, :pointer, :pointer
327
+ ],
328
+
329
+ :GEOSGetCentroid_r => [
330
+ :pointer, :pointer, :pointer
331
+ ],
332
+
333
+ :GEOSEnvelope_r => [
334
+ :pointer, :pointer, :pointer
335
+ ],
336
+
337
+ :GEOSLineMerge_r => [
338
+ :pointer, :pointer, :pointer
339
+ ],
340
+
341
+ :GEOSSimplify_r => [
342
+ :pointer, :pointer, :pointer, :double
343
+ ],
344
+
345
+ :GEOSTopologyPreserveSimplify_r => [
346
+ :pointer, :pointer, :pointer, :double
347
+ ],
348
+
349
+ :GEOSGeom_extractUniquePoints_r => [
350
+ :pointer, :pointer, :pointer
351
+ ],
352
+
353
+ :GEOSSharedPaths_r => [
354
+ :pointer, :pointer, :pointer, :pointer
355
+ ],
356
+
357
+ :GEOSSnap_r => [
358
+ :pointer, :pointer, :pointer, :pointer, :double
359
+ ],
360
+
361
+ :GEOSRelate_r => [
362
+ :string, :pointer, :pointer, :pointer
363
+ ],
364
+
365
+ :GEOSRelatePatternMatch_r => [
366
+ :char, :pointer, :string, :string
367
+ ],
368
+
369
+ :GEOSRelatePattern_r => [
370
+ :char, :pointer, :pointer, :pointer, :string
371
+ ],
372
+
373
+ :GEOSRelateBoundaryNodeRule_r => [
374
+ :string, :pointer, :pointer, :pointer, :relate_boundary_node_rule
375
+ ],
376
+
377
+ :GEOSDisjoint_r => [
378
+ :char, :pointer, :pointer, :pointer
379
+ ],
380
+
381
+ :GEOSTouches_r => [
382
+ :char, :pointer, :pointer, :pointer
383
+ ],
384
+
385
+ :GEOSIntersects_r => [
386
+ :char, :pointer, :pointer, :pointer
387
+ ],
388
+
389
+ :GEOSCrosses_r => [
390
+ :char, :pointer, :pointer, :pointer
391
+ ],
392
+
393
+ :GEOSWithin_r => [
394
+ :char, :pointer, :pointer, :pointer
395
+ ],
396
+
397
+ :GEOSContains_r => [
398
+ :char, :pointer, :pointer, :pointer
399
+ ],
400
+
401
+ :GEOSOverlaps_r => [
402
+ :char, :pointer, :pointer, :pointer
403
+ ],
404
+
405
+ :GEOSCovers_r => [
406
+ :char, :pointer, :pointer, :pointer
407
+ ],
408
+
409
+ :GEOSCoveredBy_r => [
410
+ :char, :pointer, :pointer, :pointer
411
+ ],
412
+
413
+ :GEOSEquals_r => [
414
+ :char, :pointer, :pointer, :pointer
415
+ ],
416
+
417
+ :GEOSEqualsExact_r => [
418
+ :char, :pointer, :pointer, :pointer, :double
419
+ ],
420
+
421
+ :GEOSisEmpty_r => [
422
+ :char, :pointer, :pointer
423
+ ],
424
+
425
+ :GEOSisValid_r => [
426
+ :char, :pointer, :pointer
427
+ ],
428
+
429
+ :GEOSisValidReason_r => [
430
+ :string, :pointer, :pointer
431
+ ],
432
+
433
+ :GEOSisValidDetail_r => [
434
+ :char, :pointer, :pointer, :int, :pointer, :pointer
435
+ ],
436
+
437
+ :GEOSisSimple_r => [
438
+ :char, :pointer, :pointer
439
+ ],
440
+
441
+ :GEOSisRing_r => [
442
+ :char, :pointer, :pointer
443
+ ],
444
+
445
+ :GEOSHasZ_r => [
446
+ :char, :pointer, :pointer
447
+ ],
448
+
449
+ :GEOSisClosed_r => [
450
+ :char, :pointer, :pointer
451
+ ],
452
+
453
+ :GEOSArea_r => [
454
+ :int, :pointer, :pointer, :pointer
455
+ ],
456
+
457
+ :GEOSLength_r => [
458
+ :int, :pointer, :pointer, :pointer
459
+ ],
460
+
461
+ :GEOSDistance_r => [
462
+ :int, :pointer, :pointer, :pointer, :pointer
463
+ ],
464
+
465
+ :GEOSHausdorffDistance_r => [
466
+ :int, :pointer, :pointer, :pointer, :pointer
467
+ ],
468
+
469
+ :GEOSGetGeometryN_r => [
470
+ :pointer, :pointer, :pointer, :int
471
+ ],
472
+
473
+ :GEOSGetNumInteriorRings_r => [
474
+ :int, :pointer, :pointer
475
+ ],
476
+
477
+ :GEOSGetInteriorRingN_r => [
478
+ :pointer, :pointer, :pointer, :int
479
+ ],
480
+
481
+ :GEOSGetExteriorRing_r => [
482
+ :pointer, :pointer, :pointer
483
+ ],
484
+
485
+ :GEOSGeomGetNumPoints_r => [
486
+ :int, :pointer, :pointer
487
+ ],
488
+
489
+ :GEOSGeomGetX_r => [
490
+ :int, :pointer, :pointer, :pointer
491
+ ],
492
+
493
+ :GEOSGeomGetY_r => [
494
+ :int, :pointer, :pointer, :pointer
495
+ ],
496
+
497
+ :GEOSGeomGetPointN_r => [
498
+ :pointer, :pointer, :pointer, :int
499
+ ],
500
+
501
+ :GEOSGeomGetStartPoint_r => [
502
+ :pointer, :pointer, :pointer
503
+ ],
504
+
505
+ :GEOSGeomGetEndPoint_r => [
506
+ :pointer, :pointer, :pointer
507
+ ],
508
+ #### /Geometry functions ####
509
+
510
+ #### STRtree functions ####
511
+ :GEOSSTRtree_create_r => [
512
+ :pointer, :pointer, :size_t
513
+ ],
514
+
515
+ :GEOSSTRtree_insert_r => [
516
+ :void, :pointer, :pointer, :pointer, :pointer
517
+ ],
518
+
519
+ :GEOSSTRtree_query_r => [
520
+ :void, :pointer, :pointer, :pointer, callback([ :pointer, :pointer ], :void), :pointer
521
+ ],
522
+
523
+ :GEOSSTRtree_iterate_r => [
524
+ :void, :pointer, :pointer, callback([ :pointer, :pointer ], :void), :pointer
525
+ ],
526
+
527
+ :GEOSSTRtree_remove_r => [
528
+ :char, :pointer, :pointer, :pointer, :pointer
529
+ ],
530
+
531
+ :GEOSSTRtree_destroy_r => [
532
+ :void, :pointer, :pointer
533
+ ],
534
+ #### /STRtree functions ####
535
+
536
+ #### PreparedGeometry functions ####
537
+ :GEOSPrepare_r => [
538
+ :pointer, :pointer, :pointer
539
+ ],
540
+
541
+ :GEOSPreparedGeom_destroy_r => [
542
+ :void, :pointer, :pointer
543
+ ],
544
+
545
+ :GEOSPreparedContains_r => [
546
+ :char, :pointer, :pointer, :pointer
547
+ ],
548
+
549
+ :GEOSPreparedContainsProperly_r => [
550
+ :char, :pointer, :pointer, :pointer
551
+ ],
552
+
553
+ :GEOSPreparedCovers_r => [
554
+ :char, :pointer, :pointer, :pointer
555
+ ],
556
+
557
+ :GEOSPreparedIntersects_r => [
558
+ :char, :pointer, :pointer, :pointer
559
+ ],
560
+ #### /PreparedGeometry functions ####
561
+
562
+ #### WktReader functions ####
563
+ :GEOSWKTReader_create_r => [
564
+ :pointer, :pointer
565
+ ],
566
+
567
+ :GEOSWKTReader_read_r => [
568
+ :pointer, :pointer, :pointer, :string
569
+ ],
570
+
571
+ :GEOSWKTReader_destroy_r => [
572
+ :void, :pointer, :pointer
573
+ ],
574
+ #### /WktReader functions ###
575
+
576
+ #### WktWriter functions ####
577
+ :GEOSWKTWriter_create_r => [
578
+ :pointer, :pointer
579
+ ],
580
+
581
+ :GEOSWKTWriter_write_r => [
582
+ :string, :pointer, :pointer, :pointer
583
+ ],
584
+
585
+ :GEOSWKTWriter_destroy_r => [
586
+ :void, :pointer, :pointer
587
+ ],
588
+
589
+ :GEOSWKTWriter_setTrim_r => [
590
+ :void, :pointer, :pointer, :char
591
+ ],
592
+
593
+ :GEOSWKTWriter_setRoundingPrecision_r => [
594
+ :void, :pointer, :pointer, :int
595
+ ],
596
+
597
+ :GEOSWKTWriter_setOutputDimension_r => [
598
+ :void, :pointer, :pointer, :int
599
+ ],
600
+
601
+ :GEOSWKTWriter_getOutputDimension_r => [
602
+ :int, :pointer, :pointer
603
+ ],
604
+
605
+ :GEOSWKTWriter_setOld3D_r => [
606
+ :void, :pointer, :pointer, :int
607
+ ],
608
+ #### /WktWriter functions ####
609
+
610
+ #### WkbReader functions ####
611
+ :GEOSWKBReader_create_r => [
612
+ :pointer, :pointer
613
+ ],
614
+
615
+ :GEOSWKBReader_destroy_r => [
616
+ :void, :pointer, :pointer
617
+ ],
618
+
619
+ :GEOSWKBReader_read_r => [
620
+ :pointer, :pointer, :pointer, :pointer, :size_t
621
+ ],
622
+
623
+ :GEOSWKBReader_readHEX_r => [
624
+ :pointer, :pointer, :pointer, :string, :size_t
625
+ ],
626
+ #### /WkbReader functions ####
627
+
628
+ #### WkbWriter functions ####
629
+ :GEOSWKBWriter_create_r => [
630
+ :pointer, :pointer
631
+ ],
632
+
633
+ :GEOSWKBWriter_destroy_r => [
634
+ :void, :pointer, :pointer
635
+ ],
636
+
637
+ :GEOSWKBWriter_write_r => [
638
+ :pointer, :pointer, :pointer, :pointer, :pointer
639
+ ],
640
+
641
+ :GEOSWKBWriter_writeHEX_r => [
642
+ :pointer, :pointer, :pointer, :pointer, :pointer
643
+ ],
644
+
645
+ :GEOSWKBWriter_setOutputDimension_r => [
646
+ :void, :pointer, :pointer, :int
647
+ ],
648
+
649
+ :GEOSWKBWriter_getOutputDimension_r => [
650
+ :int, :pointer, :pointer
651
+ ],
652
+
653
+ :GEOSWKBWriter_getByteOrder_r => [
654
+ :byte_order, :pointer, :pointer
655
+ ],
656
+
657
+ :GEOSWKBWriter_setByteOrder_r => [
658
+ :void, :pointer, :pointer, :byte_order
659
+ ],
660
+
661
+ :GEOSWKBWriter_getIncludeSRID_r => [
662
+ :char, :pointer, :pointer
663
+ ],
664
+
665
+ :GEOSWKBWriter_setIncludeSRID_r => [
666
+ :void, :pointer, :pointer, :char
667
+ ],
668
+ #### /WkbWriter functions ####
669
+
670
+
671
+ #### Linearref functions ####
672
+ :GEOSProject_r => [
673
+ :double, :pointer, :pointer, :pointer
674
+ ],
675
+
676
+ :GEOSProjectNormalized_r => [
677
+ :double, :pointer, :pointer, :pointer
678
+ ],
679
+
680
+ :GEOSInterpolate_r => [
681
+ :pointer, :pointer, :pointer, :double
682
+ ],
683
+
684
+ :GEOSInterpolateNormalized_r => [
685
+ :pointer, :pointer, :pointer, :double
686
+ ],
687
+ #### /Linearref functions ####
688
+
689
+ #### Algorithms ####
690
+ :GEOSOrientationIndex_r => [
691
+ :int, :pointer, :double, :double, :double, :double, :double, :double
692
+ ]
693
+ #### /Algorithms ####
694
+ }
695
+
696
+ FFI_LAYOUT.each do |fun, ary|
697
+ ret = ary.shift
698
+ begin
699
+ self.class_eval do
700
+ attach_function(fun, ary, ret)
701
+ end
702
+ rescue FFI::NotFoundError
703
+ # that's okay
704
+ end
705
+ end
706
+ end
707
+
708
+ class Handle
709
+ attr_reader :ptr
710
+
711
+ def initialize
712
+ @ptr = FFIGeos.initGEOS_r(
713
+ @notice_handler = self.method(:notice_handler),
714
+ @error_handler = self.method(:error_handler)
715
+ )
716
+
717
+ Kernel.at_exit {
718
+ FFIGeos.finishGEOS_r(@ptr)
719
+ }
720
+ end
721
+
722
+ def notice_handler(*args)
723
+ # no-op, just to appease initGEOS.
724
+ end
725
+
726
+ def error_handler(*args)
727
+ raise RuntimeError.new(args[0] % args[1])
728
+ end
729
+ end
730
+
731
+ class << self
732
+ def version
733
+ @version ||= FFIGeos.GEOSversion
734
+ end
735
+
736
+ def jts_port
737
+ @jts_port ||= FFIGeos.GEOSjtsport
738
+ end
739
+
740
+ def current_handle
741
+ Thread.current[:ffi_geos_handle] ||= Geos::Handle.new
742
+ Thread.current[:ffi_geos_handle].ptr
743
+ end
744
+
745
+ %w{
746
+ create_point
747
+ create_line_string
748
+ create_linear_ring
749
+ create_polygon
750
+ create_multi_point
751
+ create_multi_line_string
752
+ create_multi_polygon
753
+ create_geometry_collection
754
+
755
+ create_empty_point
756
+ create_empty_line_string
757
+ create_empty_polygon
758
+ create_empty_multi_point
759
+ create_empty_multi_line_string
760
+ create_empty_multi_polygon
761
+ create_empty_geometry_collection
762
+ }.each do |m|
763
+ self.class_eval <<-EOF
764
+ def #{m}(*args)
765
+ Geos::Utils.#{m}(*args)
766
+ end
767
+ EOF
768
+ end
769
+ end
770
+
771
+ module GeomTypes
772
+ GEOS_POINT = 0
773
+ GEOS_LINESTRING = 1
774
+ GEOS_LINEARRING = 2
775
+ GEOS_POLYGON = 3
776
+ GEOS_MULTIPOINT = 4
777
+ GEOS_MULTILINESTRING = 5
778
+ GEOS_MULTIPOLYGON = 6
779
+ GEOS_GEOMETRYCOLLECTION = 7
780
+ end
781
+
782
+ module VersionConstants
783
+ VERSION = File.read(File.join(GEOS_BASE, %w{ .. VERSION })) rescue nil
784
+ GEOS_JTS_PORT = Geos.jts_port
785
+ GEOS_VERSION,
786
+ GEOS_VERSION_MAJOR, GEOS_VERSION_MINOR, GEOS_VERISON_PATCH,
787
+ GEOS_CAPI_VERSION,
788
+ GEOS_CAPI_VERSION_MAJOR, GEOS_CAPI_VERSION_MINOR, GEOS_CAPI_VERSION_PATCH =
789
+ if versions = Geos.version.scan(/^((\d+)\.(\d+)\.(\d+))-CAPI-((\d+)\.(\d+)\.(\d+))$/)
790
+ versions = versions[0]
791
+ [
792
+ versions[0],
793
+ versions[1].to_i,
794
+ versions[2].to_i,
795
+ versions[3].to_i,
796
+ versions[4],
797
+ versions[5].to_i,
798
+ versions[6].to_i,
799
+ versions[7].to_i
800
+ ]
801
+ else
802
+ []
803
+ end
804
+ GEOS_CAPI_FIRST_INTERFACE = GEOS_CAPI_VERSION_MAJOR.to_i
805
+ GEOS_CAPI_LAST_INTERFACE = GEOS_CAPI_VERSION_MAJOR.to_i + GEOS_CAPI_VERSION_MINOR.to_i
806
+ end
807
+
808
+ include GeomTypes
809
+ include VersionConstants
810
+ end