xrvg 0.0.5 → 0.0.6

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.
Files changed (51) hide show
  1. data/CHANGES +8 -0
  2. data/README +1 -1
  3. data/Rakefile +36 -6
  4. data/examples/arciterate1.rb +13 -0
  5. data/examples/arcrecurse1.rb +30 -0
  6. data/examples/arcrecurse2.rb +37 -0
  7. data/examples/circleiterate1.rb +9 -0
  8. data/examples/circleiterate2.rb +11 -0
  9. data/examples/circleiterate3.rb +13 -0
  10. data/examples/circlerecurse1.rb +27 -0
  11. data/examples/circlerecurse2.rb +27 -0
  12. data/examples/circlerecurseall.rb +29 -0
  13. data/examples/euclideangeo.rb +11 -0
  14. data/examples/evolution1.rb +8 -0
  15. data/examples/evolution2.rb +9 -0
  16. data/examples/evolution3.rb +10 -0
  17. data/examples/fuseaugeo.rb +16 -0
  18. data/examples/gradientgeo.rb +21 -0
  19. data/examples/interbeziergeo1.rb +14 -0
  20. data/examples/interbeziergeo2.rb +17 -0
  21. data/examples/interbeziergeo3.rb +17 -0
  22. data/examples/offsetgeo.rb +16 -0
  23. data/lib/bezier.rb +37 -3
  24. data/lib/bezierbuilders.rb +17 -1
  25. data/lib/beziermotifs.rb +11 -4
  26. data/lib/bezierspline.rb +23 -1
  27. data/lib/beziertools.rb +48 -14
  28. data/lib/color.rb +55 -8
  29. data/lib/fitting.rb +2 -2
  30. data/lib/geometry2D.rb +10 -3
  31. data/lib/geovariety.rb +128 -0
  32. data/lib/interbezier.rb +4 -4
  33. data/lib/interpolation.rb +30 -17
  34. data/lib/parametriclength.rb +3 -2
  35. data/lib/render.rb +1 -2
  36. data/lib/samplation.rb +121 -19
  37. data/lib/shape.rb +2 -2
  38. data/lib/spiral.rb +72 -0
  39. data/lib/utils.rb +97 -76
  40. data/lib/xrvg.rb +3 -3
  41. data/test/test_bezier.rb +17 -2
  42. data/test/test_bezierbuilders.rb +1 -1
  43. data/test/test_beziertools.rb +7 -0
  44. data/test/test_color.rb +12 -0
  45. data/test/test_geovariety.rb +105 -0
  46. data/test/test_interpolation.rb +2 -1
  47. data/test/test_render.rb +0 -4
  48. data/test/test_sample.rb +28 -0
  49. data/test/test_spiral.rb +22 -0
  50. data/test/test_utils.rb +65 -40
  51. metadata +26 -2
data/lib/samplation.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  # The base module is FloatFunctor, used by Samplable and Splittable
4
4
  #
5
5
 
6
+ require 'attributable'
7
+
6
8
  module XRVG
7
9
  #
8
10
  # Base module to define float lists processing and computation.
@@ -25,7 +27,7 @@ module FloatFunctor
25
27
 
26
28
  # building recursivity method
27
29
  #
28
- # is private ?
30
+ # is private => no for Array
29
31
  def addfilter( newfilter )
30
32
  if not @subfilter
31
33
  @subfilter = newfilter
@@ -123,9 +125,20 @@ module FloatFunctor
123
125
  return self.addfilter( Filter.with {|x| 1.0 - Math.exp(-speed * x)} )
124
126
  end
125
127
 
128
+ # geometric filter full
129
+ def geofull( factor )
130
+ return self.addfilter( GeoFullFilter.new( factor ) )
131
+ end
132
+
133
+
134
+ # sin filter
135
+ def sin( speed=1.0, phase=0.0 )
136
+ return self.addfilter( Filter.with {|x| Math.sin( speed * x * Math::PI + phase) } )
137
+ end
138
+
126
139
  # random filter
