ffi-geos 0.2.1 → 0.3.0

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ceab1a4b690aced547fbaea6008072689e803a35
4
+ data.tar.gz: 3e0c22f99d9a9884a9d755c0dd09698b68dbe6bf
5
+ SHA512:
6
+ metadata.gz: 96aa99fbd28ad9fb6bfffaa08e77b5a788107c2e608976baf4b20e7a38e711942fcedc9de9eb8795174a9f7e9af5cf1641ccc40559122ce6080d993994067ae1
7
+ data.tar.gz: 1307315dc60642d103c41df11c82c810c7c08f6b6d2c4b70e23aae224ea5bcf08fec0fe3ed1d816214f9bf306622b8b7fffda762402c85d7d4dddf53915d22da
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 J Smith <dark.panda@gmail.com>
1
+ Copyright (c) 2013 J Smith <dark.panda@gmail.com>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
@@ -9,9 +9,9 @@
9
9
 
10
10
  Ruby versions known to work:
11
11
 
12
- * Ruby MRI 1.8.7, 1.9.2 and 1.9.3 x86_64, OSX 10.6.5+
13
- * Ruby MRI 1.8.7 and 1.9.2, i386, linux
14
- * Ruby MRI 1.8.7, 1.9.2 and 1.9.3, x86_64, linux
12
+ * Ruby MRI 1.8.7, 1.9.2, 1.9.3, 2.0.0 x86_64, OSX 10.6.5+
13
+ * Ruby MRI 1.8.7, 1.9.2, 1.9.3, 2.0.0 i386, linux
14
+ * Ruby MRI 1.8.7, 1.9.2, 1.9.3, 2.0.0 x86_64, linux
15
15
  * JRuby 1.6, x86_64 OSX 10.6.5+
16
16
 
17
17
  === JRuby Notes
@@ -58,6 +58,10 @@ Ruby bindings along with the following enhancements and additions:
58
58
  * Geos::PreparedGeometry class and Geos::Geometry#to_prepared method to
59
59
  allow for prepared geometries and more efficient relationship testing.
60
60
 
61
+ * Geos::Interrupt module that allows you to interrupt certain calls to the
62
+ GEOS library and perform other work or cancel GEOS calls outright. The
63
+ interruption API was added in GEOS 3.4.0.
64
+
61
65
  == New Methods and Additions (not exhaustive)
62
66
 
63
67
  * SRIDs can be copied on many operations. GEOS doesn't usually copy SRIDs
@@ -69,88 +73,100 @@ Ruby bindings along with the following enhancements and additions:
69
73
 
70
74
  === Geos
71
75
 
72
- * Geos.create_multi_point
73
-
74
- * Geos.create_multi_line_string
75
-
76
- * Geos.create_multi_polygon
77
-
78
- * Geos.create_geometry_collection
79
-
80
- * Geos.create_collection
81
-
82
- * Geos.create_empty_point
83
-
84
- * Geos.create_empty_polygon
85
-
86
- * Geos.create_empty_line_string
87
-
88
- * Geos.create_empty_multi_point
89
-
90
- * Geos.create_empty_multi_line_string
76
+ * Many new Geos.create_* methods, such as Geos.create_linear_ring, etc.
91
77
 
92
- * Geos.create_empty_multi_polygon
93
-
94
- * Geos.create_empty_geometry_collection
78
+ * Geos.srid_copy_policy, srid_copy_policy=, srid_copy_policy_default and
79
+ srid_copy_policy_default=.
95
80
 
96
81
  === Geos::Geometry
97
82
 
98
- * Geos::Geometry#num_coordinates
99
-
100
- * Geos::Geometry#union_cascaded. Geos::Geometry#union can also be called
83
+ * Geos::almost_equals?
84
+ * Geos::coord_seq
85
+ * Geos::covered_by?
86
+ * Geos::covers?
87
+ * Geos::delaunay_triangulation
88
+ * Geos::end_point
89
+ * Geos::eql_almost?
90
+ * Geos::equals?
91
+ * Geos::equals_almost?
92
+ * Geos::equals_exact?
93
+ * Geos::exactly_equals?
94
+ * Geos::extract_unique_points - Geos::Geometry#unique_points
95
+ * Geos::hausdorff_distance
96
+ * Geos::interpolate
97
+ * Geos::interpolate_normalized
98
+ * Geos::nearest_points
99
+ * Geos::node
100
+ * Geos::normalize!
101
+ * Geos::num_coordinates
102
+ * Geos::polygonize
103
+ * Geos::polygonize_cut_edges
104
+ * Geos::polygonize_full
105
+ * Geos::project
106
+ * Geos::project_normalized
107
+ * Geos::relate_boundary_node_rule
108
+ * Geos::representative_point
109
+ * Geos::shared_paths
110
+ * Geos::snap
111
+ * Geos::snap_to
112
+ * Geos::start_point
113
+ * Geos::symmetric_difference
114
+ * Geos::to_prepared
115
+ * Geos::unary_union
116
+ * Geos::union_cascaded - Geos::Geometry#union can also be called
101
117
  without a geometry argument to produce the same effect.
