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.
- 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
|
|