xrvg 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +8 -0
- data/README +1 -1
- data/Rakefile +36 -6
- data/examples/arciterate1.rb +13 -0
- data/examples/arcrecurse1.rb +30 -0
- data/examples/arcrecurse2.rb +37 -0
- data/examples/circleiterate1.rb +9 -0
- data/examples/circleiterate2.rb +11 -0
- data/examples/circleiterate3.rb +13 -0
- data/examples/circlerecurse1.rb +27 -0
- data/examples/circlerecurse2.rb +27 -0
- data/examples/circlerecurseall.rb +29 -0
- data/examples/euclideangeo.rb +11 -0
- data/examples/evolution1.rb +8 -0
- data/examples/evolution2.rb +9 -0
- data/examples/evolution3.rb +10 -0
- data/examples/fuseaugeo.rb +16 -0
- data/examples/gradientgeo.rb +21 -0
- data/examples/interbeziergeo1.rb +14 -0
- data/examples/interbeziergeo2.rb +17 -0
- data/examples/interbeziergeo3.rb +17 -0
- data/examples/offsetgeo.rb +16 -0
- data/lib/bezier.rb +37 -3
- data/lib/bezierbuilders.rb +17 -1
- data/lib/beziermotifs.rb +11 -4
- data/lib/bezierspline.rb +23 -1
- data/lib/beziertools.rb +48 -14
- data/lib/color.rb +55 -8
- data/lib/fitting.rb +2 -2
- data/lib/geometry2D.rb +10 -3
- data/lib/geovariety.rb +128 -0
- data/lib/interbezier.rb +4 -4
- data/lib/interpolation.rb +30 -17
- data/lib/parametriclength.rb +3 -2
- data/lib/render.rb +1 -2
- data/lib/samplation.rb +121 -19
- data/lib/shape.rb +2 -2
- data/lib/spiral.rb +72 -0
- data/lib/utils.rb +97 -76
- data/lib/xrvg.rb +3 -3
- data/test/test_bezier.rb +17 -2
- data/test/test_bezierbuilders.rb +1 -1
- data/test/test_beziertools.rb +7 -0
- data/test/test_color.rb +12 -0
- data/test/test_geovariety.rb +105 -0
- data/test/test_interpolation.rb +2 -1
- data/test/test_render.rb +0 -4
- data/test/test_sample.rb +28 -0
- data/test/test_spiral.rb +22 -0
- data/test/test_utils.rb +65 -40
- 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
|
-
|
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
|
-
|
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
|
-
|
345
|
-
|
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
|
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
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
|
-
#
|
101
|
-
|
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
|
-
|
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
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
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
|
-
|
423
|
-
|
424
|
-
|
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
|
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.
|
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
|
-
|
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
|
|
data/test/test_bezierbuilders.rb
CHANGED
data/test/test_beziertools.rb
CHANGED
@@ -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
|
|