102
-
103
- * Geos::Geometry#extract_unique_points (aliased to Geos::Geometry#unique_points)
104
-
105
- * Geos::Geometry#valid_reason
106
-
107
- * Geos::Geometry#valid_detail
108
-
109
- * Geos::Geometry#project
110
-
111
- * Geos::Geometry#project_normalized
112
-
113
- * Geos::Geometry#interpolate
114
-
115
- * Geos::Geometry#interpolate_normalized
116
-
117
- * Geos::Geometry#start_point
118
-
119
- * Geos::Geometry#end_point
120
-
121
- * Geos::Geometry#hausdorff_distance
122
-
123
- * Geos::Geometry#snap
124
-
125
- * Geos::Geometry#shared_paths
126
-
127
- * Geos::Geometry#polygonize_full
128
-
129
- * Geos::Geometry#polygonize
130
-
131
- * Geos::Geometry#polygonize_cut_edges
132
-
133
- * Geos::Geometry#to_prepared
118
+ * Geos::unique_points - Geos::Geometry#extract_unique_points
119
+ * Geos::valid_detail
120
+ * Geos::valid_reason
134
121
 
135
122
  === Geos::LineString and Geos::LinearRing
136
123
 
124
+ * Geos::LineString#[]
125
+ * Geos::LineString#closed?
126
+ * Geos::LineString#each
137
127
  * Geos::LineString#num_points
138
-
128
+ * Geos::LineString#offset_curve
139
129
  * Geos::LineString#point_n
140
-
141
- * Geos::LineString#closed?
130
+ * Geos::LineString#slice
131
+ * Geos::LinearRing#to_line_string
132
+ * Geos::LinearRing#to_polygon
142
133
 
143
134
  === Geos::WktWriter
144
135
 
136
+ * Geos::WktWriter#old_3d
137
+ * Geos::WktWriter#old_3d=
138
+ * Geos::WktWriter#output_dimensions
139
+ * Geos::WktWriter#output_dimensions=
140
+ * Geos::WktWriter#rounding_precision
141
+ * Geos::WktWriter#rounding_precision=
142
+ * Geos::WktWriter#trim
145
143
  * Geos::WktWriter#trim=
146
144
 
147
- * Geos::WktWriter#rounding_precision=
145
+ === Geos::CoordinateSequence
148
146
 
149
- * Geos::WktWriter#old_3d=
147
+ * Geos::CoordinateSequence#has_z?
148
+ * Geos::CoordinateSequence#to_line_string
149
+ * Geos::CoordinateSequence#to_linear_ring
150
+ * Geos::CoordinateSequence#to_point
151
+ * Geos::CoordinateSequence#to_polygon
152
+
153
+ === Geos::Polygon
154
+
155
+ * Geos::Polygon#interior_ring
156
+ * Geos::Polygon#interior_rings
150
157
 
151
158
  === Geos::Utils
152
159
 
153
160
  * Geos::Utils.orientation_index
161
+ * Geos::Utils.relate_match
162
+
163
+ === Geos::Interrupt
164
+
165
+ * Geos::Interrupt.available?
166
+ * Geos::Interrupt.register
167
+ * Geos::Interrupt.request
168
+ * Geos::Interrupt.cancel
169
+ * Geos::Interrupt.clear
154
170
 
155
171
  == Thanks
156
172
 
@@ -45,6 +45,8 @@ module Geos
45
45
  File.join(GEOS_BASE, 'tools')
46
46
  autoload :Utils,
47
47
  File.join(GEOS_BASE, 'utils')
48
+ autoload :Interrupt,
49
+ File.join(GEOS_BASE, 'interrupt')
48
50
 
49
51
  module FFIGeos
50
52
  def self.search_paths
@@ -151,6 +153,19 @@ module Geos
151
153
  :void, :pointer
152
154
  ],
153
155
 
