ffi-geos 0.2.1 → 0.3.0

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