ffi-geos 0.0.6 → 0.1.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.
@@ -21,13 +21,17 @@ module Geos
21
21
  if n < 0 || n >= self.num_geometries
22
22
  nil
23
23
  else
24
- cast_geometry_ptr(FFIGeos.GEOSGetGeometryN_r(Geos.current_handle, self.ptr, n), false)
24
+ cast_geometry_ptr(FFIGeos.GEOSGetGeometryN_r(Geos.current_handle, self.ptr, n), :auto_free => false)
25
25
  end
26
26
  end
27
27
  alias :geometry_n :get_geometry_n
28
28
 
29
29
  def [](*args)
30
- self.to_a[*args]
30
+ if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0
31
+ self.get_geometry_n(args.first)
32
+ else
33
+ self.to_a[*args]
34
+ end
31
35
  end
32
36
  alias :slice :[]
33
37
  alias :at :[]
@@ -30,12 +30,20 @@ module Geos
30
30
  if n < 0 || n >= self.num_points
31
31
  raise RuntimeError.new("Index out of bounds")
32
32
  else
33
- cast_geometry_ptr(FFIGeos.GEOSGeomGetPointN_r(Geos.current_handle, self.ptr, n))
33
+ cast_geometry_ptr(
34
+ FFIGeos.GEOSGeomGetPointN_r(Geos.current_handle, self.ptr, n), {
35
+ :srid_copy => self.srid
36
+ }
37
+ )
34
38
  end
35
39
  end
36
40
 
37
41
  def [](*args)
38
- self.to_a[*args]
42
+ if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0
43
+ self.point_n(args.first)
44
+ else
45
+ self.to_a[*args]
46
+ end
39
47
  end
40
48
  alias :slice :[]
41
49
 
@@ -49,7 +57,9 @@ module Geos
49
57
  options[:quad_segs],
50
58
  options[:join],
51
59
  options[:mitre_limit]
52
- ))
60
+ ), {
61
+ :srid_copy => self.srid
62
+ })
53
63
  end
54
64
 
55
65
  if FFIGeos.respond_to?(:GEOSisClosed_r)
@@ -1,5 +1,8 @@
1
1
 
2
2
  module Geos
3
3
  class LinearRing < LineString
4
+ def to_polygon
5
+ Geos.create_polygon(self, :srid => pick_srid_according_to_policy(self.srid))
6
+ end
4
7
  end
5
8
  end
@@ -7,8 +7,12 @@ module Geos
7
7
  FFIGeos.GEOSGeomGetX_r(Geos.current_handle, self.ptr, ret)
8
8
  }.read_double
9
9
  end
10
- alias :x :get_x
10
+ else
11
+ def get_x
12
+ self.coord_seq.get_x(0)
13
+ end
11
14
  end
15
+ alias :x :get_x
12
16
 
13
17
  if FFIGeos.respond_to?(:GEOSGeomGetY_r)
14
18
  def get_y
@@ -16,7 +20,61 @@ module Geos
16
20
  FFIGeos.GEOSGeomGetY_r(Geos.current_handle, self.ptr, ret)
17
21
  }.read_double
18
22
  end
19
- alias :y :get_y
23
+ else
24
+ def get_y
25
+ self.coord_seq.get_y(0)
26
+ end
27
+ end
28
+ alias :y :get_y
29
+
30
+ if FFIGeos.respond_to?(:GEOSGeomGetZ_r)
31
+ def get_z
32
+ FFI::MemoryPointer.new(:double).tap { |ret|
33
+ FFIGeos.GEOSGeomGetZ_r(Geos.current_handle, self.ptr, ret)
34
+ }.read_double
35
+ end
36
+ else
37
+ def get_z
38
+ self.coord_seq.get_z(0)
39
+ end
40
+ end
41
+ alias :z :get_z
42
+
43
+ def area
44
+ 0
45
+ end
46
+
47
+ def length
48
+ 0
49
+ end
50
+
51
+ def num_geometries
52
+ 1
53
+ end
54
+
55
+ def num_coordinates
56
+ 1
57
+ end
58
+
59
+ def normalize!
60
+ self
61
+ end
62
+ alias :normalize :normalize!
63
+
64
+ %w{
65
+ convex_hull
66
+ point_on_surface
67
+ centroid
68
+ envelope
69
+ topology_preserve_simplify
70
+ }.each do |method|
71
+ self.class_eval(<<-EOF)
72
+ def #{method}(*args)
73
+ self.dup.tap { |ret|
74
+ ret.srid = pick_srid_according_to_policy(ret.srid)
75
+ }
76
+ end
77
+ EOF
20
78
  end
21
79
  end
22
80
  end
@@ -9,12 +9,23 @@ module Geos
9
9
  if n < 0 || n >= self.num_interior_rings