127
- def random()
128
- return self.addfilter( RandomFilter.new )
140
+ def random(*args)
141
+ return self.addfilter( RandomFilter.new(*args) )
129
142
  end
130
143
 
131
144
  # sorting filter
@@ -133,6 +146,12 @@ module FloatFunctor
133
146
  return self.addfilter( SortFilter.new )
134
147
  end
135
148
 
149
+ # shuffle filter
150
+ def shuffle()
151
+ return self.addfilter( ShuffleFilter.new )
152
+ end
153
+
154
+
136
155
  # alternate filter
137
156
  def alternate()
138
157
  return self.addfilter( AlternateFilter.new )
@@ -190,14 +209,6 @@ module Samplable
190
209
  # alias for mean
191
210
  alias middle mean
192
211
 
193
- # alias for .random.samples
194
- def rand(nsamples=1,&block)
195
- inputs = []
196
- nsamples.times {|v| inputs.push( Kernel::rand )}
197
- result = self.process( inputs, :sample, &block )
198
- return nsamples == 1 ? result[0] : result
199
- end
200
-
201
212
  # to be overloaded if needed
202
213
  #
203
214
  # called by FloatFunctor apply method
@@ -297,7 +308,6 @@ end
297
308
  # this allow to do for example
298
309
  # [bezier1.filter(:point), bezier1.filter(:tangent), palette].samples( 10 ) do |point, tangent, color|
299
310
  class Filter
300
-
301
311
  include Samplable
302
312
 
303
313
  # to define a filter on "object" with method "samplemethod", or with a block (exclusive)
@@ -329,26 +339,85 @@ class Filter
329
339
  end
330
340
 
331
341
 
332
- # RandomFilter class, to resample randomly
342
+ # = RandomFilter class, to resample randomly
343
+ # == Attributes
344
+ # attribute :mindiff, 0.0
345
+ # attribute :sort, false
346
+ # :mindiff specifies which minimum interval must be preserved between random values. Of course, the number of sampling must then be above a given value so that this constraint can be verified.
333
347
  class RandomFilter < Filter
334
- def initialize(*args) #:nodoc:
348
+ include Attributable
349
+ attribute :mindiff, 0.0
350
+ attribute :sort, false
351
+
352
+ # make sampling by trying to check :mindiff constraint
353
+ #
354
+ # generate an exception if not possible
355
+ def rawtransforms(nsamples)
356
+ size = 1.0
357
+ nsplit = nsamples - 1
358
+ rsize = size - nsplit * @mindiff
359
+ if rsize < 0.0
360
+ raise("RandomFilter rawtransforms error: nsamples #{nsamples} mindiff #{@mindiff} are incompatible")
361
+ end
362
+
363
+ mindiffs = Array.new( nsplit, @mindiff )
364
+
365
+ # compute now nsplit values whose sum is <= to rsize
366
+ randarray = [0.0]
367
+ subarray = (0.0..rsize).rand( nsplit-1 )
368
+ if not subarray.is_a? Array
369
+ subarray = [subarray]
370
+ end
371
+ randarray += subarray
372
+ randarray.push( rsize )
373
+ randarray.sort!
374
+
375
+ rsizes = Array.new
376
+ randarray.each_cons(2) { |min, max| rsizes.push( (0.0..max-min).rand ) }
377
+
378
+ rsum = rsizes.sum
379
+ root = (0.0..(rsize-rsum)).rand
380
+
381
+ Trace("mindiffs #{mindiffs.inspect} rsizes #{rsizes.inspect} rsize #{rsize} rsum #{rsum} root #{root}")
382
+
383
+ preresult = []
384
+ mindiffs.zip( rsizes ) {|mindiff, rsize| preresult.push( mindiff + rsize )}
385
+
386
+ result = [root]
387
+ preresult.each {|v| newv = result[-1] + v; result << newv }
388
+
389
+ return result
335
390
  end
336
391
 
