geos-extensions 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +17 -0
  3. data/MIT-LICENSE +1 -1
  4. data/Rakefile +2 -0
  5. data/lib/geos-extensions.rb +6 -0
  6. data/lib/geos/coordinate_sequence.rb +290 -12
  7. data/lib/geos/extensions/exceptions.rb +2 -0
  8. data/lib/geos/extensions/version.rb +3 -1
  9. data/lib/geos/geometry.rb +3 -1
  10. data/lib/geos/geometry_collection.rb +52 -0
  11. data/lib/geos/geos_helper.rb +2 -0
  12. data/lib/geos/google_maps.rb +2 -0
  13. data/lib/geos/google_maps/api_2.rb +2 -0
  14. data/lib/geos/google_maps/api_3.rb +2 -0
  15. data/lib/geos/google_maps/api_common.rb +2 -0
  16. data/lib/geos/google_maps/polyline_encoder.rb +2 -0
  17. data/lib/geos/line_string.rb +123 -0
  18. data/lib/geos/multi_line_string.rb +2 -0
  19. data/lib/geos/multi_point.rb +2 -0
  20. data/lib/geos/multi_polygon.rb +2 -0
  21. data/lib/geos/point.rb +59 -0
  22. data/lib/geos/polygon.rb +97 -0
  23. data/lib/geos/yaml.rb +1 -0
  24. data/lib/geos/yaml/psych.rb +1 -0
  25. data/lib/geos/yaml/syck.rb +1 -0
  26. data/lib/geos_extensions.rb +2 -0
  27. data/test/coordinate_sequence_tests.rb +256 -0
  28. data/test/geometry_collection_tests.rb +429 -0
  29. data/test/geometry_tests.rb +57 -0
  30. data/test/google_maps_api_2_tests.rb +2 -0
  31. data/test/google_maps_api_3_tests.rb +2 -0
  32. data/test/google_maps_api_common_tests.rb +2 -0
  33. data/test/google_maps_polyline_encoder_tests.rb +2 -0
  34. data/test/helper_tests.rb +2 -0
  35. data/test/line_string_tests.rb +211 -0
  36. data/test/misc_tests.rb +2 -0
  37. data/test/point_tests.rb +173 -0
  38. data/test/polygon_tests.rb +329 -0
  39. data/test/reader_tests.rb +2 -0
  40. data/test/test_helper.rb +73 -3
  41. data/test/writer_tests.rb +2 -0
  42. data/test/yaml_tests.rb +1 -0
  43. metadata +16 -3
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos::Helper
3
5
  JS_ESCAPE_MAP = {
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos
3
5
  module GoogleMaps
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos::GoogleMaps::Api2
3
5
  module Geometry
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos::GoogleMaps
3
5
  module Api3
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos
3
5
  module GoogleMaps
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos
3
5
  module GoogleMaps
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos
3
5
  class LineString
@@ -10,6 +12,127 @@ module Geos
10
12
  self.coord_seq.to_geojsonable(options)
11
13
  end
12
14
  alias_method :to_geojsonable, :as_geojson
15
+
16
+ # Dumps points similarly to the PostGIS `ST_DumpPoints` function.
17
+ def dump_points(cur_path = [])
18
+ cur_path.concat(self.to_a)
19
+ end
20
+
21
+ %w{ max min }.each do |op|
22
+ %w{ x y }.each do |dimension|
23
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
24
+ def #{dimension}_#{op}
25
+ unless self.empty?
26
+ self.coord_seq.#{dimension}_#{op}
27
+ end
28
+ end
29
+ EOF
30
+ end
31
+
32
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
33
+ def z_#{op}
34
+ unless self.empty?
35
+ if self.has_z?
36
+ self.coord_seq.z_#{op}
37
+ else
38
+ 0
39
+ end
40
+ end
41
+ end
42
+ EOF
43
+ end
44
+
45
+ def snap_to_grid!(*args)
46
+ if !self.empty?
47
+ cs = self.coord_seq.snap_to_grid!(*args)
48
+
49
+ if cs.length == 0
50
+ @ptr = Geos.create_empty_line_string(:srid => self.srid).ptr
51
+ elsif cs.length <= 1
52
+ raise Geos::InvalidGeometryError.new("snap_to_grid! produced an invalid number of points in for a LineString - found #{cs.length} - must be 0 or > 1")
53
+ else
54
+ @ptr = Geos.create_line_string(cs).ptr
55
+ end
56
+ end
57
+
58
+ self
59
+ end
60
+
61
+ def snap_to_grid(*args)
62
+ ret = self.dup.snap_to_grid!(*args)
63
+ ret.srid = pick_srid_according_to_policy(self.srid)
64
+ ret
65
+ end
66
+
67
+ def line_interpolate_point(fraction)
68
+ if !fraction.between?(0, 1)
69
+ raise ArgumentError.new("fraction must be between 0 and 1")
70
+ end
71
+
72
+ case fraction
73
+ when 0
74
+ self.start_point
75
+ when 1
76
+ self.end_point
77
+ else
78
+ length = self.length
79
+ total_length = 0
80
+ segs = self.num_points - 1
81
+
82
+ segs.times do |i|
83
+ p1 = self[i]
84
+ p2 = self[i + 1]
85
+
86
+ seg_length = p1.distance(p2) / length
87
+
88
+ if fraction < total_length + seg_length
89
+ dseg = (fraction - total_length) / seg_length
90
+
91
+ args = []
92
+ args << p1.x + ((p2.x - p1.x) * dseg)
93
+ args << p1.y + ((p2.y - p1.y) * dseg)
94
+ args << p1.z + ((p2.z - p1.z) * dseg) if self.has_z?
95
+
96
+ args << { :srid => pick_srid_according_to_policy(self.srid) } unless self.srid == 0
97
+
98
+ return Geos.create_point(*args)
99
+ end
100
+
101
+ total_length += seg_length
102
+ end
103
+
104
+ # if all else fails...
105
+ self.end_point
106
+ end
107
+ end
108
+ alias_method :interpolate_point, :line_interpolate_point
109
+
110
+ %w{
111
+ affine
112
+ rotate
113
+ rotate_x
114
+ rotate_y
115
+ rotate_z
116
+ scale
117
+ trans_scale
118
+ translate
119
+ }.each do |m|
120
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
121
+ def #{m}!(*args)
122
+ unless self.empty?
123
+ self.coord_seq.#{m}!(*args)
124
+ end
125
+
126
+ self
127
+ end
128
+
129
+ def #{m}(*args)
130
+ ret = self.dup.#{m}!(*args)
131
+ ret.srid = pick_srid_according_to_policy(self.srid)
132
+ ret
133
+ end
134
+ EOF
135
+ end
13
136
  end
14
137
  end
15
138
 
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos
3
5
  class MultiLineString < GeometryCollection
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos
3
5
  class MultiPoint < GeometryCollection
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos
3
5
  class MultiPolygon < GeometryCollection
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos
3
5
  class Point
@@ -115,6 +117,63 @@ module Geos
115
117
  }