156
+ :GEOS_interruptRegisterCallback => [
157
+ :pointer,
158
+ callback([], :void)
159
+ ],
160
+
161
+ :GEOS_interruptRequest => [
162
+ :void
163
+ ],
164
+
165
+ :GEOS_interruptCancel => [
166
+ :void
167
+ ],
168
+
154
169
  :GEOSversion => [
155
170
  :string
156
171
  ],
@@ -399,6 +414,11 @@ module Geos
399
414
  :pointer, :pointer, :pointer
400
415
  ],
401
416
 
417
+ :GEOSNode_r => [
418
+ # *geom, *handle, *geom
419
+ :pointer, :pointer, :pointer
420
+ ],
421
+
402
422
  # Deprecated in GEOS 3.3.0. Use GEOSUnaryUnion_r instead.
403
423
  :GEOSUnionCascaded_r => [
404
424
  # *geom, *handle, *geom
@@ -450,6 +470,11 @@ module Geos
450
470
  :pointer, :pointer, :pointer, :pointer, :double
451
471
  ],
452
472
 
473
+ :GEOSDelaunayTriangulation_r => [
474
+ # *geom, *handle, *geom, tolerance, only_edges
475
+ :pointer, :pointer, :pointer, :double, :int
476
+ ],
477
+
453
478
  :GEOSRelate_r => [
454
479
  # string, *handle, *geom_a, *geom_b
455
480
  :string, :pointer, :pointer, :pointer
@@ -590,6 +615,11 @@ module Geos
590
615
  :int, :pointer, :pointer, :pointer, :double, :pointer
591
616
  ],
592
617
 
618
+ :GEOSNearestPoints_r => [
619
+ # (NULL on exception, pointer to CoordinateSequence otherwise), *handle, *geom, *geom
620
+ :pointer, :pointer, :pointer, :pointer
621
+ ],
622
+
593
623
  :GEOSGetGeometryN_r => [
594
624
  # *geom, *handle, *geom, n
595
625
  :pointer, :pointer, :pointer, :int
@@ -44,7 +44,7 @@ module Geos
44
44
  attr_reader :ptr, :x, :y, :z
45
45
 
46
46
  # :call-seq:
47
- # new(ptr, auto_free = true)
47
+ # new(ptr, auto_free = true, parent = nil)
48
48
  # new(size = 0, dimensions = 0)
49
49
  # new(options)
50
50
  # new(points)
@@ -58,8 +58,8 @@ module Geos
58
58
  def initialize(*args)
59
59
  points = nil # forward declaration we can use later
60
60
 
61
- ptr, auto_free = if args.first.is_a?(FFI::Pointer)
62
- [ args.first, args[1] ]
61
+ ptr, auto_free, parent = if args.first.is_a?(FFI::Pointer)
62
+ args.first(3)
63
63
  else
64
64
  size, dimensions = if args.first.is_a?(Array)
65
65
  points = if args.first.first.is_a?(Array)
@@ -100,6 +100,7 @@ module Geos
100
100
  )
101
101
 
102
102
  @ptr.autorelease = auto_free
103
+ @parent = parent if parent
103
104
 
104
105
  @x = CoordinateAccessor.new(self, 0)
105
106
  @y = CoordinateAccessor.new(self, 1)
@@ -76,7 +76,7 @@ module Geos
76
76
  end
77
77
 
78
78
  def coord_seq
79
- CoordinateSequence.new(FFIGeos.GEOSGeom_getCoordSeq_r(Geos.current_handle, self.ptr), false)
79
+ CoordinateSequence.new(FFIGeos.GEOSGeom_getCoordSeq_r(Geos.current_handle, self.ptr), false, self)
80
80
  end
81
81
 
82
82
  def intersection(geom)
@@ -189,6 +189,13 @@ module Geos
189
189
  end
190
190
  end
191
191
 
192
+ if FFIGeos.respond_to?(:GEOSNode_r)
193
+ # Available in GEOS 3.3.4+
194
+ def node
195
+ cast_geometry_ptr(FFIGeos.GEOSNode_r(Geos.current_handle, self.ptr))
196
+ end
197
+ end
198
+
192
199
  def point_on_surface
193
200
  cast_geometry_ptr(FFIGeos.GEOSPointOnSurface_r(Geos.current_handle, self.ptr), :srid_copy => self.srid)
194
201
  end
@@ -473,6 +480,18 @@ module Geos
473
480
  double_ptr.read_double
474
481
  end
475
482
 