337
- def transform(abs) #:nodoc:
392
+ # do (0.0..1.0).rand to speed up computation if @mindiff is 0.0
393
+ def basictransform( v )
338
394
  return (0.0..1.0).rand
339
395
  end
340
396
 
341
397
  def transforms( inputs, type ) #:nodoc:
342
- result = inputs.map { |v| self.transform( v ) }
343
398
  if type == :split
344
- result[0] = 0.0
345
- result[-1] = 1.0
399
+ @sort = true
400
+ end
401
+ if @mindiff == 0.0
402
+ result = inputs.map { |v| self.basictransform( v ) }
403
+ if @sort
404
+ result = result.sort
405
+ end
406
+ if type == :split
407
+ result[0] = 0.0
408
+ result[-1] = 1.0
409
+ end
410
+ else
411
+ result = self.rawtransforms( inputs.size )
412
+ if not @sort
413
+ result = result.shuffle
414
+ end
346
415
  end
347
416
  return result
348
417
  end
349
418
  end
350
419
 
351
- # SortFilter, to sort inputs (in particular from Random)
420
+ # SortFilter, to sort inputs (in particular from Shuffle)
352
421
  class SortFilter < Filter
353
422
  def initialize(*args) #:nodoc:
354
423
  end
@@ -356,9 +425,42 @@ class SortFilter < Filter
356
425
  def transforms( inputs, type ) #:nodoc:
357
426
  return inputs.sort
358
427
  end
428
+ end
429
+
430
+ # GeoFullFilter, to transform inputs into geometrical sequence converging to 1.0
431
+ class GeoFullFilter < Filter
432
+ def initialize(factor) #:nodoc:
433
+ @factor = factor
434
+ end
359
435
 
436
+
437
+ # make sampling by trying to check :mindiff constraint
438
+ #
439
+ # generate an exception if not possible
440
+ def transforms( inputs, type ) #:nodoc:
441
+ nsamples = inputs.size
442
+ result = [1.0]
443
+ (nsamples-1).times do
444
+ result << result[-1] / @factor
445
+ end
446
+ range = (1.0..result[-1])
447
+ result = result.map {|v| range.abscissa( v )}
448
+ return result
449
+ end
450
+ end
451
+
452
+
453
+ # ShuffleFilter, to unsort inputs (in particular from Random)
454
+ class ShuffleFilter < Filter
455
+ def initialize(*args) #:nodoc:
456
+ end
457
+
458
+ def transforms( inputs, type ) #:nodoc:
459
+ return inputs.sort_by { rand }
460
+ end
360
461
  end
361
462
 
463
+
362
464
  # AlternateFilter, to inverse one value per two
363
465
  class AlternateFilter < Filter
364
466
  def initialize(range=nil) #:nodoc:
data/lib/shape.rb CHANGED
@@ -4,10 +4,10 @@
4
4
  # - Curve interface
5
5
  # - Line class
6
6
  # - Circle class
7
+ require 'utils'
7
8
  require 'frame'
8
9
  require 'geometry2D'
9
- require 'utils'
10
- require 'attributable'
10
+
11
11
 
12
12
  module XRVG
13
13
  # Shape abstract interface
