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.
- data/MIT-LICENSE +22 -0
- data/README.rdoc +135 -0
- data/Rakefile +41 -0
- data/VERSION +1 -0
- data/lib/coordinate_sequence.rb +126 -0
- data/lib/ffi-geos.rb +810 -0
- data/lib/geometry.rb +504 -0
- data/lib/geometry_collection.rb +28 -0
- data/lib/line_string.rb +61 -0
- data/lib/linear_ring.rb +5 -0
- data/lib/multi_line_string.rb +5 -0
- data/lib/multi_point.rb +5 -0
- data/lib/multi_polygon.rb +5 -0
- data/lib/point.rb +22 -0
- data/lib/polygon.rb +20 -0
- data/lib/prepared_geometry.rb +42 -0
- data/lib/strtree.rb +111 -0
- data/lib/tools.rb +54 -0
- data/lib/utils.rb +145 -0
- data/lib/wkb_reader.rb +33 -0
- data/lib/wkb_writer.rb +95 -0
- data/lib/wkt_reader.rb +29 -0
- data/lib/wkt_writer.rb +108 -0
- data/test/coordinate_sequence_tests.rb +70 -0
- data/test/geometry_tests.rb +1499 -0
- data/test/misc_tests.rb +53 -0
- data/test/point_tests.rb +31 -0
- data/test/prepared_geometry_tests.rb +28 -0
- data/test/strtree_tests.rb +54 -0
- data/test/test_helper.rb +40 -0
- data/test/utils_tests.rb +333 -0
- data/test/wkb_reader_tests.rb +188 -0
- data/test/wkb_writer_tests.rb +435 -0
- data/test/wkt_reader_tests.rb +120 -0
- data/test/wkt_writer_tests.rb +149 -0
- metadata +114 -0
data/lib/geometry.rb
ADDED
@@ -0,0 +1,504 @@
|
|
1
|
+
|
2
|
+
module Geos
|
3
|
+
class Geometry
|
4
|
+
include Geos::Tools
|
5
|
+
|
6
|
+
attr_reader :ptr
|
7
|
+
|
8
|
+
# For internal use. Geometry objects should be created via WkbReader,
|
9
|
+
# WktReader and the various Geos.create_* methods.
|
10
|
+
def initialize(ptr, auto_free = true)
|
11
|
+
@ptr = FFI::AutoPointer.new(
|
12
|
+
ptr,
|
13
|
+
auto_free ? self.class.method(:release) : self.class.method(:no_release)
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.no_release(ptr) #:nodoc:
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.release(ptr) #:nodoc:
|
21
|
+
FFIGeos.GEOSGeom_destroy_r(Geos.current_handle, ptr)
|
22
|
+
end
|
23
|
+
|
24
|
+
def clone
|
25
|
+
cast_geometry_ptr(FFIGeos.GEOSGeom_clone_r(Geos.current_handle, ptr))
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the name of the Geometry type, i.e. "Point", "Polygon", etc.
|
29
|
+
def geom_type
|
30
|
+
FFIGeos.GEOSGeomType_r(Geos.current_handle, self.ptr)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns one of the values from Geos::GeomTypes.
|
34
|
+
def type_id
|
35
|
+
FFIGeos.GEOSGeomTypeId_r(Geos.current_handle, self.ptr)
|
36
|
+
end
|
37
|
+
|
38
|
+
def normalize
|
39
|
+
FFIGeos.GEOSNormalize_r(Geos.current_handle, self.ptr)
|
40
|
+
end
|
41
|
+
|
42
|
+
def srid
|
43
|
+
FFIGeos.GEOSGetSRID_r(Geos.current_handle, self.ptr)
|
44
|
+
end
|
45
|
+
|
46
|
+
def srid=(s)
|
47
|
+
FFIGeos.GEOSSetSRID_r(Geos.current_handle, self.ptr, s)
|
48
|
+
end
|
49
|
+
|
50
|
+
def dimensions
|
51
|
+
FFIGeos.GEOSGeom_getDimensions_r(Geos.current_handle, self.ptr)
|
52
|
+
end
|
53
|
+
|
54
|
+
def num_geometries
|
55
|
+
FFIGeos.GEOSGetNumGeometries_r(Geos.current_handle, self.ptr)
|
56
|
+
end
|
57
|
+
|
58
|
+
def num_coordinates
|
59
|
+
FFIGeos.GEOSGetNumCoordinates_r(Geos.current_handle, self.ptr)
|
60
|
+
end
|
61
|
+
|
62
|
+
def coord_seq
|
63
|
+
CoordinateSequence.new(FFIGeos.GEOSGeom_getCoordSeq_r(Geos.current_handle, self.ptr), false)
|
64
|
+
end
|
65
|
+
|
66
|
+
def intersection(geom)
|
67
|
+
check_geometry(geom)
|
68
|
+
cast_geometry_ptr(FFIGeos.GEOSIntersection_r(Geos.current_handle, self.ptr, geom.ptr))
|
69
|
+
end
|
70
|
+
|
71
|
+
# :call-seq:
|
72
|
+
# buffer(width)
|
73
|
+
# buffer(width, options)
|
74
|
+
# buffer(width, quad_segs)
|
75
|
+
#
|
76
|
+
# Calls buffer on the Geometry. Calling with an options Hash is equivalent
|
77
|
+
# to calling buffer_with_style.
|
78
|
+
#
|
79
|
+
# By default, quad_segs is set to 8.
|
80
|
+
def buffer(width, *args)
|
81
|
+
quad_segs, options = if args.length <= 0
|
82
|
+
[ 8, nil ]
|
83
|
+
else
|
84
|
+
if args.first.is_a?(Hash)
|
85
|
+
[ args.first[:quad_segs] || 8, args.first ]
|
86
|
+
else
|
87
|
+
[ args.first, args[1] ]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
if options
|
92
|
+
if options.is_a?(Hash)
|
93
|
+
self.buffer_with_style(width, options)
|
94
|
+
else
|
95
|
+
raise RuntimeError.new("Expected an options Hash")
|
96
|
+
end
|
97
|
+
else
|
98
|
+
cast_geometry_ptr(FFIGeos.GEOSBuffer_r(Geos.current_handle, self.ptr, width, quad_segs))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Options:
|
103
|
+
#
|
104
|
+
# * :quad_segs - defaults to 8.
|
105
|
+
# * :endcap - defaults :round.
|
106
|
+
# * :join - defaults to :round.
|
107
|
+
# * :mitre_limit - defaults to 5.0.
|
108
|
+
def buffer_with_style(width, options = {})
|
109
|
+
options = {
|
110
|
+
:quad_segs => 8,
|
111
|
+
:endcap => :round,
|
112
|
+
:join => :round,
|
113
|
+
:mitre_limit => 5.0
|
114
|
+
}.merge(options)
|
115
|
+
|
116
|
+
check_enum_value(Geos::BufferCapStyles, options[:endcap]) if options[:endcap]
|
117
|
+
check_enum_value(Geos::BufferJoinStyles, options[:join]) if options[:join]
|
118
|
+
|
119
|
+
cast_geometry_ptr(FFIGeos.GEOSBufferWithStyle_r(
|
120
|
+
Geos.current_handle,
|
121
|
+
self.ptr,
|
122
|
+
width,
|
123
|
+
options[:quad_segs],
|
124
|
+
options[:endcap],
|
125
|
+
options[:join],
|
126
|
+
options[:mitre_limit]
|
127
|
+
))
|
128
|
+
end
|
129
|
+
|
130
|
+
def convex_hull
|
131
|
+
cast_geometry_ptr(FFIGeos.GEOSConvexHull_r(Geos.current_handle, self.ptr))
|
132
|
+
end
|
133
|
+
|
134
|
+
def difference(geom)
|
135
|
+
check_geometry(geom)
|
136
|
+
cast_geometry_ptr(FFIGeos.GEOSDifference_r(Geos.current_handle, self.ptr, geom.ptr))
|
137
|
+
end
|
138
|
+
|
139
|
+
def sym_difference(geom)
|
140
|
+
check_geometry(geom)
|
141
|
+
cast_geometry_ptr(FFIGeos.GEOSSymDifference_r(Geos.current_handle, self.ptr, geom.ptr))
|
142
|
+
end
|
143
|
+
|
144
|
+
def boundary
|
145
|
+
cast_geometry_ptr(FFIGeos.GEOSBoundary_r(Geos.current_handle, self.ptr))
|
146
|
+
end
|
147
|
+
|
148
|
+
# Calling without a geom argument is equivalent to calling unary_union when
|
149
|
+
# using GEOS 3.3+ and is equivalent to calling union_cascaded in older
|
150
|
+
# versions.
|
151
|
+
def union(geom = nil)
|
152
|
+
if geom
|
153
|
+
check_geometry(geom)
|
154
|
+
cast_geometry_ptr(FFIGeos.GEOSUnion_r(Geos.current_handle, self.ptr, geom.ptr))
|
155
|
+
else
|
156
|
+
if self.respond_to?(:unary_union)
|
157
|
+
self.unary_union
|
158
|
+
else
|
159
|
+
self.union_cascaded
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def union_cascaded
|
165
|
+
cast_geometry_ptr(FFIGeos.GEOSUnionCascaded_r(Geos.current_handle, self.ptr))
|
166
|
+
end
|
167
|
+
|
168
|
+
if FFIGeos.respond_to?(:GEOSUnaryUnion_r)
|
169
|
+
# Available in GEOS 3.3+
|
170
|
+
def unary_union
|
171
|
+
cast_geometry_ptr(FFIGeos.GEOSUnaryUnion_r(Geos.current_handle, self.ptr))
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def point_on_surface
|
176
|
+
cast_geometry_ptr(FFIGeos.GEOSPointOnSurface_r(Geos.current_handle, self.ptr))
|
177
|
+
end
|
178
|
+
|
179
|
+
def centroid
|
180
|
+
cast_geometry_ptr(FFIGeos.GEOSGetCentroid_r(Geos.current_handle, self.ptr))
|
181
|
+
end
|
182
|
+
alias :center :centroid
|
183
|
+
|
184
|
+
def envelope
|
185
|
+
cast_geometry_ptr(FFIGeos.GEOSEnvelope_r(Geos.current_handle, self.ptr))
|
186
|
+
end
|
187
|
+
|
188
|
+
# Returns the Dimensionally Extended Nine-Intersection Model (DE-9IM)
|
189
|
+
# matrix of the geometries as a String.
|
190
|
+
def relate(geom)
|
191
|
+
check_geometry(geom)
|
192
|
+
FFIGeos.GEOSRelate_r(Geos.current_handle, self.ptr, geom.ptr)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Checks the DE-9IM pattern against the geoms.
|
196
|
+
def relate_pattern(geom, pattern)
|
197
|
+
check_geometry(geom)
|
198
|
+
bool_result(FFIGeos.GEOSRelatePattern_r(Geos.current_handle, self.ptr, geom.ptr, pattern))
|
199
|
+
end
|
200
|
+
|
201
|
+
if FFIGeos.respond_to?(:GEOSRelateBoundaryNodeRule_r)
|
202
|
+
# Available in GEOS 3.3+.
|
203
|
+
def relate_boundary_node_rule(geom, bnr = :mod2)
|
204
|
+
check_geometry(geom)
|
205
|
+
check_enum_value(Geos::RelateBoundaryNodeRules, bnr)
|
206
|
+
FFIGeos.GEOSRelateBoundaryNodeRule_r(Geos.current_handle, self.ptr, geom.ptr, bnr)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def line_merge
|
211
|
+
cast_geometry_ptr(FFIGeos.GEOSLineMerge_r(Geos.current_handle, self.ptr))
|
212
|
+
end
|
213
|
+
|
214
|
+
def simplify(tolerance)
|
215
|
+
cast_geometry_ptr(FFIGeos.GEOSSimplify_r(Geos.current_handle, self.ptr, tolerance))
|
216
|
+
end
|
217
|
+
|
218
|
+
def topology_preserve_simplify(tolerance)
|
219
|
+
cast_geometry_ptr(FFIGeos.GEOSTopologyPreserveSimplify_r(Geos.current_handle, self.ptr, tolerance))
|
220
|
+
end
|
221
|
+
|
222
|
+
def extract_unique_points
|
223
|
+
cast_geometry_ptr(FFIGeos.GEOSGeom_extractUniquePoints_r(Geos.current_handle, self.ptr))
|
224
|
+
end
|
225
|
+
alias :unique_points :extract_unique_points
|
226
|
+
|
227
|
+
def disjoint?(geom)
|
228
|
+
check_geometry(geom)
|
229
|
+
bool_result(FFIGeos.GEOSDisjoint_r(Geos.current_handle, self.ptr, geom.ptr))
|
230
|
+
end
|
231
|
+
|
232
|
+
def touches?(geom)
|
233
|
+
check_geometry(geom)
|
234
|
+
bool_result(FFIGeos.GEOSTouches_r(Geos.current_handle, self.ptr, geom.ptr))
|
235
|
+
end
|
236
|
+
|
237
|
+
def intersects?(geom)
|
238
|
+
check_geometry(geom)
|
239
|
+
bool_result(FFIGeos.GEOSIntersects_r(Geos.current_handle, self.ptr, geom.ptr))
|
240
|
+
end
|
241
|
+
|
242
|
+
def crosses?(geom)
|
243
|
+
check_geometry(geom)
|
244
|
+
bool_result(FFIGeos.GEOSCrosses_r(Geos.current_handle, self.ptr, geom.ptr))
|
245
|
+
end
|
246
|
+
|
247
|
+
def within?(geom)
|
248
|
+
check_geometry(geom)
|
249
|
+
bool_result(FFIGeos.GEOSWithin_r(Geos.current_handle, self.ptr, geom.ptr))
|
250
|
+
end
|
251
|
+
|
252
|
+
def contains?(geom)
|
253
|
+
check_geometry(geom)
|
254
|
+
bool_result(FFIGeos.GEOSContains_r(Geos.current_handle, self.ptr, geom.ptr))
|
255
|
+
end
|
256
|
+
|
257
|
+
def overlaps?(geom)
|
258
|
+
check_geometry(geom)
|
259
|
+
bool_result(FFIGeos.GEOSOverlaps_r(Geos.current_handle, self.ptr, geom.ptr))
|
260
|
+
end
|
261
|
+
|
262
|
+
if FFIGeos.respond_to?(:GEOSCovers_r)
|
263
|
+
# In GEOS versions 3.3+, the native GEOSCoveredBy method will be used,
|
264
|
+
# while in older GEOS versions we'll use a relate_pattern-based
|
265
|
+
# implementation.
|
266
|
+
def covers?(geom)
|
267
|
+
check_geometry(geom)
|
268
|
+
bool_result(FFIGeos.GEOSCovers_r(Geos.current_handle, self.ptr, geom.ptr))
|
269
|
+
end
|
270
|
+
else
|
271
|
+
def covers?(geom) #:nodoc:
|
272
|
+
check_geometry(geom)
|
273
|
+
!!%w{
|
274
|
+
T*****FF*
|
275
|
+
*T****FF*
|
276
|
+
***T**FF*
|
277
|
+
****T*FF*
|
278
|
+
}.detect do |pattern|
|
279
|
+
self.relate_pattern(geom, pattern)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
if FFIGeos.respond_to?(:GEOSCoveredBy_r)
|
285
|
+
# In GEOS versions 3.3+, the native GEOSCovers method will be used,
|
286
|
+
# while in older GEOS versions we'll use a relate_pattern-based
|
287
|
+
# implementation.
|
288
|
+
def covered_by?(geom)
|
289
|
+
check_geometry(geom)
|
290
|
+
bool_result(FFIGeos.GEOSCoveredBy_r(Geos.current_handle, self.ptr, geom.ptr))
|
291
|
+
end
|
292
|
+
else
|
293
|
+
def covered_by?(geom) #:nodoc:
|
294
|
+
check_geometry(geom)
|
295
|
+
!!%w{
|
296
|
+
T*F**F***
|
297
|
+
*TF**F***
|
298
|
+
**FT*F***
|
299
|
+
**F*TF***
|
300
|
+
}.detect do |pattern|
|
301
|
+
self.relate_pattern(geom, pattern)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def disjoint?(geom)
|
307
|
+
check_geometry(geom)
|
308
|
+
bool_result(FFIGeos.GEOSDisjoint_r(Geos.current_handle, self.ptr, geom.ptr))
|
309
|
+
end
|
310
|
+
|
311
|
+
def eql?(geom)
|
312
|
+
check_geometry(geom)
|
313
|
+
bool_result(FFIGeos.GEOSEquals_r(Geos.current_handle, self.ptr, geom.ptr))
|
314
|
+
end
|
315
|
+
alias :== :eql?
|
316
|
+
|
317
|
+
def eql_exact?(geom, tolerance)
|
318
|
+
check_geometry(geom)
|
319
|
+
bool_result(FFIGeos.GEOSEqualsExact_r(Geos.current_handle, self.ptr, geom.ptr, tolerance))
|
320
|
+
end
|
321
|
+
|
322
|
+
def empty?
|
323
|
+
bool_result(FFIGeos.GEOSisEmpty_r(Geos.current_handle, self.ptr))
|
324
|
+
end
|
325
|
+
|
326
|
+
def valid?
|
327
|
+
bool_result(FFIGeos.GEOSisValid_r(Geos.current_handle, self.ptr))
|
328
|
+
end
|
329
|
+
|
330
|
+
# Returns a String describing whether or not the Geometry is valid.
|
331
|
+
def valid_reason
|
332
|
+
FFIGeos.GEOSisValidReason_r(Geos.current_handle, self.ptr)
|
333
|
+
end
|
334
|
+
|
335
|
+
# Returns a Hash containing the following structure on invalid geometries:
|
336
|
+
#
|
337
|
+
# {
|
338
|
+
# :detail => "String explaining the problem",
|
339
|
+
# :location => Geos::Point # centered on the problem
|
340
|
+
# }
|
341
|
+
#
|
342
|
+
# If the Geometry is valid, returns nil.
|
343
|
+
def valid_detail(flags = 0)
|
344
|
+
detail = FFI::MemoryPointer.new(:pointer)
|
345
|
+
location = FFI::MemoryPointer.new(:pointer)
|
346
|
+
valid = bool_result(
|
347
|
+
FFIGeos.GEOSisValidDetail_r(Geos.current_handle, self.ptr, flags, detail, location)
|
348
|
+
)
|
349
|
+
|
350
|
+
if !valid
|
351
|
+
{
|
352
|
+
:detail => detail.read_pointer.read_string,
|
353
|
+
:location => cast_geometry_ptr(location.read_pointer)
|
354
|
+
}
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
def simple?
|
359
|
+
bool_result(FFIGeos.GEOSisSimple_r(Geos.current_handle, self.ptr))
|
360
|
+
end
|
361
|
+
|
362
|
+
def ring?
|
363
|
+
bool_result(FFIGeos.GEOSisRing_r(Geos.current_handle, self.ptr))
|
364
|
+
end
|
365
|
+
|
366
|
+
def has_z?
|
367
|
+
bool_result(FFIGeos.GEOSHasZ_r(Geos.current_handle, self.ptr))
|
368
|
+
end
|
369
|
+
|
370
|
+
# GEOS versions prior to 3.3.0 didn't handle exceptions and can crash on
|
371
|
+
# bad input.
|
372
|
+
if FFIGeos.respond_to?(:GEOSProject_r) && Geos::GEOS_VERSION >= '3.3.0'
|
373
|
+
def project(geom, normalized = false)
|
374
|
+
raise TypeError.new("Expected Geos::Point type") if !geom.is_a?(Geos::Point)
|
375
|
+
|
376
|
+
if normalized
|
377
|
+
FFIGeos.GEOSProjectNormalized_r(Geos.current_handle, self.ptr, geom.ptr)
|
378
|
+
else
|
379
|
+
FFIGeos.GEOSProject_r(Geos.current_handle, self.ptr, geom.ptr)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def project_normalized(geom)
|
384
|
+
self.project(geom, true)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
def interpolate(d, normalized = false)
|
389
|
+
ret = if normalized
|
390
|
+
FFIGeos.GEOSInterpolateNormalized_r(Geos.current_handle, self.ptr, d)
|
391
|
+
else
|
392
|
+
FFIGeos.GEOSInterpolate_r(Geos.current_handle, self.ptr, d)
|
393
|
+
end
|
394
|
+
|
395
|
+
cast_geometry_ptr(ret)
|
396
|
+
end
|
397
|
+
|
398
|
+
def interpolate_normalized(d)
|
399
|
+
self.interpolate(d, true)
|
400
|
+
end
|
401
|
+
|
402
|
+
def start_point
|
403
|
+
cast_geometry_ptr(FFIGeos.GEOSGeomGetStartPoint_r(Geos.current_handle, self.ptr))
|
404
|
+
end
|
405
|
+
|
406
|
+
def end_point
|
407
|
+
cast_geometry_ptr(FFIGeos.GEOSGeomGetEndPoint_r(Geos.current_handle, self.ptr))
|
408
|
+
end
|
409
|
+
|
410
|
+
def area
|
411
|
+
FFI::MemoryPointer.new(:double).tap { |ret|
|
412
|
+
FFIGeos.GEOSArea_r(Geos.current_handle, self.ptr, ret)
|
413
|
+
}.read_double
|
414
|
+
end
|
415
|
+
|
416
|
+
def length
|
417
|
+
FFI::MemoryPointer.new(:double).tap { |ret|
|
418
|
+
FFIGeos.GEOSLength_r(Geos.current_handle, self.ptr, ret)
|
419
|
+
}.read_double
|
420
|
+
end
|
421
|
+
|
422
|
+
def distance(geom)
|
423
|
+
check_geometry(geom)
|
424
|
+
FFI::MemoryPointer.new(:double).tap { |ret|
|
425
|
+
FFIGeos.GEOSDistance_r(Geos.current_handle, self.ptr, geom.ptr, ret)
|
426
|
+
}.read_double
|
427
|
+
end
|
428
|
+
|
429
|
+
def hausdorff_distance(geom)
|
430
|
+
check_geometry(geom)
|
431
|
+
FFI::MemoryPointer.new(:double).tap { |ret|
|
432
|
+
FFIGeos.GEOSHausdorffDistance_r(Geos.current_handle, self.ptr, geom.ptr, ret)
|
433
|
+
}.read_double
|
434
|
+
end
|
435
|
+
|
436
|
+
def snap(geom, tolerance)
|
437
|
+
check_geometry(geom)
|
438
|
+
cast_geometry_ptr(FFIGeos.GEOSSnap_r(Geos.current_handle, self.ptr, geom.ptr, tolerance))
|
439
|
+
end
|
440
|
+
alias :snap_to :snap
|
441
|
+
|
442
|
+
def shared_paths(geom)
|
443
|
+
check_geometry(geom)
|
444
|
+
cast_geometry_ptr(FFIGeos.GEOSSharedPaths_r(Geos.current_handle, self.ptr, geom.ptr)).to_a
|
445
|
+
end
|
446
|
+
|
447
|
+
# Returns a Hash with the following structure:
|
448
|
+
#
|
449
|
+
# {
|
450
|
+
# :rings => [ ... ],
|
451
|
+
# :cuts => [ ... ],
|
452
|
+
# :dangles => [ ... ],
|
453
|
+
# :invalid_rings => [ ... ]
|
454
|
+
# }
|
455
|
+
def polygonize_full
|
456
|
+
cuts = FFI::MemoryPointer.new(:pointer)
|
457
|
+
dangles = FFI::MemoryPointer.new(:pointer)
|
458
|
+
invalid_rings = FFI::MemoryPointer.new(:pointer)
|
459
|
+
|
460
|
+
rings = cast_geometry_ptr(
|
461
|
+
FFIGeos.GEOSPolygonize_full_r(Geos.current_handle, self.ptr, cuts, dangles, invalid_rings)
|
462
|
+
)
|
463
|
+
|
464
|
+
cuts = cast_geometry_ptr(cuts.read_pointer)
|
465
|
+
dangles = cast_geometry_ptr(dangles.read_pointer)
|
466
|
+
invalid_rings = cast_geometry_ptr(invalid_rings.read_pointer)
|
467
|
+
|
468
|
+
{
|
469
|
+
:rings => rings.to_a,
|
470
|
+
:cuts => cuts.to_a,
|
471
|
+
:dangles => dangles.to_a,
|
472
|
+
:invalid_rings => invalid_rings.to_a
|
473
|
+
}
|
474
|
+
end
|
475
|
+
|
476
|
+
def polygonize
|
477
|
+
ary = FFI::MemoryPointer.new(:pointer)
|
478
|
+
ary.write_array_of_pointer([ self.ptr ])
|
479
|
+
|
480
|
+
cast_geometry_ptr(FFIGeos.GEOSPolygonize_r(Geos.current_handle, ary, 1)).to_a
|
481
|
+
end
|
482
|
+
|
483
|
+
def polygonize_cut_edges
|
484
|
+
ary = FFI::MemoryPointer.new(:pointer)
|
485
|
+
ary.write_array_of_pointer([ self.ptr ])
|
486
|
+
|
487
|
+
cast_geometry_ptr(FFIGeos.GEOSPolygonizer_getCutEdges_r(Geos.current_handle, ary, 1)).to_a
|
488
|
+
end
|
489
|
+
|
490
|
+
def to_prepared
|
491
|
+
Geos::PreparedGeometry.new(FFIGeos.GEOSPrepare_r(Geos.current_handle, self.ptr))
|
492
|
+
end
|
493
|
+
|
494
|
+
def to_s
|
495
|
+
writer = WktWriter.new
|
496
|
+
wkt = writer.write(self)
|
497
|
+
if wkt.length > 120
|
498
|
+
wkt = "#{wkt[0...120]} ... "
|
499
|
+
end
|
500
|
+
|
501
|
+
"#<Geos::#{self.geom_type}: #{wkt}>"
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|