116
118
  end
117
119
  alias_method :to_geojsonable, :as_geojson
120
+
121
+ # Dumps points similarly to the PostGIS `ST_DumpPoints` function.
122
+ def dump_points(cur_path = [])
123
+ cur_path.push(self.dup)
124
+ end
125
+
126
+ %w{ max min }.each do |op|
127
+ %w{ x y }.each do |dimension|
128
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
129
+ def #{dimension}_#{op}
130
+ unless self.empty?
131
+ self.#{dimension}
132
+ end
133
+ end
134
+ EOF
135
+ end
136
+
137
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
138
+ def z_#{op}
139
+ unless self.empty?
140
+ if self.has_z?
141
+ self.z
142
+ else
143
+ 0
144
+ end
145
+ end
146
+ end
147
+ EOF
148
+ end
149
+
150
+ %w{
151
+ affine
152
+ rotate
153
+ rotate_x
154
+ rotate_y
155
+ rotate_z
156
+ scale
157
+ snap_to_grid
158
+ trans_scale
159
+ translate
160
+ }.each do |m|
161
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
162
+ def #{m}!(*args)
163
+ unless self.empty?
164
+ self.coord_seq.#{m}!(*args)
165
+ end
166
+
167
+ self
168
+ end
169
+
170
+ def #{m}(*args)
171
+ ret = self.dup.#{m}!(*args)
172
+ ret.srid = pick_srid_according_to_policy(self.srid)
173
+ ret
174
+ end
175
+ EOF
176
+ end
118
177
  end