data/lib/spiral.rb ADDED
@@ -0,0 +1,72 @@
1
+ # File dedicated to Spiral curves
2
+ # - Spiral
3
+ # - SpiralParam
4
+ # - SpiralFrise
5
+
6
+ require 'shape'
7
+
8
+ module XRVG
9
+
10
+ # abstract class to define spiral types
11
+ #
12
+ # use compute_radius to compute nsamples reference points, before interpolating with SimpleBezier
13
+ class GSpiral < BezierBuilder
14
+ attribute :center, V2D::O, V2D
15
+ attribute :ext, V2D::O + V2D::X, V2D
16
+ attribute :curvature, 1.0
17
+ attribute :nsamples, 100
18
+
19
+ def compute_radius( r0, angle0, curvature, angle )
20
+ raise NotImplementedError.new("#{self.class.name}#compute_radius is an abstract method.")
21
+ end
22
+
23
+ def maxangle( r0, angle0, curvature )
24
+ raise NotImplementedError.new("#{self.class.name}#maxangle is an abstract method.")
25
+ end
26
+
27
+ def compute()
28
+ points = []
29
+ r0, angle0 = (@ext - @center).coords(:polar)
30
+ maxangle = self.maxangle( r0, angle0, @curvature )
31
+ [(r0..0.0), (angle0..maxangle)].samples( self.nsamples ) do |radius, angle|
32
+ r = self.compute_radius( r0, angle0, @curvature, angle )
33
+ point = V2D.polar( r, angle )
34
+ points.push( @center + point )
35
+ end
36
+ return SimpleBezier.build( :support, points ).data
37
+ end
38
+ end
39
+
40
+ # at angle angle0, r = r0
41
+ # at angle angle0 + curvature, r = 0.0
42
+ class SpiralLinear < GSpiral
43
+
44
+ def maxangle( r0, angle0, curvature )
45
+ return (angle0 + curvature)
46
+ end
47
+
48
+ def compute_radius( r0, angle0, curvature, angle )
49
+ return r0 * (1.0 - ( 1.0 + (Math.exp( - 10.0 * ( angle- angle0) / curvature ) ) ) * ( angle - angle0 ) /curvature )
50
+ # return r0 * (1.0 - ( angle - angle0 ) /curvature )
51
+ end
52
+
53
+ end
54
+
55
+ # curvature is in number of tour before center % extremity
56
+ class SpiralLog < GSpiral
57
+
58
+ def nsamples
59
+ return (curvature * 15.0).to_i
60
+ end
61
+
62
+ def compute_radius( r0, angle0, curvature, angle )
63
+ return r0 * Math.exp( -(angle-angle0) / curvature )
64
+ end
65
+
66
+ def maxangle( r0, angle0, curvature )
67
+ return angle0 - curvature * Math.log( 0.001 )
68
+ end
69
+ end
70
+
71
+ end #XRVG
72
+
data/lib/utils.rb CHANGED
@@ -74,6 +74,39 @@ class Range
74
74
  return value
75
75
  end
76
76
 
77
+ # return modulo of value given interval
78
+ # (-1.0..1.5).modulo( 2.0 ) => -0.5
79
+ #
80
+ # TODO: manage special case range size = 0.0
81
+ def modulo( value )
82
+ return ((value - self.min)%self.size + self.min)
83
+ end
84
+
85
+ # compute list of "modulo boundaries"
86
+ # (-1.0..1.5).modulos( (-1.2..2.4) ) => [(1.3..1.5), (-1.0..1.5), (-1.0..0.4)]
87
+ def modulos( range )
88
+ t1 = self.modulo( range.min )
89
+ t2 = self.modulo( range.max )
90
+ s1 = ((range.min - self.min)/self.size).floor
91
+ s2 = ((range.max - self.min)/self.size).floor
92
+ if s1 == s2
93
+ result = [(t1..t2)]
94
+ else
95
+ result = [(t1..self.max)]
96
+ (s2-s1-1).times do
97
+ result << (self.min..self.max)
98
+ end
99
+ if t2 - self.min > 0.0
100
+ result << (self.min..t2)
101
+ end
102
+ end
103
+ if range.begin > range.end
104
+ result = result.reverse.map {|v| v.reverse}
105
+ end
106
+ # Trace("modulos range #{range.inspect} result #{result.inspect}")
107
+ return result
108
+ end
109
+
77
110
  # return max value of range
78
111
  def max
79
112
  return (self.begin > self.end) ? self.begin : self.end
@@ -84,6 +117,11 @@ class Range
84
117
  return (self.begin < self.end) ? self.begin : self.end
85
118
  end
86
119
 
120
+ # return size of the range
121
+ def size
122
+ return (self.max - self.min)
123
+ end
124
+
87
125
  # -------------------------------------------------------------