10
10
  raise RuntimeError.new("Index out of bounds")
11
11
  else
12
- cast_geometry_ptr(FFIGeos.GEOSGetInteriorRingN_r(Geos.current_handle, self.ptr, n), false)
12
+ cast_geometry_ptr(
13
+ FFIGeos.GEOSGetInteriorRingN_r(Geos.current_handle, self.ptr, n), {
14
+ :auto_free => false,
15
+ :srid_copy => self.srid
16
+ }
17
+ )
13
18
  end
14
19
  end
20
+ alias :interior_ring :interior_ring_n
15
21
 
16
22
  def exterior_ring
17
- cast_geometry_ptr(FFIGeos.GEOSGetExteriorRing_r(Geos.current_handle, self.ptr), false)
23
+ cast_geometry_ptr(
24
+ FFIGeos.GEOSGetExteriorRing_r(Geos.current_handle, self.ptr), {
25
+ :auto_free => false,
26
+ :srid_copy => self.srid
27
+ }
28
+ )
18
29
  end
19
30
 
20
31
  def interior_rings
@@ -3,7 +3,11 @@ module Geos
3
3
  module Tools
4
4
  include GeomTypes
5
5
 
6
- def cast_geometry_ptr(geom_ptr, auto_free = true)
6
+ def cast_geometry_ptr(geom_ptr, options = {})
7
+ options = {
8
+ :auto_free => true
9
+ }.merge(options)
10
+
7
11
  if geom_ptr.null?
8
12
  raise RuntimeError.new("Tried to create a Geometry from a NULL pointer!")
9
13
  end
@@ -29,13 +33,42 @@ module Geos
29
33
  raise RuntimeError.new("Invalid geometry type")
30
34
  end
31
35
 
32
- klass.new(geom_ptr, auto_free)
36
+ klass.new(geom_ptr, options[:auto_free]).tap { |ret|
37
+ if options[:srid]
38
+ ret.srid = options[:srid] || 0
39
+ elsif options[:srid_copy]
40
+ ret.srid = if Geos.srid_copy_policy == :zero
41
+ 0
42
+ else
43
+ options[:srid_copy] || 0
44
+ end
45
+ end
46
+ }
33
47
  end
34
48
 
35
49
  def check_geometry(geom)
36
50
  raise TypeError.new("Expected Geos::Geometry") unless geom.is_a?(Geos::Geometry)
37
51
  end
38
52
 
53
+ def pick_srid_from_geoms(srid_a, srid_b, policy = Geos.srid_copy_policy)
54
+ case policy
55
+ when :zero
56
+ 0
57
+ when :lenient
58
+ srid_a
59
+ when :strict
60
+ raise Geos::MixedSRIDsError.new(srid_a, srid_b)
61
+ end
62
+ end
63
+
64
+ def pick_srid_according_to_policy(srid, policy = Geos.srid_copy_policy)
65
+ if srid != 0 && Geos.srid_copy_policy != :zero
66
+ self.srid
67
+ else
68
+ 0
69
+ end
70
+ end
71
+
39
72
  def bool_result(r)
40
73
  case r
41
74
  when 1
@@ -26,98 +26,140 @@ module Geos
26
26
  end
27
27
  end
28
28
 
29
- def create_point(cs)
29
+ def create_point(*args)
30
+ options = if args.last.is_a?(Hash)
31
+ args.pop
32
+ else
33
+ {}
34
+ end
35
+
36
+ if args.length == 1
37
+ cs = args.first
38
+ elsif args.length == 2
39
+ cs = CoordinateSequence.new(1, 2)
40
+ cs.x[0], cs.y[0] = args[0], args[1]
41
+ elsif args.length == 3
42
+ cs = CoordinateSequence.new(1, 3)
43
+ cs.x[0], cs.y[0], cs.z[0] = args
44
+ else
45
+ raise ArgumentError.new("Wrong number of arguments (#{args.length} for 1-3)")
46
+ end
47
+
30
48
  if cs.length != 1
31
49
  raise RuntimeError.new("IllegalArgumentException: Point coordinate list must contain a single element")
32
50
  end
33
51
 
34
- cs_clone = cs.clone
52
+ cs_dup = cs.dup
53
+ cs_dup.ptr.autorelease = false
35
54
 
36
- cast_geometry_ptr(FFIGeos.GEOSGeom_createPoint_r(Geos.current_handle, cs_clone.ptr)).tap {
37
- cs_clone.ptr.autorelease = false
38
- }
55
+ cast_geometry_ptr(FFIGeos.GEOSGeom_createPoint_r(Geos.current_handle, cs_dup.ptr), {
56
+ :srid => options[:srid]
57
+ })
39
58
  end
40
59
 