119
178
  end
120
179
 
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  module Geos
3
5
  class Polygon
@@ -153,6 +155,101 @@ module Geos
153
155
  ret
154
156
  end
155
157
  alias_method :to_geojsonable, :as_geojson
158
+
159
+ # Dumps points similarly to the PostGIS `ST_DumpPoints` function.
160
+ def dump_points(cur_path = [])
161
+ points = [ self.exterior_ring.dump_points ]
162
+
163
+ self.interior_rings.each do |ring|
164
+ points.push(ring.dump_points)
165
+ end
166
+
167
+ cur_path.concat(points)
168
+ end
169
+
170
+ %w{ max min }.each do |op|
171
+ %w{ x y }.each do |dimension|
172
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
173
+ def #{dimension}_#{op}
174
+ unless self.empty?
175
+ self.envelope.exterior_ring.#{dimension}_#{op}
176
+ end
177
+ end
178
+ EOF
179
+ end
180
+
181
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
182
+ def z_#{op}
183
+ unless self.empty?
184
+ if self.has_z?
185
+ self.exterior_ring.z_#{op}
186
+ else
187
+ 0
188
+ end
189
+ end
190
+ end
191
+ EOF
192
+ end
193
+
194
+ def snap_to_grid!(*args)
195
+ if !self.empty?
196
+ exterior_ring = self.exterior_ring.coord_seq.snap_to_grid!(*args)
197
+
198
+ if exterior_ring.length == 0
199
+ @ptr = Geos.create_empty_polygon(:srid => self.srid).ptr
200
+ elsif exterior_ring.length < 4
201
+ raise Geos::InvalidGeometryError.new("snap_to_grid! produced an invalid number of points in exterior ring - found #{exterior_ring.length} - must be 0 or >= 4")
202
+ else
203
+ interior_rings = []
204
+
205
+ self.num_interior_rings.times { |i|
206
+ interior_ring = self.interior_ring_n(i).coord_seq.snap_to_grid!(*args)
207
+
208
+ interior_rings << interior_ring unless interior_ring.length < 4
209
+ }
210
+
211
+ interior_rings.compact!
212
+
213
+ polygon = Geos.create_polygon(exterior_ring, interior_rings, :srid => self.srid)
214
+ @ptr = polygon.ptr
215
+ end
216
+ end
217
+
218
+ self
219
+ end
220
+
221
+ def snap_to_grid(*args)
222
+ ret = self.dup.snap_to_grid!(*args)
223
+ ret.srid = pick_srid_according_to_policy(self.srid)
224
+ ret
225
+ end
226
+
227
+ %w{
228
+ affine
229
+ rotate
230
+ rotate_x
231
+ rotate_y
232
+ rotate_z
233
+ scale
234
+ trans_scale
235
+ translate
236
+ }.each do |m|
237
+ self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
238
+ def #{m}!(*args)
239
+ self.exterior_ring.coord_seq.#{m}!(*args)
240
+ self.interior_rings.each do |ring|
241
+ ring.coord_seq.#{m}!(*args)
242
+ end
243
+ self
244
+ end
245
+
246
+ def #{m}(*args)
247
+ ret = self.dup.#{m}!(*args)
248
+ ret.srid = pick_srid_according_to_policy(self.srid)
249
+ ret
250
+ end
251
+ EOF
252
+ end
156
253
  end