88
126
  # Samplable interface include and overriding
89
127
  # -------------------------------------------------------------
@@ -97,8 +135,10 @@ class Range
97
135
  return (self.begin + ( self.end - self.begin ) * value)
98
136
  end
99
137
 
100
- # to speed up samplation on ranges, as used everywhere
101
- def generate( nsamples ) #:nodoc:
138
+ # Very fundamental generator
139
+ #
140
+ # Generates a sequence of "nsamples" floats between 0.0 and 1.0 (included)
141
+ def Range.generate( nsamples )
102
142
  result = []
103
143
  if nsamples == 1
104
144
  result = [0.0]
@@ -107,21 +147,26 @@ class Range
107
147
  end
108
148
  return result
109
149
  end
150
+
151
+ # Simply redirect on Range.generate
152
+ def generate( nsamples ) #:nodoc:
153
+ return Range.generate( nsamples )
154
+ end
110
155
 
111
156
  # apply_sample is good by default
112
157
  # apply_split is good by default
113
158
 
114
- # size of the range
115
- # (0.0..2.0).size => 2.0
116
- def size
117
- return self.end - self.begin
118
- end
119
-
120
159
  # returns a reversed range
121
160
  # (1.0..2.0).reverse => (2.0..1.0)
122
161
  def reverse
123
162
  return Range.new( self.end, self.begin )
124
163
  end
164
+
165
+ # returns an increasing Range
166
+ # (2.0..1.0).sort => (1.0..2.0)
167
+ def sort
168
+ return (self.begin > self.end ? Range.new( self.end, self.begin ) : Range.new( self.begin, self.end ))
169
+ end
125
170
 
126
171
  # resize range by factor, with fixed point center of the range
127
172
  # (1.0..2.0).resize( 0.5 ) => (1.25..1.75)
@@ -207,6 +252,14 @@ class Range
207
252
  return self.samples( samples )
208
253
  end
209
254
 
255
+ # alias for .random.samples
256
+ def rand(nsamples=1,&block)
257
+ inputs = []
258
+ nsamples.times {|v| inputs.push( Kernel::rand )}
259
+ result = self.process( inputs, :sample, &block )
260
+ return nsamples == 1 ? result[0] : result
261
+ end
262
+
210
263
  # deprecated
211
264
  #
212
265
  # TODO : must add gauss parameters
@@ -262,10 +315,22 @@ class Array
262
315
  return self.sum / self.size
263
316
  end
264
317
 
318
+ # return a random item from array
319
+ def choice
320
+ return self[Kernel::rand(self.size)]
321
+ end
322
+
265
323
  # compute range of an array by returning (min..max)
266
324
  # [1.0, 3.0, 2.0].range => (1.0..3.0)
325
+ # if proc supplied, use it to return range of subvalues
326
+ # [V2D::O, V2D::X].range( :x ) => (0.0..1.0)
267
327
  def range( proc=nil )
268
- return (self.min..self.max)
328
+ if not proc
329
+ return (self.min..self.max)
330
+ else
331
+ arraytmp = self.map {|item| item.send( proc )}
332
+ return arraytmp.range
333
+ end
269
334
  end
270
335
 
271
336
  # alias for sub(2)
@@ -384,6 +449,11 @@ class Array
384
449
  return result
385
450
  end
386
451
 
452
+ # shuffle values in array
453
+ def shuffle
454
+ return self.sort_by{ rand }
455
+ end
456
+
387
457
  # -------------------------------------------------------------
388
458
  # Samplable interface include and overriding
389
459
  # -------------------------------------------------------------
@@ -395,6 +465,10 @@ class Array
395
465
  return self.map {|v| v.compute( inputs, type )}.forzip(nil,&block)
396
466
  end
397
467
 
468
+ def addfilter( newfilter )
469
+ self.each {|v| v.addfilter( newfilter )}
470
+ end
471
+
398
472
  end
399
473
 
400
474
  # -------------------------------------------------------------
