ffi-geos 0.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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