157
254
  end
158
255
 
@@ -1,4 +1,5 @@
1
1
  # encoding: UTF-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  # This file adds yaml serialization support to geometries. The generated yaml
4
5
  # has this format:
@@ -1,4 +1,5 @@
1
1
  # encoding: UTF-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Geos
4
5
  class Geometry
@@ -1,4 +1,5 @@
1
1
  # encoding: UTF-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Geos
4
5
  class Geometry
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  begin
3
5
  if !ENV['USE_BINARY_GEOS']
@@ -0,0 +1,256 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ $: << File.dirname(__FILE__)
5
+ require 'test_helper'
6
+
7
+ class CoordinateSequenceTests < Minitest::Test
8
+ include TestHelper
9
+
10
+ def test_x_max
11
+ cs = Geos::CoordinateSequence.new([ -10, -15 ], [ 0, 5 ], [ 10, 20 ])
12
+ assert_equal(10, cs.x_max)
13
+ end
14
+
15
+ def test_x_min
16
+ cs = Geos::CoordinateSequence.new([ -10, -15 ], [ 0, 5 ], [ 10, 20 ])
17
+ assert_equal(-10, cs.x_min)
18
+ end
19
+
20
+ def test_y_max
21
+ cs = Geos::CoordinateSequence.new([ -10, -15 ], [ 0, 5 ], [ 10, 20 ])
22
+ assert_equal(20, cs.y_max)
23
+ end
24
+
25
+ def test_y_min
26
+ cs = Geos::CoordinateSequence.new([ -10, -15 ], [ 0, 5 ], [ 10, 20 ])
27
+ assert_equal(-15, cs.y_min)
28
+ end
29
+
30
+ def test_z_max
31
+ cs = Geos::CoordinateSequence.new([ -10, -15 ], [ 0, 5 ], [ 10, 20 ])
32
+ assert(cs.z_max.nan?, " Expected NaN")
33
+
34
+ cs = Geos::CoordinateSequence.new([ -10, -15, -20 ], [ 0, 5, 10 ], [ 10, 20, 30 ])
35
+ assert_equal(30, cs.z_max)
36
+ end
37
+
38
+ def test_z_min
39
+ cs = Geos::CoordinateSequence.new([ -10, -15 ], [ 0, 5 ], [ 10, 20 ])
40
+ assert(cs.z_min.nan?, " Expected NaN")
41
+
42
+ cs = Geos::CoordinateSequence.new([ -10, -15, -20 ], [ 0, 5, 10 ], [ 10, 20, 30 ])
43
+ assert_equal(-20, cs.z_min)
44
+ end
45
+
46
+ def test_snap_to_grid_with_size
47
+ expected = [
48
+ [[-10.0, -15.0], [0.0, 5.0], [10.0, 20.0]],
49
+ [[-10.1, -15.1], [0.1, 5.1], [10.1, 20.1]],
50
+ [[-10.12, -15.12], [0.12, 5.12], [10.12, 20.12]],
51
+ [[-10.123, -15.123], [0.123, 5.123], [10.123, 20.123]],
52
+ [[-10.1235, -15.1235], [0.1235, 5.1235], [10.1235, 20.1235]],
53
+ [[-10.12346, -15.12346], [0.12346, 5.12346], [10.12346, 20.12346]],
54
+ [[-10.123457, -15.123457], [0.123457, 5.123457], [10.123457, 20.123457]],
55
+ [[-10.1234568, -15.1234568], [0.1234568, 5.1234568], [10.1234568, 20.1234568]],
56
+ [[-10.12345679, -15.12345679], [0.12345679, 5.12345679], [10.12345679, 20.12345679]]
57
+ ]
58
+
59
+ coordinates = [
60
+ [ -10.123456789, -15.123456789 ],
61
+ [ 0.123456789, 5.123456789 ],
62
+ [ 10.123456789, 20.123456789 ]
63
+ ]
64
+
65
+ 9.times do |i|
66
+ cs = Geos::CoordinateSequence.new(*coordinates)
67
+ cs.snap_to_grid!(10 ** -i)
68
+
69
+ # XXX - Ruby 1.8.7 sometimes sees the the float values as differing
70
+ # slightly, but not enough that it would matter for these tests.
71
+ # Test equality on the inspect Strings instead of the float values.
72
+ assert_equal(expected[i].inspect, cs.to_a.inspect)
73
+
74
+ cs = Geos::CoordinateSequence.new(*coordinates)
75
+ snapped = cs.snap_to_grid(10 ** -i)
76
+ assert_equal(coordinates, cs.to_a)
77
+ assert_equal(expected[i].inspect, snapped.to_a.inspect)
78
+ end
79
+ end
80
+
81
+ def test_snap_to_grid_with_hash
82
+ cs = Geos::CoordinateSequence.new(
83
+ [ 10, 10 ],
84
+ [ 20, 20 ],
85
+ [ 30, 30 ]
86
+ )
87
+ cs.snap_to_grid!(:size_x => 1, :size_y => 1, :offset_x => 12.5, :offset_y => 12.5)
88
+
89
+ assert_equal([
90
+ [ 9.5, 9.5 ],
91
+ [ 20.5, 20.5 ],
92
+ [ 30.5, 30.5 ]
93
+ ], cs.to_a)
94
+ end
95
+
96
+ def test_snap_to_grid_with_geometry_origin
97
+ cs = Geos::CoordinateSequence.new(
98
+ [ 10, 10 ],
99
+ [ 20, 20 ],
100
+ [ 30, 30 ]
101
+ )
102
+ cs.snap_to_grid!(:size => 1, :offset => read('LINESTRING (0 0, 25 25)'))
103
+
104
+ assert_equal([
105
+ [ 9.5, 9.5 ],
106
+ [ 20.5, 20.5 ],
107
+ [ 30.5, 30.5 ]
108
+ ], cs.to_a)
109
+ end
110
+
111
+ def test_snap_to_grid_with_z
112
+ cs = Geos::CoordinateSequence.new(
113
+ [ 10, 10, 10 ],
114
+ [ 20, 20, 20 ],
115
+ [ 30, 30, 30 ]
116
+ )
117
+ cs.snap_to_grid!(
118
+ :size_x => 1,
119
+ :size_y => 1,
120
+ :size_z => 1,
121
+
122
+ :offset_x => 12.5,
123
+ :offset_y => 12.5,
124
+ :offset_z => 12.5
125
+ )
126
+
127
+ assert_equal([
128
+ [ 9.5, 9.5, 9.5 ],
129
+ [ 20.5, 20.5, 20.5 ],
130
+ [ 30.5, 30.5, 30.5 ]
131
+ ], cs.to_a)
132
+ end
133
+
134
+ def test_snap_to_grid_remove_duplicate_points
135
+ coords = [
136
+ [-10.0, 0.0],
137
+ [-10.0, 5.0], [-10.0, 5.0],
138
+ [-10.0, 6.0], [-10.0, 6.0], [-10.0, 6.0],
139
+ [-10.0, 7.0], [-10.0, 7.0], [-10.0, 7.0],
140
+ [-10.0, 8.0], [-10.0, 8.0],
141
+ [-9.0, 8.0], [-9.0, 9.0],
142
+ [-10.0, 0.0]
143
+ ]
144
+
145
+ expected = [
146
+ [-10.0, 0.0],
147
+ [-10.0, 5.0],
148
+ [-10.0, 6.0],
149
+ [-10.0, 7.0],
150
+ [-10.0, 8.0],
151
+ [-9.0, 8.0],
152
+ [-9.0, 9.0],
153
+ [-10.0, 0.0]
154
+ ]
155
+
156
+ cs = Geos::CoordinateSequence.new(coords)
157
+ cs.snap_to_grid!
158
+
159
+ assert_equal(expected, cs.to_a)
160
+
161
+ cs = Geos::CoordinateSequence.new(coords)
162
+ cs2 = cs.snap_to_grid
163
+
164
+ assert_equal(coords, cs.to_a)
165
+ assert_equal(expected, cs2.to_a)
166
+ end
167
+
168
+ def cs_affine_tester(method, expected, coords, *args)
169
+ cs = Geos::CoordinateSequence.new(coords)
170
+ cs.send("#{method}!", *args)
171
+
172
+ expected.length.times do |i|
173
+ assert_in_delta(expected[i], cs.get_ordinate(0, i), DELTA_TOLERANCE)
174
+ end
175
+
176
+ cs = Geos::CoordinateSequence.new(coords)
177
+ cs2 = cs.send(method, *args)
178
+
179
+ expected.length.times do |i|
180
+ assert_in_delta(coords[i], cs.get_ordinate(0, i), DELTA_TOLERANCE)
181
+ assert_in_delta(expected[i], cs2.get_ordinate(0, i), DELTA_TOLERANCE)
182
+ end
183
+ end
184
+
185
+ def test_rotate
186
+ cs_affine_tester(:rotate, [ 29.0, 11.0 ], [ 1, 1 ], Math::PI / 2, [ 10.0, 20.0 ])
187
+ cs_affine_tester(:rotate, [ -2.0, 0.0 ], [ 1, 1 ], -Math::PI / 2, [ -1.0, 2.0 ])
188
+ cs_affine_tester(:rotate, [ 19.0, 1.0 ], [ 1, 1 ], Math::PI / 2, read('POINT(10 10)'))
189
+ cs_affine_tester(:rotate, [ -0.5, 0.5 ], [ 1, 1 ], Math::PI / 2, read('LINESTRING(0 0, 1 0)'))
190
+ end
191
+
192
+ def test_rotate_x
193
+ cs_affine_tester(:rotate_x, [ 1, -1, -1 ], [ 1, 1, 1 ], Math::PI)
194
+ cs_affine_tester(:rotate_x, [ 1, -1, 1 ], [ 1, 1, 1 ], Math::PI / 2)
195
+ cs_affine_tester(:rotate_x, [ 1, 1, -1 ], [ 1, 1, 1 ], Math::PI + Math::PI / 2)
196
+ cs_affine_tester(:rotate_x, [ 1, 1, 1 ], [ 1, 1, 1 ], Math::PI * 2)
197
+ end
198
+
199
+ def test_rotate_y
200
+ cs_affine_tester(:rotate_y, [ -1, 1, -1 ], [ 1, 1, 1 ], Math::PI)
201
+ cs_affine_tester(:rotate_y, [ 1, 1, -1 ], [ 1, 1, 1 ], Math::PI / 2)
202
+ cs_affine_tester(:rotate_y, [ -1, 1, 1 ], [ 1, 1, 1 ], Math::PI + Math::PI / 2)
203
+ cs_affine_tester(:rotate_y, [ 1, 1, 1 ], [ 1, 1, 1 ], Math::PI * 2)
204
+ end
205
+
206
+ def test_rotate_z
207
+ cs_affine_tester(:rotate_z, [ -1, -1 ], [ 1, 1 ], Math::PI)
208
+ cs_affine_tester(:rotate_z, [ -1, 1 ], [ 1, 1 ], Math::PI / 2)
209
+ cs_affine_tester(:rotate_z, [ 1, -1 ], [ 1, 1 ], Math::PI + Math::PI / 2)
210
+ cs_affine_tester(:rotate_z, [ 1, 1 ], [ 1, 1 ], Math::PI * 2)
211
+ end
212
+
213
+ def test_scale
214
+ cs_affine_tester(:scale, [ 5, 5 ], [ 1, 1 ], 5, 5)
215
+ cs_affine_tester(:scale, [ 3, 2 ], [ 1, 1 ], 3, 2)
216
+ cs_affine_tester(:scale, [ 40, 40, 40 ], [ 10, 20, -5 ], 4, 2, -8)
217
+ end
218
+
219
+ def test_scale_hash
220
+ cs_affine_tester(:scale, [ 5, 5 ], [ 1, 1 ], :x => 5, :y => 5)
221
+ cs_affine_tester(:scale, [ 3, 2 ], [ 1, 1 ], :x => 3, :y => 2)
222
+ cs_affine_tester(:scale, [ 40, 40, 40 ], [ 10, 20, -5 ], :x => 4, :y => 2, :z => -8)
223
+ end
224
+
225
+ def test_trans_scale
226
+ cs_affine_tester(:trans_scale, [ 2, 2 ], [ 1, 1 ], 1, 1, 1, 1)
227
+ cs_affine_tester(:trans_scale, [ 3, 3 ], [ 2, 2 ], 1, 1, 1, 1)
228
+ cs_affine_tester(:trans_scale, [ 0, 0 ], [ 1, 1 ], -1, -1, -1, -1)
229
+ cs_affine_tester(:trans_scale, [ 1, 2 ], [ 1, 1 ], 0, 1, 1, 1)
230
+ cs_affine_tester(:trans_scale, [ 2, 1 ], [ 1, 1 ], 1, 0, 1, 1)
231
+ cs_affine_tester(:trans_scale, [ 0, 2 ], [ 1, 1 ], 1, 1, 0, 1)
232
+ cs_affine_tester(:trans_scale, [ 2, 0 ], [ 1, 1 ], 1, 1, 1, 0)
233
+ cs_affine_tester(:trans_scale, [ 3, 2 ], [ 1, 1 ], 2, 1, 1, 1)
234
+ cs_affine_tester(:trans_scale, [ 2, 3 ], [ 1, 1 ], 1, 2, 1, 1)
235
+ cs_affine_tester(:trans_scale, [ 4, 2 ], [ 1, 1 ], 1, 1, 2, 1)
236
+ cs_affine_tester(:trans_scale, [ 2, 4 ], [ 1, 1 ], 1, 1, 1, 2)
237
+ cs_affine_tester(:trans_scale, [ 15, 28 ], [ 1, 1 ], 2, 3, 5, 7)
238
+ cs_affine_tester(:trans_scale, [ 15, 28, 1 ], [ 1, 1, 1 ], 2, 3, 5, 7)
239
+ end
240
+
241
+ def test_trans_scale_hash
242
+ cs_affine_tester(:trans_scale, [ 2, 2 ], [ 1, 1 ], :delta_x => 1, :delta_y => 1, :x_factor => 1, :y_factor => 1)
243
+ cs_affine_tester(:trans_scale, [ 15, 28, 1 ], [ 1, 1, 1 ], :delta_x => 2, :delta_y => 3, :x_factor => 5, :y_factor => 7)
244
+ cs_affine_tester(:trans_scale, [ 3, 1, 1 ], [ 1, 1, 1 ], :delta_x => 2, :z_factor => 2)
245
+ end
246
+
247
+ def test_translate
248
+ cs_affine_tester(:translate, [ 5, 12 ], [ 0, 0 ], 5, 12)
249
+ cs_affine_tester(:translate, [ -3, -7, 3 ], [ 0, 0, 0 ], -3, -7, 3)
250
+ end
251
+
252
+ def test_translate_hash
253
+ cs_affine_tester(:translate, [ 5, 12 ], [ 0, 0 ], :x => 5, :y => 12)
254
+ cs_affine_tester(:translate, [ -3, -7, 3 ], [ 0, 0, 0 ], :x => -3, :y => -7, :z => 3)
255
+ end
256
+ end