@@ -409,24 +483,21 @@ class String #:nodoc:
409
483
 
410
484
  end
411
485
 
412
- class Float #:nodoc:
413
-
414
- def complement( max = 1.0, min = 0.0 )
415
- return ( max - ( self.to_f - min ) )
416
- end
417
-
486
+ # Ruby base class Float extension
487
+ #
488
+ # Mainly to be able to compare two floats with specific accuracy
489
+ class Float
490
+
491
+ # compare two Float with specific precision
492
+ # assert( 0.25.fequal?( 0.26,0.02) )
493
+ # assert_equal( false, 0.25.fequal?( 0.26,0.01) )
418
494
  def fequal?( other, epsilon=0.0000000001 )
419
495
  return ((self - other).abs < epsilon)
420
496
  end
421
497
 
422
- def randsplit(minsize=0.0)
423
- v = self.to_f
424
- rand = minsize + Kernel::rand * (1.0 - minsize )
425
- min = v * rand
426
- max = v - min
427
- return [min, max]
428
- end
429
-
498
+ # sort and remove duplicated elements of a float list with specific precision
499
+ # assert_equal( [0.25], Float.sort_float_list([0.26,0.25], 0.02 ) )
500
+ # assert_equal( [0.25,0.26], Float.sort_float_list([0.26,0.25], 0.01 ) )
430
501
  def Float.sort_float_list( floatlist, epsilon=0.0000001 )
431
502
  floatlist = floatlist.uniq.sort
432
503
  result = [floatlist[0]]
@@ -438,6 +509,9 @@ class Float #:nodoc:
438
509
  return result
439
510
  end
440
511
 
512
+ # check if an Float item is included in a Float list, with specific precision
513
+ # assert( Float.floatlist_include?( [1.0,2.0,3.0001,4.0], 3.0, 0.001 ) )
514
+ # assert_equal( false, Float.floatlist_include?( [1.0,2.0,3.0001,4.0], 3.0, 0.0001 ) )
441
515
  def Float.floatlist_include?( floatlist, float, epsilon=0.0000001 )
442
516
  floatlist.each do |item|
443
517
  if item.fequal?( float, epsilon )
@@ -446,58 +520,5 @@ class Float #:nodoc:
446
520
  end
447
521
  return false
448
522
  end
449
-
450
-
451
- end
452
-
453
-
454
- class Integer #:nodoc:
455
-
456
-
457
- def randsplit!(minsize=0.0)
458
- size = 1.0
459
- nsplit = self.to_i
460
- rsize = size - nsplit * minsize
461
- if rsize < 0.0
462
- return []
463
- end
464
-
465
- minsizes = Array.new( nsplit, minsize )
466
- # puts "minsizes #{minsizes.join(" ")}"
467
-
468
- randarray = [0.0]
469
- subarray = (0.0..rsize).rand( nsplit - 1 )
470
- Trace("subarray #{subarray.inspect}")
471
- randarray += subarray
472
- randarray.push( rsize )
473
- randarray.sort!
474
-
475
- # puts "randarray #{randarray.join(" ")}"
476
-
477
- rsizes = Array.new
478
- randarray.each_cons(2) { |min, max| rsizes.push( max - min ) }
479
-
480
- # puts "rsizes #{rsizes.join(" ")}"
481
-
482
- result = Array.new
483
- minsizes.zip( rsizes ) {|minsize, rsize| result.push( minsize + rsize )}
484
-
485
- # puts "result randsplit! #{result.join(" ")}"
486
-
487
- return result
488
- end
489
-
490
- def randsplitsum!(minsize=0.0)
491
- preresult = self.randsplit!(minsize)
492
-
493
- result = Array.new
494
- sum = 0
495
- preresult.each {|v| sum += v; result.push( sum ) }
496
-
497
- # puts "result randsplitsum! #{result.join(" ")}"
498
- return result
499
- end
500
-
501
-
502
523
  end
503
524
 