483
+ if FFIGeos.respond_to?(:GEOSNearestPoints_r)
484
+ # Available in GEOS 3.4+.
485
+ def nearest_points(geom)
486
+ check_geometry(geom)
487
+ ptr = FFIGeos.GEOSNearestPoints_r(Geos.current_handle, self.ptr, geom.ptr)
488
+
489
+ if !ptr.null?
490
+ CoordinateSequence.new(ptr)
491
+ end
492
+ end
493
+ end
494
+
476
495
  def snap(geom, tolerance)
477
496
  check_geometry(geom)
478
497
  cast_geometry_ptr(FFIGeos.GEOSSnap_r(Geos.current_handle, self.ptr, geom.ptr, tolerance), {
@@ -533,6 +552,12 @@ module Geos
533
552
  cast_geometry_ptr(FFIGeos.GEOSPolygonizer_getCutEdges_r(Geos.current_handle, ary, 1), :srid_copy => self.srid).to_a
534
553
  end
535
554
 
555
+ if FFIGeos.respond_to?(:GEOSDelaunayTriangulation_r)
556
+ def delaunay_triangulation(tolerance, options = {})
557
+ cast_geometry_ptr(FFIGeos.GEOSDelaunayTriangulation_r(Geos.current_handle, self.ptr, tolerance, options[:only_edges] ? 1 : 0))
558
+ end
559
+ end
560
+
536
561
  def to_prepared
537
562
  Geos::PreparedGeometry.new(self)
538
563
  end
@@ -0,0 +1,73 @@
1
+
2
+ module Geos
3
+ module Interrupt
4
+ class << self
5
+ if FFIGeos.respond_to?(:GEOS_interruptRegisterCallback)
6
+ # Check for the availability of the GEOS interruption API. The
7
+ # interruption API was added in GEOS 3.4.0.
8
+ def available?
9
+ true
10
+ end
11
+
12
+ # Registers an interrupt method or block that may be called during
13
+ # certain operations such as Geos::Geometry#buffer. During these
14
+ # blocks you can interrupt the current operation using
15
+ # Geos.request_interrupt and cancel that interrupt request using
16
+ # Geos.clear_interrupt.
17
+ #
18
+ # The return value for Geos.register_interrupt is a reference to the
19
+ # previously registered callback, allowing you to chain interrupt
20
+ # calls together by calling #call on the previously registered callback.
21
+ #
22
+ # HUGE NOTE CONCERNING INTERRUPTS: be careful when using interrupt
23
+ # blocks and how they reference other ruby objects. The ruby garbage
24
+ # collector may not play nicely with GEOS and objects may get cleaned
25
+ # up in unexpected ways while interrupts are firing.
26
+ def register(method_or_block = nil, &block)
27
+ if method_or_block.nil? && !block_given?
28
+ raise ArgumentError.new("Expected either a method or a block for Geos.register_interrupt")
29
+ elsif !method_or_block.nil? && block_given?
30
+ raise ArgumentError.new("Cannot use both a method and a block for Geos.register_interrupt")
31
+ else
32
+ retval = @current_interrupt_callback
33
+
34
+ @current_interrupt_callback = if method_or_block
35
+ FFIGeos.GEOS_interruptRegisterCallback(method_or_block)
36
+ method_or_block
37
+ elsif block_given?
38
+ FFIGeos.GEOS_interruptRegisterCallback(&block)
39
+ block
40
+ end
41
+
42
+ retval
43
+ end
44
+ end
45
+
46
+ # Interrupt the current operation. This method should generally be
47
+ # called from within a callback registered with Geos.register_interrupt
48
+ # but can be called at any time to interrupt the next interruptable
49
+ # operation.
50
+ def request
51
+ FFIGeos.GEOS_interruptRequest
52
+ end
53
+
54
+ # Cancel a request to interrupt the current operation. This method
55
+ # should be called from within a callback registered with
56
+ # Geos.register_interrupt but can be called at any time all the same.
57
+ def cancel
58
+ FFIGeos.GEOS_interruptCancel
59
+ end
60
+
61
+ def clear
62
+ FFIGeos.GEOS_interruptRegisterCallback(nil)
63
+ @current_interrupt_callback = nil
64
+ end
65
+ else
66
+ def available?
67
+ false
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module Geos
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.0"
5
5
  end
6
6
 
@@ -24,13 +24,6 @@ module Geos
24
24
  FFIGeos.GEOSWKBWriter_destroy_r(Geos.current_handle, ptr)
25
25
  end
26
26
 
27
- def set_options(options = {}) #:nodoc:
28
- [ :include_srid ].each do |k|
29
- self.send("#{k}=", options[k]) if options.has_key?(k)
30
- end
31
- end
32
- private :set_options
33
-
34
27
  # Options can be set temporarily for individual writes using an options
35
28
  # Hash. The only option currently available is :include_srid.
36
29
  def write(geom, options = nil)
@@ -92,5 +85,12 @@ module Geos
92
85
  check_enum_value(Geos::ByteOrders, val)
93
86
  FFIGeos.GEOSWKBWriter_setByteOrder_r(Geos.current_handle, self.ptr, val)
94
87
  end
88
+
89
+ private
90
+ def set_options(options) #:nodoc:
91
+ [ :include_srid ].each do |k|
92
+ self.send("#{k}=", options[k]) if options.has_key?(k)
93
+ end
94
+ end
95
95
  end
96
96
  end
@@ -481,6 +481,16 @@ class GeometryTests < MiniTest::Unit::TestCase
481
481
  )
482
482
  end
483
483
 
484
+ def test_node
485
+ skip unless ENV['FORCE_TESTS'] || Geos::Geometry.method_defined?(:node)
486
+
487
+ self_tester(
488
+ :node,
489
+ 'LINESTRING(0 0, 10 0, 5 -5, 5 5)',
490
+ 'MULTILINESTRING ((0 0, 5 0), (5 0, 10 0, 5 -5, 5 0), (5 0, 5 5))'
491
+ )
492
+ end
493
+
484
494
  def test_union_without_arguments
485
495
  self_tester(
486
496
  :union,
@@ -1299,6 +1309,35 @@ class GeometryTests < MiniTest::Unit::TestCase
1299
1309
  tester[9.0, geom_a, 'LINESTRING (3 0 , 10 0)']
1300
1310
  end
1301
1311
 
1312
+ def test_nearest_points
1313
+ skip unless ENV['FORCE_TESTS'] || Geos::Geometry.method_defined?(:nearest_points)
1314
+
1315
+ tester = lambda { |expected, g1, g2|
1316
+ geom_1 = read(g1)
1317
+ geom_2 = read(g2)
1318
+
1319
+ cs = geom_1.nearest_points(geom_2)
1320
+
1321
+ result = if cs
1322
+ cs.to_s
1323
+ end
1324
+
1325
+ assert_equal(expected, result)
1326
+ }
1327
+
1328
+ tester[
1329
+ nil,
1330
+ 'POINT EMPTY',
1331
+ 'POINT EMPTY'
1332
+ ]
1333
+
1334
+ tester[
1335
+ '5.0 5.0 NaN, 8.0 8.0 NaN',
1336
+ 'POLYGON((1 1, 1 5, 5 5, 5 1, 1 1))',
1337
+ 'POLYGON((8 8, 9 9, 9 10, 8 8))'
1338
+ ]
1339
+ end
1340
+
1302
1341
  def test_snap
1303
1342
  skip unless ENV['FORCE_TESTS'] || Geos::Geometry.method_defined?(:snap)
1304
1343
 
@@ -1642,4 +1681,52 @@ class GeometryTests < MiniTest::Unit::TestCase
1642
1681
  def test_to_s
1643
1682
  assert_match(/^\#<Geos::Point: .+>$/, read('POINT(0 0)').to_s)
1644
1683
  end
1684
+
1685
+ def test_delaunay_triangulation
1686
+ skip unless ENV['FORCE_TESTS'] || Geos::Geometry.method_defined?(:delaunay_triangulation)
1687
+
1688
+ tester = lambda { |expected, geom, *args|
1689
+ geom = read(geom)
1690
+ geom_tri = geom.delaunay_triangulation(*args)
1691
+ geom_tri.normalize!
1692
+
1693
+ assert_equal(expected, write(geom_tri))
1694
+ }
1695
+
1696
+ writer.trim = true
1697
+
1698
+ # empty polygon
1699
+ tester['GEOMETRYCOLLECTION EMPTY', 'POLYGON EMPTY', 0]
1700
+ tester['MULTILINESTRING EMPTY', 'POLYGON EMPTY', 0, { :only_edges => true }]
1701
+
1702
+ # single point
1703
+ tester['GEOMETRYCOLLECTION EMPTY', 'POINT (0 0)', 0]
1704
+ tester['MULTILINESTRING EMPTY', 'POINT (0 0)', 0, { :only_edges => true }]
1705
+
1706
+ # three collinear points
1707
+ tester['GEOMETRYCOLLECTION EMPTY', 'MULTIPOINT(0 0, 5 0, 10 0)', 0]
1708
+ tester['MULTILINESTRING ((5 0, 10 0), (0 0, 5 0))', 'MULTIPOINT(0 0, 5 0, 10 0)', 0, { :only_edges => true }]
1709
+
1710
+ # three points
1711
+ tester['GEOMETRYCOLLECTION (POLYGON ((0 0, 10 10, 5 0, 0 0)))', 'MULTIPOINT(0 0, 5 0, 10 10)', 0]
1712
+ tester['MULTILINESTRING ((5 0, 10 10), (0 0, 10 10), (0 0, 5 0))', 'MULTIPOINT(0 0, 5 0, 10 10)', 0, { :only_edges => true }]
1713
+
1714
+ # polygon with a hole
1715
+ tester[
1716
+ 'GEOMETRYCOLLECTION (POLYGON ((8 2, 10 10, 8.5 1, 8 2)), POLYGON ((7 8, 10 10, 8 2, 7 8)), POLYGON ((3 8, 10 10, 7 8, 3 8)), POLYGON ((2 2, 8 2, 8.5 1, 2 2)), POLYGON ((2 2, 7 8, 8 2, 2 2)), POLYGON ((2 2, 3 8, 7 8, 2 2)), POLYGON ((0.5 9, 10 10, 3 8, 0.5 9)), POLYGON ((0.5 9, 3 8, 2 2, 0.5 9)), POLYGON ((0 0, 2 2, 8.5 1, 0 0)), POLYGON ((0 0, 0.5 9, 2 2, 0 0)))',
1717
+ 'POLYGON((0 0, 8.5 1, 10 10, 0.5 9, 0 0),(2 2, 3 8, 7 8, 8 2, 2 2)))',
1718
+ 0
1719
+ ]
1720
+
1721
+ tester[
1722
+ 'MULTILINESTRING ((8.5 1, 10 10), (8 2, 10 10), (8 2, 8.5 1), (7 8, 10 10), (7 8, 8 2), (3 8, 10 10), (3 8, 7 8), (2 2, 8.5 1), (2 2, 8 2), (2 2, 7 8), (2 2, 3 8), (0.5 9, 10 10), (0.5 9, 3 8), (0.5 9, 2 2), (0 0, 8.5 1), (0 0, 2 2), (0 0, 0.5 9))',
1723
+ 'POLYGON((0 0, 8.5 1, 10 10, 0.5 9, 0 0),(2 2, 3 8, 7 8, 8 2, 2 2)))',
1724
+ 0, {
1725
+ :only_edges => true
1726
+ }
1727
+ ]
1728
+
1729
+ # four points with a tolerance making one collapse
1730
+ tester['MULTILINESTRING ((10 0, 10 10), (0 0, 10 10), (0 0, 10 0))', 'MULTIPOINT(0 0, 10 0, 10 10, 11 10)', 2.0, { :only_edges => true }]
1731
+ end
1645
1732
  end
@@ -0,0 +1,192 @@
1
+ # encoding: UTF-8
2
+
3
+ $: << File.dirname(__FILE__)
4
+ require 'test_helper'
5
+
6
+ class InterruptTests < MiniTest::Unit::TestCase
7
+ include TestHelper
8
+
9
+ def interrupt_method
10
+ interrupt_called
11
+ Geos::Interrupt.request
12
+ end
13
+
14
+ def interrupt_tester
15
+ yield
16
+ ensure
17
+ Geos::Interrupt.clear
18
+ end
19
+
20
+ def interrupt_called
21
+ @interrupt_calls += 1
22
+ end
23
+
24
+ def setup
25
+ super
26
+ @interrupt_calls = 0
27
+ end
28
+
29
+ def assert_interrupt_called(times = 0)
30
+ assert(@interrupt_calls > times, "Expected @interrupt_calls to be > #{times}")
31
+ end
32
+
33
+ def test_interrupt_with_method
34
+ skip unless ENV['FORCE_TESTS'] || Geos::Interrupt.available?
35
+
36
+ interrupt_tester do
37
+ geom = read('LINESTRING(0 0, 1 0)')
38
+
39
+ Geos::Interrupt.register(self.method(:interrupt_method))
40
+
41
+ begin
42
+ buffer = geom.buffer(1, 8)
43
+ rescue => e
44
+ assert_match(/^InterruptedException/, e.message)
45
+ assert_nil(buffer)
46
+ assert_interrupt_called
47
+ end
48
+ end
49
+ end
50
+
51
+ def test_interrupt_with_block
52
+ skip unless ENV['FORCE_TESTS'] || Geos::Interrupt.available?
53
+
54
+ interrupt_tester do
55
+ geom = read('LINESTRING(0 0, 1 0)')
56
+
57
+ Geos::Interrupt.register do
58
+ interrupt_called
59
+ Geos::Interrupt.request
60
+ end
61
+
62
+ begin
63
+ buffer = geom.buffer(1, 8)
64
+ rescue => e
65
+ assert_match(/^InterruptedException/, e.message)
66
+ assert_nil(buffer)
67
+ assert_interrupt_called
68
+ end
69
+ end
70
+ end
71
+
72
+ def test_interrupt_with_proc
73
+ skip unless ENV['FORCE_TESTS'] || Geos::Interrupt.available?
74
+
75
+ interrupt_tester do
76
+ geom = read('LINESTRING(0 0, 1 0)')
77
+
78
+ prc = proc {
79
+ interrupt_called
80
+ Geos::Interrupt.request
81
+ }
82
+
83
+ Geos::Interrupt.register(prc)
84
+
85
+ begin
86
+ buffer = geom.buffer(1, 8)
87
+ rescue => e
88
+ assert_match(/^InterruptedException/, e.message)
89
+ assert_nil(buffer)
90
+ assert_interrupt_called
91
+ end
92
+ end
93
+ end
94
+
95
+ def test_chain_interrupts
96
+ skip unless ENV['FORCE_TESTS'] || Geos::Interrupt.available?
97
+
98
+ interrupt_tester do
99
+ geom = read('LINESTRING(0 0, 1 0)')
100
+ prev = nil
101
+ called = []
102
+
103
+ prc_0 = proc {
104
+ interrupt_called
105
+ called << :prc_0
106
+ Geos::Interrupt.request
107
+ }
108
+
109
+ prc_1 = proc {
110
+ interrupt_called
111
+ called << :prc_1
112
+ prev.call if prev
113
+ }
114
+
115
+ Geos::Interrupt.register(prc_0)
116
+ prev = Geos::Interrupt.register(prc_1)
117
+
118
+ begin
119
+ buffer = geom.buffer(1, 8)
120
+ rescue => e
121
+ assert_match(/^InterruptedException/, e.message)
122
+ assert_nil(buffer)
123
+ assert_interrupt_called(1)
124
+ assert_equal([ :prc_1, :prc_0 ], called)
125
+ end
126
+ end
127
+ end
128
+
129
+ def test_cancel_interrupt
130
+ skip unless ENV['FORCE_TESTS'] || Geos::Interrupt.available?
131
+
132
+ interrupt_tester do
133
+ geom = read('LINESTRING(0 0, 1 0)')
134
+
135
+ Geos::Interrupt.register do
136
+ Geos::Interrupt.request
137
+ interrupt_called
138
+ Geos::Interrupt.cancel
139
+ end
140
+
141
+ buffer = geom.buffer(1, 8)
142
+
143
+ assert_kind_of(Geos::Polygon, buffer)
144
+ assert_interrupt_called(1)
145
+ end
146
+ end
147
+
148
+ def test_request_interrupt_without_a_callback
149
+ skip unless ENV['FORCE_TESTS'] || Geos::Interrupt.available?
150
+
151
+ geom = read('LINESTRING(0 0, 1 0)')
152
+ Geos::Interrupt.request
153
+
154
+ begin
155
+ buffer = geom.buffer(1, 8)
156
+ rescue => e
157
+ assert_match(/^InterruptedException/, e.message)
158
+ assert_nil(buffer)
159
+ end
160
+ end
161
+
162
+ def test_cancel_interrupt_without_a_callback
163
+ skip unless ENV['FORCE_TESTS'] || Geos::Interrupt.available?
164
+
165
+ geom = read('LINESTRING(0 0, 1 0)')
166
+ Geos::Interrupt.request
167
+ Geos::Interrupt.cancel
168
+
169
+ buffer = geom.buffer(1, 8)
170
+
171
+ assert_kind_of(Geos::Polygon, buffer)
172
+ end
173
+
174
+ def test_interrupt_with_method_and_block
175
+ skip unless ENV['FORCE_TESTS'] || Geos::Interrupt.available?
176
+
177
+ assert_raises(ArgumentError) do
178
+ Geos::Interrupt.register(self.method(:interrupt_method)) do
179
+ # no-op
180
+ end
181
+ end
182
+ end
183
+
184
+ def test_interrupt_without_method_or_block
185
+ skip unless ENV['FORCE_TESTS'] || Geos::Interrupt.available?
186
+
187
+ assert_raises(ArgumentError) do
188
+ Geos::Interrupt.register
189
+ end
190
+ end
191
+ end
192
+
@@ -85,6 +85,15 @@ class MiscTests < MiniTest::Unit::TestCase
85
85
  assert_equal(collection_a[0], collection_b[0])
86
86
  end
87
87
 
88
+ def test_segfault_on_coord_seq_parents
89
+ geom = read('LINESTRING(0 0, 1 0)')
90
+ cs = geom.envelope.exterior_ring.coord_seq
91
+
92
+ GC.start
93
+
94
+ assert_equal('0.0 0.0, 1.0 0.0, 1.0 0.0, 0.0 0.0, 0.0 0.0', cs.to_s)
95
+ end
96
+
88
97
  def test_cant_clone_buffer_params
89
98
  assert_raises(NoMethodError) do
90
99
  Geos::BufferParams.new.clone
@@ -7,6 +7,7 @@ if RUBY_VERSION >= '1.9'
7
7
  SimpleCov.merge_timeout(3600)
8
8
  SimpleCov.start do
9
9
  add_filter '/test/'
10
+ add_filter '/.bundle/'
10
11
  end
11
12
  end
12
13
 
metadata CHANGED
@@ -1,30 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-geos
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.2.1
4
+ version: 0.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - J Smith
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-08-02 00:00:00.000000000 Z
11
+ date: 2013-08-26 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: ffi
16
- type: :runtime
17
15
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
16
  requirements:
20
- - - ! '>='
17
+ - - '>='
21
18
  - !ruby/object:Gem::Version
22
19
  version: 1.0.0
20
+ type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: 1.0.0
30
27
  description: An ffi wrapper for GEOS, a C++ port of the Java Topology Suite (JTS).
@@ -46,6 +43,7 @@ files:
46
43
  - lib/ffi-geos/coordinate_sequence.rb
47
44
  - lib/ffi-geos/geometry.rb
48
45
  - lib/ffi-geos/geometry_collection.rb
46
+ - lib/ffi-geos/interrupt.rb
49
47
  - lib/ffi-geos/line_string.rb
50
48
  - lib/ffi-geos/linear_ring.rb
51
49
  - lib/ffi-geos/multi_line_string.rb
@@ -65,6 +63,7 @@ files:
65
63
  - test/coordinate_sequence_tests.rb
66
64
  - test/geometry_collection_tests.rb
67
65
  - test/geometry_tests.rb
66
+ - test/interrupt_tests.rb
68
67
  - test/line_string_tests.rb
69
68
  - test/linear_ring_tests.rb
70
69
  - test/misc_tests.rb
@@ -81,32 +80,32 @@ files:
81
80
  - test/wkt_writer_tests.rb
82
81
  homepage: http://github.com/dark-panda/ffi-geos
83
82
  licenses: []
83
+ metadata: {}
84
84
  post_install_message:
85
85
  rdoc_options: []
86
86
  require_paths:
87
87
  - lib
88
88
  required_ruby_version: !ruby/object:Gem::Requirement
89
- none: false
90
89
  requirements:
91
- - - ! '>='
90
+ - - '>='
92
91
  - !ruby/object:Gem::Version
93
92
  version: '0'
94
93
  required_rubygems_version: !ruby/object:Gem::Requirement
95
- none: false
96
94
  requirements:
97
- - - ! '>='
95
+ - - '>='
98
96
  - !ruby/object:Gem::Version
99
97
  version: '0'
100
98
  requirements: []
101
99
  rubyforge_project:
102
- rubygems_version: 1.8.23
100
+ rubygems_version: 2.0.3
103
101
  signing_key:
104
- specification_version: 3
102
+ specification_version: 4
105
103
  summary: An ffi wrapper for GEOS, a C++ port of the Java Topology Suite (JTS).
106
104
  test_files:
107
105
  - test/coordinate_sequence_tests.rb
108
106
  - test/geometry_collection_tests.rb
109
107
  - test/geometry_tests.rb
108
+ - test/interrupt_tests.rb
110
109
  - test/line_string_tests.rb
111
110
  - test/linear_ring_tests.rb
112
111
  - test/misc_tests.rb