41
- def create_line_string(cs)
60
+ def create_line_string(cs, options = {})
61
+ cs = cs_from_cs_or_geom(cs)
62
+
42
63
  if cs.length <= 1 && cs.length != 0
43
64
  raise RuntimeError.new("IllegalArgumentException: point array must contain 0 or >1 elements")
44
65
  end
45
66
 
46
- cs_clone = cs.clone
67
+ cs_dup = cs.dup
68
+ cs_dup.ptr.autorelease = false
47
69
 
48
- cast_geometry_ptr(FFIGeos.GEOSGeom_createLineString_r(Geos.current_handle, cs_clone.ptr)).tap {
49
- cs_clone.ptr.autorelease = false
50
- }
70
+ cast_geometry_ptr(FFIGeos.GEOSGeom_createLineString_r(Geos.current_handle, cs_dup.ptr), {
71
+ :srid => options[:srid]
72
+ })
51
73
  end
52
74
 
53
- def create_linear_ring(cs)
75
+ def create_linear_ring(cs, options = {})
76
+ cs = cs_from_cs_or_geom(cs)
77
+
54
78
  if cs.length <= 1 && cs.length != 0
55
79
  raise RuntimeError.new("IllegalArgumentException: point array must contain 0 or >1 elements")
56
80
  end
57
81
 
58
- cs_clone = cs.clone
82
+ cs.ptr.autorelease = false
59
83
 
60
- cast_geometry_ptr(FFIGeos.GEOSGeom_createLinearRing_r(Geos.current_handle, cs_clone.ptr)).tap {
61
- cs_clone.ptr.autorelease = false
62
- }
84
+ ret = cast_geometry_ptr(FFIGeos.GEOSGeom_createLinearRing_r(Geos.current_handle, cs.ptr), {
85
+ :srid => options[:srid]
86
+ })
63
87
  end
64
88
 
65
- def create_polygon(outer, *inner)
66
- inner_clones = Array(inner).flatten.collect { |i|
89
+ def create_polygon(outer, *args)
90
+ options = if args.last.is_a?(Hash)
91
+ args.pop
92
+ else
93
+ {}
94
+ end
95
+
96
+ inner_dups = Array(args).flatten.collect { |i|
67
97
  force_to_linear_ring(i) or
68
98
  raise TypeError.new("Expected inner Array to contain Geos::LinearRing or Geos::CoordinateSequence objects")
69
99
  }
70
100
 
71
- outer_clone = force_to_linear_ring(outer) or
101
+ outer_dup = force_to_linear_ring(outer) or
72
102
  raise TypeError.new("Expected outer shell to be a Geos::LinearRing or Geos::CoordinateSequence")
73
103
 
74
- ary = FFI::MemoryPointer.new(:pointer, inner_clones.length)
75
- ary.write_array_of_pointer(inner_clones.map(&:ptr))
104
+ ary = FFI::MemoryPointer.new(:pointer, inner_dups.length)
105
+ ary.write_array_of_pointer(inner_dups.map(&:ptr))
76
106
 
77
- cast_geometry_ptr(FFIGeos.GEOSGeom_createPolygon_r(Geos.current_handle, outer_clone.ptr, ary, inner_clones.length)).tap {
78
- outer_clone.ptr.autorelease = false
79
- inner_clones.each { |i| i.ptr.autorelease = false }
107
+ outer_dup.ptr.autorelease = false
108
+ inner_dups.each { |i|
109
+ i.ptr.autorelease = false
80
110
  }
111
+
112
+ cast_geometry_ptr(FFIGeos.GEOSGeom_createPolygon_r(Geos.current_handle, outer_dup.ptr, ary, inner_dups.length), {
113
+ :srid => options[:srid]
114
+ })
81
115
  end
82
116
 
83
- def create_empty_point
84
- cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyPoint_r(Geos.current_handle))
117
+ def create_empty_point(options = {})
118
+ cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyPoint_r(Geos.current_handle), {
119
+ :srid => options[:srid]
120
+ })
85
121
  end
86
122
 
87
- def create_empty_line_string
88
- cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyLineString_r(Geos.current_handle))
123
+ def create_empty_line_string(options = {})
124
+ cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyLineString_r(Geos.current_handle), {
125
+ :srid => options[:srid]
126
+ })
89
127
  end
90
128
 
91
- def create_empty_polygon
92
- cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyPolygon_r(Geos.current_handle))
129
+ def create_empty_polygon(options = {})
130
+ cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyPolygon_r(Geos.current_handle), {
131
+ :srid => options[:srid]
132
+ })
93
133
  end
94
134
 
95
- def create_empty_collection(t)
135
+ def create_empty_collection(t, options = {})
96
136
  check_enum_value(Geos::GeometryTypes, t)
97
- cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyCollection_r(Geos.current_handle, t))
137
+ cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyCollection_r(Geos.current_handle, t), {
138
+ :srid => options[:srid]
139
+ })
98
140
  end