data/lib/xrvg.rb CHANGED
@@ -1,9 +1,9 @@
1
- # This file is to be included if you want to start a XRVG script
1
+ # This file has to be included if you want to start a XRVG script
2
2
  #
3
3
  # Please refer to README for XRVG introduction
4
4
 
5
5
  # XRVG version (used in rakefile)
6
- XRVG_VERSION = "0.0.5"
6
+ XRVG_VERSION = "0.0.6"
7
7
 
8
8
  # XRVG namespace
9
9
  module XRVG
@@ -39,7 +39,7 @@ require 'beziermotifs'
39
39
  require 'beziertools'
40
40
  require 'interbezier'
41
41
  require 'geovariety'
42
- # require 'spiral'
42
+ require 'spiral'
43
43
  # require 'graph'
44
44
 
45
45
 
data/test/test_bezier.rb CHANGED
@@ -147,6 +147,7 @@ class BezierTest < Test::Unit::TestCase
147
147
  [:raw, V2D[1.0, 0.0], V2D[2.0, 2.0], V2D[1.0, 1.0], V2D[2.0, 0.0] ],
148
148
  [:raw, V2D[2.0, 0.0], V2D[2.0, 2.0], V2D[1.0, 1.0], V2D[3.0, 0.0] ]]
149
149
  assert_equal( 3, Bezier.multi( pieces ).subbezier(0.1,0.9).piecenumber )
150
+ assert_equal( 3, Bezier.multi( pieces ).subbezier(0.9,0.1).piecenumber )
150
151
  end
151
152
 
152
153
  def test_computelength
@@ -237,7 +238,7 @@ class BezierTest < Test::Unit::TestCase
237
238
  end
238
239
 
239
240
  def test_gdebug
240
- require 'render'
241
+ # require 'render'
241
242
  render = SVGRender[]
242
243
  @@bezier.gdebug( render )
243
244
  end
@@ -256,7 +257,21 @@ class BezierTest < Test::Unit::TestCase
256
257
  assert( V2D.vequal?( V2D[0.5, 0.5], @@beziersym.filter(:point).sample( 0.5 ) ) )
257
258
  end
258
259
 
259
-
260
+ def test_transform
261
+ bezier = Bezier.raw( V2D[0.0, 0.0], V2D[1.0, 0.0], V2D[-1.0, 0.0], V2D[1.0, 0.0] )
262
+ # assert_equal( [V2D[0.0, 0.0], V2D[-1.0, 0.0], V2D[1.0, 0.0], V2D[-1.0, 0.0]], bezier.rotate( Range.Angle.sample( 0.5 ) ).pointlist )
263
+ assert_equal( V2D[0.0, 0.0], bezier.rotate( Range.Angle.sample( 0.5 ) ).firstpoint )
264
+ # assert_equal( bezier.pointlist, bezier.rotate( Range.Angle.sample( 1.0 ) ).pointlist )
265
+ assert_equal( bezier.firstpoint, bezier.rotate( Range.Angle.sample( 1.0 ) ).firstpoint )
266
+ # assert_equal( [V2D[0.0, 0.0], V2D[-1.0, 0.0], V2D[1.0, 0.0], V2D[-1.0, 0.0]], bezier.sym( V2D::O ).pointlist )
267
+ assert_equal( V2D[0.0, 0.0], bezier.sym( V2D::O ).firstpoint )
268
+ # assert_equal( bezier.pointlist, bezier.sym( V2D::O ).sym( V2D::O ).pointlist )
269
+ assert_equal( bezier.firstpoint, bezier.sym( V2D::O ).sym( V2D::O ).firstpoint )
270
+ # assert_equal( [V2D[0.0, 0.0], V2D[-1.0, 0.0], V2D[1.0, 0.0], V2D[-1.0, 0.0]], bezier.axesym( V2D::O, V2D[0.0,1.0] ).pointlist )
271
+ assert_equal( V2D[0.0, 0.0], bezier.axesym( V2D::O, V2D[0.0,1.0] ).firstpoint )
272
+ # assert_equal( bezier.pointlist, bezier.axesym( V2D::O, V2D[1.0,0.0] ).pointlist )
273
+ assert_equal( bezier.firstpoint, bezier.axesym( V2D::O, V2D[1.0,0.0] ).firstpoint )
274
+ end
260
275
  end
