ffi-geos 1.2.1 → 1.2.2
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.
- checksums.yaml +5 -5
- data/.rubocop.yml +20 -0
- data/.travis.yml +7 -3
- data/Gemfile +1 -1
- data/Guardfile +4 -5
- data/ffi-geos.gemspec +1 -1
- data/lib/ffi-geos.rb +212 -196
- data/lib/ffi-geos/buffer_params.rb +9 -20
- data/lib/ffi-geos/coordinate_sequence.rb +342 -58
- data/lib/ffi-geos/geometry.rb +167 -178
- data/lib/ffi-geos/geometry_collection.rb +60 -12
- data/lib/ffi-geos/interrupt.rb +2 -4
- data/lib/ffi-geos/line_string.rb +146 -37
- data/lib/ffi-geos/linear_ring.rb +2 -3
- data/lib/ffi-geos/multi_line_string.rb +1 -2
- data/lib/ffi-geos/multi_point.rb +0 -1
- data/lib/ffi-geos/multi_polygon.rb +0 -1
- data/lib/ffi-geos/point.rb +69 -14
- data/lib/ffi-geos/polygon.rb +110 -21
- data/lib/ffi-geos/prepared_geometry.rb +11 -12
- data/lib/ffi-geos/strtree.rb +41 -52
- data/lib/ffi-geos/tools.rb +15 -18
- data/lib/ffi-geos/utils.rb +27 -44
- data/lib/ffi-geos/version.rb +1 -3
- data/lib/ffi-geos/wkb_reader.rb +4 -9
- data/lib/ffi-geos/wkb_writer.rb +14 -18
- data/lib/ffi-geos/wkt_reader.rb +2 -5
- data/lib/ffi-geos/wkt_writer.rb +17 -22
- data/test/.rubocop.yml +36 -0
- data/test/coordinate_sequence_tests.rb +263 -14
- data/test/geometry_collection_tests.rb +412 -1
- data/test/geometry_tests.rb +156 -86
- data/test/interrupt_tests.rb +2 -4
- data/test/line_string_tests.rb +212 -23
- data/test/linear_ring_tests.rb +1 -2
- data/test/misc_tests.rb +28 -29
- data/test/multi_line_string_tests.rb +0 -1
- data/test/point_tests.rb +158 -1
- data/test/polygon_tests.rb +284 -1
- data/test/prepared_geometry_tests.rb +1 -3
- data/test/strtree_tests.rb +9 -10
- data/test/test_helper.rb +49 -18
- data/test/tools_tests.rb +1 -3
- data/test/utils_tests.rb +22 -22
- data/test/wkb_reader_tests.rb +10 -9
- data/test/wkb_writer_tests.rb +5 -13
- data/test/wkt_reader_tests.rb +1 -2
- data/test/wkt_writer_tests.rb +9 -14
- metadata +6 -3
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module Geos
|
@@ -33,7 +32,7 @@ module Geos
|
|
33
32
|
|
34
33
|
@params = {}
|
35
34
|
VALID_PARAMETERS.each do |param|
|
36
|
-
|
35
|
+
send("#{param}=", params[param])
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
@@ -44,43 +43,33 @@ module Geos
|
|
44
43
|
def endcap=(value)
|
45
44
|
check_enum_value(Geos::BufferCapStyles, value)
|
46
45
|
|
47
|
-
if bool_result(FFIGeos.GEOSBufferParams_setEndCapStyle_r(Geos.current_handle_pointer, ptr, value))
|
48
|
-
@params[:endcap] = symbol_for_enum(Geos::BufferCapStyles, value)
|
49
|
-
end
|
46
|
+
@params[:endcap] = symbol_for_enum(Geos::BufferCapStyles, value) if bool_result(FFIGeos.GEOSBufferParams_setEndCapStyle_r(Geos.current_handle_pointer, ptr, value))
|
50
47
|
end
|
51
48
|
|
52
49
|
def join=(value)
|
53
50
|
check_enum_value(Geos::BufferJoinStyles, value)
|
54
51
|
|
55
|
-
if bool_result(FFIGeos.GEOSBufferParams_setJoinStyle_r(Geos.current_handle_pointer, ptr, value))
|
56
|
-
@params[:join] = symbol_for_enum(Geos::BufferJoinStyles, value)
|
57
|
-
end
|
52
|
+
@params[:join] = symbol_for_enum(Geos::BufferJoinStyles, value) if bool_result(FFIGeos.GEOSBufferParams_setJoinStyle_r(Geos.current_handle_pointer, ptr, value))
|
58
53
|
end
|
59
54
|
|
60
55
|
def mitre_limit=(value)
|
61
|
-
if bool_result(FFIGeos.GEOSBufferParams_setMitreLimit_r(Geos.current_handle_pointer, ptr, value))
|
62
|
-
@params[:mitre_limit] = value
|
63
|
-
end
|
56
|
+
@params[:mitre_limit] = value if bool_result(FFIGeos.GEOSBufferParams_setMitreLimit_r(Geos.current_handle_pointer, ptr, value))
|
64
57
|
end
|
65
58
|
|
66
59
|
def quad_segs=(value)
|
67
|
-
if bool_result(FFIGeos.GEOSBufferParams_setQuadrantSegments_r(Geos.current_handle_pointer, ptr, value))
|
68
|
-
@params[:quad_segs] = value
|
69
|
-
end
|
60
|
+
@params[:quad_segs] = value if bool_result(FFIGeos.GEOSBufferParams_setQuadrantSegments_r(Geos.current_handle_pointer, ptr, value))
|
70
61
|
end
|
71
62
|
|
72
63
|
def single_sided=(value)
|
73
|
-
if bool_result(FFIGeos.GEOSBufferParams_setSingleSided_r(Geos.current_handle_pointer, ptr, Geos::Tools.bool_to_int(value)))
|
74
|
-
@params[:single_sided] = value
|
75
|
-
end
|
64
|
+
@params[:single_sided] = value if bool_result(FFIGeos.GEOSBufferParams_setSingleSided_r(Geos.current_handle_pointer, ptr, Geos::Tools.bool_to_int(value)))
|
76
65
|
end
|
77
66
|
|
78
67
|
VALID_PARAMETERS.each do |param|
|
79
|
-
|
68
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
80
69
|
def #{param}
|
81
70
|
@params[:#{param}]
|
82
71
|
end
|
83
|
-
|
72
|
+
RUBY
|
84
73
|
end
|
85
74
|
else
|
86
75
|
attr_accessor(*VALID_PARAMETERS)
|
@@ -89,7 +78,7 @@ module Geos
|
|
89
78
|
params = Geos::Constants::BUFFER_PARAM_DEFAULTS.merge(params)
|
90
79
|
|
91
80
|
VALID_PARAMETERS.each do |param|
|
92
|
-
|
81
|
+
send("#{param}=", params[param])
|
93
82
|
end
|
94
83
|
end
|
95
84
|
end
|
@@ -1,8 +1,6 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module Geos
|
5
|
-
|
6
4
|
# A CoordinateSequence is a list of coordinates in a Geometry.
|
7
5
|
class CoordinateSequence
|
8
6
|
class ParseError < Geos::ParseError
|
@@ -19,22 +17,22 @@ module Geos
|
|
19
17
|
end
|
20
18
|
|
21
19
|
def [](idx)
|
22
|
-
parent.get_ordinate(idx,
|
20
|
+
parent.get_ordinate(idx, dimension)
|
23
21
|
end
|
24
22
|
|
25
23
|
def []=(idx, value)
|
26
|
-
parent.set_ordinate(idx,
|
24
|
+
parent.set_ordinate(idx, dimension, value)
|
27
25
|
end
|
28
26
|
|
29
27
|
def each
|
30
28
|
if block_given?
|
31
29
|
parent.length.times do |n|
|
32
|
-
yield parent.get_ordinate(n,
|
30
|
+
yield parent.get_ordinate(n, dimension)
|
33
31
|
end
|
34
32
|
self
|
35
33
|
else
|
36
34
|
parent.length.times.collect { |n|
|
37
|
-
parent.get_ordinate(n,
|
35
|
+
parent.get_ordinate(n, dimension)
|
38
36
|
}.to_enum
|
39
37
|
end
|
40
38
|
end
|
@@ -73,9 +71,9 @@ module Geos
|
|
73
71
|
if lengths.empty?
|
74
72
|
[ 0, 0 ]
|
75
73
|
elsif lengths.length != 1
|
76
|
-
raise ParseError
|
74
|
+
raise ParseError, 'Different sized points found in Array'
|
77
75
|
elsif !lengths.first.between?(1, 3)
|
78
|
-
raise ParseError
|
76
|
+
raise ParseError, 'Expected points to contain 1-3 elements'
|
79
77
|
else
|
80
78
|
[ points.length, points.first.length ]
|
81
79
|
end
|
@@ -83,7 +81,7 @@ module Geos
|
|
83
81
|
args.first.values_at(:size, :dimensions)
|
84
82
|
else
|
85
83
|
if !args.length.between?(0, 2)
|
86
|
-
raise ArgumentError
|
84
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 0-2)"
|
87
85
|
else
|
88
86
|
[ args[0], args[1] ]
|
89
87
|
end
|
@@ -107,11 +105,11 @@ module Geos
|
|
107
105
|
@y = CoordinateAccessor.new(self, 1)
|
108
106
|
@z = CoordinateAccessor.new(self, 2)
|
109
107
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
108
|
+
return unless points
|
109
|
+
|
110
|
+
points.each_with_index do |point, idx|
|
111
|
+
point.each_with_index do |val, dim|
|
112
|
+
set_ordinate(idx, dim, val)
|
115
113
|
end
|
116
114
|
end
|
117
115
|
end
|
@@ -135,13 +133,13 @@ module Geos
|
|
135
133
|
# 2-dimensional CoordinateSequences.
|
136
134
|
def each
|
137
135
|
if block_given?
|
138
|
-
|
139
|
-
yield
|
136
|
+
length.times do |n|
|
137
|
+
yield build_coordinate(n)
|
140
138
|
end
|
141
139
|
self
|
142
140
|
else
|
143
|
-
|
144
|
-
|
141
|
+
length.times.collect { |n|
|
142
|
+
build_coordinate(n)
|
145
143
|
}.to_enum
|
146
144
|
end
|
147
145
|
end
|
@@ -149,82 +147,82 @@ module Geos
|
|
149
147
|
def [](*args)
|
150
148
|
if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0
|
151
149
|
i = args.first
|
152
|
-
ary = [
|
153
|
-
ary <<
|
150
|
+
ary = [ get_x(i), get_y(i) ]
|
151
|
+
ary << get_z(i) if has_z?
|
154
152
|
ary
|
155
153
|
else
|
156
|
-
|
154
|
+
to_a[*args]
|
157
155
|
end
|
158
156
|
end
|
159
|
-
|
157
|
+
alias slice []
|
160
158
|
|
161
159
|
def has_z?
|
162
|
-
|
160
|
+
dimensions == 3
|
163
161
|
end
|
164
162
|
|
165
163
|
# Sets the x value of a coordinate. Can also be set via #x[]=.
|
166
164
|
def set_x(idx, val)
|
167
|
-
|
168
|
-
FFIGeos.GEOSCoordSeq_setX_r(Geos.current_handle_pointer,
|
165
|
+
check_bounds(idx)
|
166
|
+
FFIGeos.GEOSCoordSeq_setX_r(Geos.current_handle_pointer, ptr, idx, val.to_f)
|
169
167
|
end
|
170
168
|
|
171
169
|
# Sets the y value of a coordinate. Can also be set via #y[]=.
|
172
170
|
def set_y(idx, val)
|
173
|
-
|
174
|
-
FFIGeos.GEOSCoordSeq_setY_r(Geos.current_handle_pointer,
|
171
|
+
check_bounds(idx)
|
172
|
+
FFIGeos.GEOSCoordSeq_setY_r(Geos.current_handle_pointer, ptr, idx, val.to_f)
|
175
173
|
end
|
176
174
|
|
177
175
|
# Sets the z value of a coordinate. Can also be set via #z[]=.
|
178
176
|
def set_z(idx, val)
|
179
|
-
|
180
|
-
FFIGeos.GEOSCoordSeq_setZ_r(Geos.current_handle_pointer,
|
177
|
+
check_bounds(idx)
|
178
|
+
FFIGeos.GEOSCoordSeq_setZ_r(Geos.current_handle_pointer, ptr, idx, val.to_f)
|
181
179
|
end
|
182
180
|
|
183
181
|
def set_ordinate(idx, dim, val)
|
184
|
-
|
185
|
-
FFIGeos.GEOSCoordSeq_setOrdinate_r(Geos.current_handle_pointer,
|
182
|
+
check_bounds(idx)
|
183
|
+
FFIGeos.GEOSCoordSeq_setOrdinate_r(Geos.current_handle_pointer, ptr, idx, dim, val.to_f)
|
186
184
|
end
|
187
185
|
|
188
186
|
# Gets the x value of a coordinate. Can also be retrieved via #x[].
|
189
187
|
def get_x(idx)
|
190
|
-
|
188
|
+
check_bounds(idx)
|
191
189
|
double_ptr = FFI::MemoryPointer.new(:double)
|
192
|
-
FFIGeos.GEOSCoordSeq_getX_r(Geos.current_handle_pointer,
|
190
|
+
FFIGeos.GEOSCoordSeq_getX_r(Geos.current_handle_pointer, ptr, idx, double_ptr)
|
193
191
|
double_ptr.read_double
|
194
192
|
end
|
195
193
|
|
196
194
|
# Gets the y value of a coordinate. Can also be retrieved via #y[].
|
197
195
|
def get_y(idx)
|
198
|
-
|
196
|
+
check_bounds(idx)
|
199
197
|
double_ptr = FFI::MemoryPointer.new(:double)
|
200
|
-
FFIGeos.GEOSCoordSeq_getY_r(Geos.current_handle_pointer,
|
198
|
+
FFIGeos.GEOSCoordSeq_getY_r(Geos.current_handle_pointer, ptr, idx, double_ptr)
|
201
199
|
double_ptr.read_double
|
202
200
|
end
|
203
201
|
|
204
202
|
# Gets the z value of a coordinate. Can also be retrieved via #z[].
|
205
203
|
def get_z(idx)
|
206
|
-
|
204
|
+
check_bounds(idx)
|
207
205
|
double_ptr = FFI::MemoryPointer.new(:double)
|
208
|
-
FFIGeos.GEOSCoordSeq_getZ_r(Geos.current_handle_pointer,
|
206
|
+
FFIGeos.GEOSCoordSeq_getZ_r(Geos.current_handle_pointer, ptr, idx, double_ptr)
|
209
207
|
double_ptr.read_double
|
210
208
|
end
|
211
209
|
|
212
210
|
def get_ordinate(idx, dim)
|
213
|
-
|
211
|
+
check_bounds(idx)
|
214
212
|
double_ptr = FFI::MemoryPointer.new(:double)
|
215
|
-
FFIGeos.GEOSCoordSeq_getOrdinate_r(Geos.current_handle_pointer,
|
213
|
+
FFIGeos.GEOSCoordSeq_getOrdinate_r(Geos.current_handle_pointer, ptr, idx, dim, double_ptr)
|
216
214
|
double_ptr.read_double
|
217
215
|
end
|
218
216
|
|
219
217
|
def length
|
220
218
|
int_ptr = FFI::MemoryPointer.new(:int)
|
221
|
-
FFIGeos.GEOSCoordSeq_getSize_r(Geos.current_handle_pointer,
|
219
|
+
FFIGeos.GEOSCoordSeq_getSize_r(Geos.current_handle_pointer, ptr, int_ptr)
|
222
220
|
int_ptr.read_int
|
223
221
|
end
|
224
|
-
|
222
|
+
alias size length
|
225
223
|
|
226
224
|
def empty?
|
227
|
-
|
225
|
+
length.zero?
|
228
226
|
end
|
229
227
|
|
230
228
|
def dimensions
|
@@ -232,47 +230,333 @@ module Geos
|
|
232
230
|
@dimensions
|
233
231
|
else
|
234
232
|
int_ptr = FFI::MemoryPointer.new(:int)
|
235
|
-
FFIGeos.GEOSCoordSeq_getDimensions_r(Geos.current_handle_pointer,
|
233
|
+
FFIGeos.GEOSCoordSeq_getDimensions_r(Geos.current_handle_pointer, ptr, int_ptr)
|
236
234
|
@dimensions = int_ptr.read_int
|
237
235
|
end
|
238
236
|
end
|
239
237
|
|
240
238
|
def to_point(options = {})
|
241
|
-
Geos.create_point(self, :
|
239
|
+
Geos.create_point(self, srid: options[:srid])
|
242
240
|
end
|
243
241
|
|
244
242
|
def to_linear_ring(options = {})
|
245
|
-
Geos.create_linear_ring(self, :
|
243
|
+
Geos.create_linear_ring(self, srid: options[:srid])
|
246
244
|
end
|
247
245
|
|
248
246
|
def to_line_string(options = {})
|
249
|
-
Geos.create_line_string(self, :
|
247
|
+
Geos.create_line_string(self, srid: options[:srid])
|
250
248
|
end
|
251
249
|
|
252
250
|
def to_polygon(options = {})
|
253
|
-
Geos.create_polygon(self, :
|
251
|
+
Geos.create_polygon(self, srid: options[:srid])
|
254
252
|
end
|
255
253
|
|
256
254
|
def to_s
|
257
|
-
|
255
|
+
entries.collect { |entry|
|
258
256
|
entry.join(' ')
|
259
257
|
}.join(', ')
|
260
258
|
end
|
261
259
|
|
262
|
-
|
260
|
+
%w{ x y z }.each do |m|
|
261
|
+
class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
262
|
+
def #{m}_max
|
263
|
+
ret = nil
|
264
|
+
self.length.times do |i|
|
265
|
+
value = self.get_#{m}(i)
|
266
|
+
ret = value if !ret || value >= ret
|
267
|
+
end
|
268
|
+
ret
|
269
|
+
end
|
270
|
+
|
271
|
+
def #{m}_min
|
272
|
+
ret = nil
|
273
|
+
self.length.times do |i|
|
274
|
+
value = self.get_#{m}(i)
|
275
|
+
ret = value if !ret || value <= ret
|
276
|
+
end
|
277
|
+
ret
|
278
|
+
end
|
279
|
+
EOF
|
280
|
+
end
|
281
|
+
|
282
|
+
def snap_to_grid!(*args)
|
283
|
+
grid = {
|
284
|
+
:offset_x => 0, # 1
|
285
|
+
:offset_y => 0, # 2
|
286
|
+
:offset_z => 0, # -
|
287
|
+
:size_x => 0, # 3
|
288
|
+
:size_y => 0, # 4
|
289
|
+
:size_z => 0 # -
|
290
|
+
}
|
291
|
+
|
292
|
+
if args.length == 1 && args[0].is_a?(Numeric)
|
293
|
+
grid[:size_x] = grid[:size_y] = grid[:size_z] = args[0]
|
294
|
+
elsif args[0].is_a?(Hash)
|
295
|
+
grid.merge!(args[0])
|
296
|
+
end
|
297
|
+
|
298
|
+
if grid[:size]
|
299
|
+
grid[:size_x] = grid[:size_y] = grid[:size_z] = grid[:size]
|
300
|
+
end
|
301
|
+
|
302
|
+
if grid[:offset]
|
303
|
+
case grid[:offset]
|
304
|
+
when Geos::Geometry
|
305
|
+
point = grid[:offset].centroid
|
306
|
+
|
307
|
+
grid[:offset_x] = point.x
|
308
|
+
grid[:offset_y] = point.y
|
309
|
+
grid[:offset_z] = point.z
|
310
|
+
when Array
|
311
|
+
grid[:offset_x], grid[:offset_y], grid[:offset_z] = grid[:offset]
|
312
|
+
else
|
313
|
+
raise ArgumentError.new("Expected :offset option to be a Geos::Point")
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
self.length.times do |i|
|
318
|
+
if grid[:size_x] != 0
|
319
|
+
self.x[i] = ((self.x[i] - grid[:offset_x]) / grid[:size_x]).round * grid[:size_x] + grid[:offset_x]
|
320
|
+
end
|
321
|
+
|
322
|
+
if grid[:size_y] != 0
|
323
|
+
self.y[i] = ((self.y[i] - grid[:offset_y]) / grid[:size_y]).round * grid[:size_y] + grid[:offset_y]
|
324
|
+
end
|
325
|
+
|
326
|
+
if self.has_z? && grid[:size_z] != 0
|
327
|
+
self.z[i] = ((self.z[i] - grid[:offset_z]) / grid[:size_z]).round * grid[:size_z] + grid[:offset_z]
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
cs = self.remove_duplicate_coords
|
332
|
+
@ptr = cs.ptr
|
333
|
+
|
334
|
+
self
|
335
|
+
end
|
336
|
+
|
337
|
+
def snap_to_grid(*args)
|
338
|
+
self.dup.snap_to_grid!(*args)
|
339
|
+
end
|
340
|
+
|
341
|
+
def remove_duplicate_coords
|
342
|
+
Geos::CoordinateSequence.new(self.to_a.inject([]) { |memo, v|
|
343
|
+
memo << v unless memo.last == v
|
344
|
+
memo
|
345
|
+
})
|
346
|
+
end
|
347
|
+
|
348
|
+
def affine!(options)
|
349
|
+
options.default = 0.0
|
350
|
+
|
351
|
+
if self.has_z?
|
352
|
+
self.length.times do |i|
|
353
|
+
x, y, z = self.x[i], self.y[i], self.z[i]
|
354
|
+
|
355
|
+
self.x[i] = options[:afac] * x + options[:bfac] * y + options[:cfac] * z + options[:xoff]
|
356
|
+
self.y[i] = options[:dfac] * x + options[:efac] * y + options[:ffac] * z + options[:yoff]
|
357
|
+
self.z[i] = options[:gfac] * x + options[:hfac] * y + options[:ifac] * z + options[:zoff]
|
358
|
+
end
|
359
|
+
else
|
360
|
+
self.length.times do |i|
|
361
|
+
x, y = self.x[i], self.y[i]
|
362
|
+
|
363
|
+
self.x[i] = options[:afac] * x + options[:bfac] * y + options[:xoff]
|
364
|
+
self.y[i] = options[:dfac] * x + options[:efac] * y + options[:yoff]
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
self
|
369
|
+
end
|
263
370
|
|
264
|
-
def
|
265
|
-
|
266
|
-
|
371
|
+
def affine(options)
|
372
|
+
self.dup.affine!(options)
|
373
|
+
end
|
374
|
+
|
375
|
+
def rotate!(radians, origin = [ 0.0, 0.0 ])
|
376
|
+
origin = case origin
|
377
|
+
when Array
|
378
|
+
origin
|
379
|
+
when Geos::Geometry
|
380
|
+
center = origin.centroid
|
381
|
+
[ center.x, center.y ]
|
382
|
+
else
|
383
|
+
raise ArgumentError.new("Expected an Array or a Geos::Geometry for the origin")
|
267
384
|
end
|
385
|
+
|
386
|
+
self.affine!({
|
387
|
+
:afac => Math.cos(radians),
|
388
|
+
:bfac => -Math.sin(radians),
|
389
|
+
:cfac => 0,
|
390
|
+
:dfac => Math.sin(radians),
|
391
|
+
:efac => Math.cos(radians),
|
392
|
+
:ffac => 0,
|
393
|
+
:gfac => 0,
|
394
|
+
:hfac => 0,
|
395
|
+
:ifac => 1,
|
396
|
+
:xoff => origin[0] - Math.cos(radians) * origin[0] + Math.sin(radians) * origin[1],
|
397
|
+
:yoff => origin[1] - Math.sin(radians) * origin[0] - Math.cos(radians) * origin[1],
|
398
|
+
:zoff => 0
|
399
|
+
})
|
400
|
+
end
|
401
|
+
|
402
|
+
def rotate(radians, origin = [ 0.0, 0.0 ])
|
403
|
+
self.dup.rotate!(radians, origin)
|
404
|
+
end
|
405
|
+
|
406
|
+
def rotate_x!(radians)
|
407
|
+
self.affine!({
|
408
|
+
:afac => 1,
|
409
|
+
:bfac => 0,
|
410
|
+
:cfac => 0,
|
411
|
+
:dfac => 0,
|
412
|
+
:efac => Math.cos(radians),
|
413
|
+
:ffac => -Math.sin(radians),
|
414
|
+
:gfac => 0,
|
415
|
+
:hfac => Math.sin(radians),
|
416
|
+
:ifac => Math.cos(radians),
|
417
|
+
:xoff => 0,
|
418
|
+
:yoff => 0,
|
419
|
+
:zoff => 0
|
420
|
+
})
|
421
|
+
end
|
422
|
+
|
423
|
+
def rotate_x(radians)
|
424
|
+
self.dup.rotate_x!(radians)
|
425
|
+
end
|
426
|
+
|
427
|
+
def rotate_y!(radians)
|
428
|
+
self.affine!({
|
429
|
+
:afac => Math.cos(radians),
|
430
|
+
:bfac => 0,
|
431
|
+
:cfac => Math.sin(radians),
|
432
|
+
:dfac => 0,
|
433
|
+
:efac => 1,
|
434
|
+
:ffac => 0,
|
435
|
+
:gfac => -Math.sin(radians),
|
436
|
+
:hfac => 0,
|
437
|
+
:ifac => Math.cos(radians),
|
438
|
+
:xoff => 0,
|
439
|
+
:yoff => 0,
|
440
|
+
:zoff => 0
|
441
|
+
})
|
442
|
+
end
|
443
|
+
|
444
|
+
def rotate_y(radians)
|
445
|
+
self.dup.rotate_y!(radians)
|
268
446
|
end
|
269
447
|
|
270
|
-
def
|
271
|
-
|
272
|
-
self.get_x(n),
|
273
|
-
(self.dimensions >= 2 ? self.get_y(n) : nil),
|
274
|
-
(self.dimensions >= 3 ? self.get_z(n) : nil)
|
275
|
-
].compact
|
448
|
+
def rotate_z!(radians)
|
449
|
+
self.rotate!(radians)
|
276
450
|
end
|
451
|
+
|
452
|
+
def rotate_z(radians)
|
453
|
+
self.dup.rotate!(radians)
|
454
|
+
end
|
455
|
+
|
456
|
+
def scale!(*args)
|
457
|
+
x, y, z = if args.length == 1 && args[0].is_a?(Hash)
|
458
|
+
args[0].values_at(:x, :y, :z)
|
459
|
+
elsif args.length.between?(1, 3)
|
460
|
+
args.values_at(0...3)
|
461
|
+
else
|
462
|
+
raise ArgumentError.new("Wrong number of arguments #{args.length} for 1-3")
|
463
|
+
end
|
464
|
+
|
465
|
+
self.affine!({
|
466
|
+
:afac => x || 1,
|
467
|
+
:bfac => 0,
|
468
|
+
:cfac => 0,
|
469
|
+
:dfac => 0,
|
470
|
+
:efac => y || 1,
|
471
|
+
:ffac => 0,
|
472
|
+
:gfac => 0,
|
473
|
+
:hfac => 0,
|
474
|
+
:ifac => z || 1,
|
475
|
+
:xoff => 0,
|
476
|
+
:yoff => 0,
|
477
|
+
:zoff => 0
|
478
|
+
})
|
479
|
+
end
|
480
|
+
|
481
|
+
def scale(*args)
|
482
|
+
self.dup.scale!(*args)
|
483
|
+
end
|
484
|
+
|
485
|
+
def trans_scale!(*args)
|
486
|
+
delta_x, delta_y, x_factor, y_factor = if args.length == 1 && args[0].is_a?(Hash)
|
487
|
+
args[0].values_at(:delta_x, :delta_y, :x_factor, :y_factor)
|
488
|
+
elsif args.length.between?(1, 4)
|
489
|
+
args.values_at(0...4)
|
490
|
+
else
|
491
|
+
raise ArgumentError.new("Wrong number of arguments #{args.length} for 1-4")
|
492
|
+
end
|
493
|
+
|
494
|
+
x_factor ||= 1
|
495
|
+
y_factor ||= 1
|
496
|
+
delta_x ||= 0
|
497
|
+
delta_y ||= 0
|
498
|
+
|
499
|
+
self.affine!({
|
500
|
+
:afac => x_factor,
|
501
|
+
:bfac => 0,
|
502
|
+
:cfac => 0,
|
503
|
+
:dfac => 0,
|
504
|
+
:efac => y_factor,
|
505
|
+
:ffac => 0,
|
506
|
+
:gfac => 0,
|
507
|
+
:hfac => 0,
|
508
|
+
:ifac => 1,
|
509
|
+
:xoff => delta_x * x_factor,
|
510
|
+
:yoff => delta_y * y_factor,
|
511
|
+
:zoff => 0
|
512
|
+
})
|
513
|
+
end
|
514
|
+
|
515
|
+
def trans_scale(*args)
|
516
|
+
self.dup.trans_scale!(*args)
|
517
|
+
end
|
518
|
+
|
519
|
+
def translate!(*args)
|
520
|
+
x, y, z = if args.length == 1 && args[0].is_a?(Hash)
|
521
|
+
args[0].values_at(:x, :y, :z)
|
522
|
+
elsif args.length.between?(1, 3)
|
523
|
+
args.values_at(0...3)
|
524
|
+
else
|
525
|
+
raise ArgumentError.new("Wrong number of arguments #{args.length} for 1-3")
|
526
|
+
end
|
527
|
+
|
528
|
+
self.affine!({
|
529
|
+
:afac => 1,
|
530
|
+
:bfac => 0,
|
531
|
+
:cfac => 0,
|
532
|
+
:dfac => 0,
|
533
|
+
:efac => 1,
|
534
|
+
:ffac => 0,
|
535
|
+
:gfac => 0,
|
536
|
+
:hfac => 0,
|
537
|
+
:ifac => 1,
|
538
|
+
:xoff => x || 0,
|
539
|
+
:yoff => y || 0,
|
540
|
+
:zoff => z || 1
|
541
|
+
})
|
542
|
+
end
|
543
|
+
|
544
|
+
def translate(*args)
|
545
|
+
self.dup.translate!(*args)
|
546
|
+
end
|
547
|
+
|
548
|
+
protected
|
549
|
+
|
550
|
+
def check_bounds(idx) #:nodoc:
|
551
|
+
raise Geos::IndexBoundsError, 'Index out of bounds' if idx.negative? || idx >= length
|
552
|
+
end
|
553
|
+
|
554
|
+
def build_coordinate(n) #:nodoc:
|
555
|
+
[
|
556
|
+
get_x(n),
|
557
|
+
(dimensions >= 2 ? get_y(n) : nil),
|
558
|
+
(dimensions >= 3 ? get_z(n) : nil)
|
559
|
+
].compact
|
560
|
+
end
|
277
561
|
end
|
278
562
|
end
|