ffi-geos 0.0.6 → 0.1.0

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