261
276
 
262
277
 
@@ -87,6 +87,6 @@ end
87
87
  class CircleTest < Test::Unit::TestCase
88
88
 
89
89
  def test_bezier
90
- assert_equal( 2, Circle[].bezier.piecenumber )
90
+ assert_equal( 4, Circle[].bezier.piecenumber )
91
91
  end
92
92
  end
@@ -9,6 +9,13 @@ class SimpleBezierTest < Test::Unit::TestCase
9
9
  assert_raise(RuntimeError){SimpleBezier[ :support, [V2D::O] ]}
10
10
  assert_equal( SimpleBezier[ :support, [V2D::O,V2D::X] ].point( 0.3 ), LinearBezier[ :support, [V2D::O,V2D::X] ].point( 0.3 ) )
11
11
  end
12
+
13
+ def test_interpolation
14
+ interpolator = Interpolator[ :samplelist, [0.0,0.0, 0.5,1.0, 1.0,0.0], :interpoltype, :simplebezier]
15
+ assert( 1.0.fequal?( interpolator.interpolate( 0.5 ) ) )
16
+ assert( 0.0.fequal?( interpolator.interpolate( 1.0 ) ) )
17
+ end
18
+
12
19
  end
13
20
 
14
21
  class ClosureTest < Test::Unit::TestCase
data/test/test_color.rb CHANGED
@@ -20,6 +20,7 @@ class ColorTest < Test::Unit::TestCase
20
20
  green = Color[0.0, 1.0, 0.0, 1.0]
21
21
  yellow = Color[1.0, 1.0, 0.0, 1.0]
22
22
  orange = Color[1.0, 0.5, 0.0, 1.0]
23
+ grey10 = Color[0.1, 0.1, 0.1, 1.0]
23
24
  assert_equal( black, Color.black )
24
25
  assert_equal( white, Color.white )
25
26
  assert_equal( red, Color.red )
@@ -27,6 +28,7 @@ class ColorTest < Test::Unit::TestCase
27
28
  assert_equal( green, Color.green )
28
29
  assert_equal( yellow, Color.yellow )
29
30
  assert_equal( orange, Color.orange )
31
+ assert_equal( grey10, Color.grey( 0.1 ) )
30
32
  end
31
33
 
32
34
  def test_rand
@@ -84,6 +86,10 @@ class ColorTest < Test::Unit::TestCase
84
86
  assert_equal( [25,25,25,25], Color[0.1,0.1,0.1,0.1].format255 )
85
87
  end
86
88
 
89
+ def test_operators
90
+ assert_equal( Color[0.2, 0.4, 0.6, 1.0], Color[0.1, 0.2, 0.3, 0.5 ] + Color[0.1, 0.2, 0.3, 0.5 ] )
91
+ assert_equal( Color[0.2, 0.4, 0.6, 1.0], Color[0.1, 0.2, 0.3, 0.5 ] * 2.0 )
92
+ end
87
93
  end
88
94
 
89
95
 
@@ -101,6 +107,12 @@ class PaletteTest < Test::Unit::TestCase
101
107
  palette = Palette.new( :colorlist, [ 0.0, Color.black, 0.3, Color.red, 1.0, Color.white ] ).reverse
102
108
  assert_equal( Color.red, palette.color( 0.7 ) )
103
109
  end
110
+
111
+ def test_interpolator
112
+ palette = Palette.new( :colorlist, [ 0.0, Color.black, 0.3, Color.red, 1.0, Color.white ] )
113
+ palette.interpoltype = :linear
114
+ assert_equal( :linear, palette.interpoltype )
115
+ end
104
116
 
105
117
  end
106
118