99
141
 
100
- def create_empty_multi_point
101
- create_empty_collection(:multi_point)
142
+ def create_empty_multi_point(options = {})
143
+ create_empty_collection(:multi_point, options)
102
144
  end
103
145
 
104
- def create_empty_multi_line_string
105
- create_empty_collection(:multi_line_string)
146
+ def create_empty_multi_line_string(options = {})
147
+ create_empty_collection(:multi_line_string, options)
106
148
  end
107
149
 
108
- def create_empty_multi_polygon
109
- create_empty_collection(:multi_polygon)
150
+ def create_empty_multi_polygon(options = {})
151
+ create_empty_collection(:multi_polygon, options)
110
152
  end
111
153
 
112
- def create_empty_geometry_collection
113
- create_empty_collection(:geometry_collection)
154
+ def create_empty_geometry_collection(options = {})
155
+ create_empty_collection(:geometry_collection, options)
114
156
  end
115
157
 
116
- def create_empty_linear_ring
117
- Geos::WktReader.new.read('LINEARRING EMPTY')
158
+ def create_empty_linear_ring(options = {})
159
+ Geos::WktReader.new.read('LINEARRING EMPTY', options)
118
160
  end
119
161
 
120
- def create_collection(t, *geoms)
162
+ def create_collection(t, *args)
121
163
  check_enum_value(Geos::GeometryTypes, t)
122
164
 
123
165
  klass = case t
@@ -131,47 +173,63 @@ module Geos
131
173
  Geos::Geometry
132
174
  end
133
175
 
134
- geoms = Array(geoms).flatten.tap { |i|
176
+ options = if args.last.is_a?(Hash)
177
+ args.pop
178
+ else
179
+ {}
180
+ end
181
+
182
+ geoms = Array(args).flatten.tap { |i|
135
183
  if i.detect { |g| !g.is_a?(klass) }
136
184
  raise TypeError.new("Expected geoms Array to contain #{klass} objects")
137
185
  end
138
186
  }
139
187
 
140
- geoms_clones = geoms.map(&:clone)
188
+ geoms_dups = geoms.map(&:dup)
189
+ geoms_dups.each { |i|
190
+ i.ptr.autorelease = false
191
+ }
141
192
 
142
193
  ary = FFI::MemoryPointer.new(:pointer, geoms.length)
143
- ary.write_array_of_pointer(geoms_clones.map(&:ptr))
194
+ ary.write_array_of_pointer(geoms_dups.map(&:ptr))
144
195
 
145
- cast_geometry_ptr(FFIGeos.GEOSGeom_createCollection_r(Geos.current_handle, t, ary, geoms_clones.length)).tap {
146
- geoms_clones.each { |i|
147
- i.ptr.autorelease = false
148
- }
149
- }
196
+ cast_geometry_ptr(FFIGeos.GEOSGeom_createCollection_r(Geos.current_handle, t, ary, geoms_dups.length), {
197
+ :srid => options[:srid]
198
+ })
150
199
  end
151
200
 
152
- def create_multi_point(*geoms)
153
- create_collection(:multi_point, *geoms)
201
+ def create_multi_point(*args)
202
+ create_collection(:multi_point, *args)
154
203
  end
155
204
 
156
- def create_multi_line_string(*geoms)
157
- create_collection(:multi_line_string, *geoms)
205
+ def create_multi_line_string(*args)
206
+ create_collection(:multi_line_string, *args)
158
207
  end
159
208
 
160
- def create_multi_polygon(*geoms)
161
- create_collection(:multi_polygon, *geoms)
209
+ def create_multi_polygon(*args)
210
+ create_collection(:multi_polygon, *args)
162
211
  end
163
212
 
164
- def create_geometry_collection(*geoms)
165
- create_collection(:geometry_collection, *geoms)
213
+ def create_geometry_collection(*args)
214
+ create_collection(:geometry_collection, *args)
166
215
  end
167
216
 
168
217
  private
169
- def force_to_linear_ring(geom)
170
- case geom
218
+ def cs_from_cs_or_geom(geom_or_cs)
219
+ case geom_or_cs
220
+ when Array
221
+ Geos::CoordinateSequence.new(geom_or_cs)
222
+ when Geos::CoordinateSequence
223
+ geom_or_cs.dup
224
+ end
225
+ end
226
+
227
+ def force_to_linear_ring(geom_or_cs)
228
+ case geom_or_cs
171
229
  when Geos::CoordinateSequence
172
- geom.to_linear_ring
230
+ geom_or_cs.to_linear_ring
173
231
  when Geos::LinearRing
174
- geom.clone
232
+ geom_or_cs.dup
175
233
  end
176
234
  end
177
235
  end