xrvg 0.0.3 → 0.0.4
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 +21 -0
- data/README +3 -3
- data/Rakefile +4 -4
- data/examples/bezierbasic.rb +1 -0
- data/examples/bezierbasicvector.rb +1 -0
- data/examples/foreach.rb +1 -0
- data/examples/geodash.rb +1 -0
- data/examples/geodash2.rb +1 -0
- data/examples/hellocrown.rb +1 -0
- data/examples/hellocrown2.rb +1 -0
- data/examples/hellocrownrecurse.rb +1 -0
- data/examples/helloworldcompact.rb +1 -0
- data/examples/helloworldexpanded.rb +1 -0
- data/examples/multibezierbasic.rb +1 -0
- data/examples/palette_circle.rb +1 -0
- data/examples/randomdash.rb +1 -0
- data/examples/range_examples.rb +1 -0
- data/examples/range_examples2.rb +1 -0
- data/examples/sample.rb +1 -0
- data/examples/simpledash.rb +1 -0
- data/examples/uplets.rb +1 -0
- data/lib/bezier.rb +21 -55
- data/lib/bezierbuilders.rb +194 -0
- data/lib/beziermotifs.rb +114 -0
- data/lib/bezierspline.rb +20 -75
- data/lib/beziertools.rb +211 -0
- data/lib/color.rb +26 -7
- data/lib/fitting.rb +203 -0
- data/lib/frame.rb +2 -1
- data/lib/geometry2D.rb +6 -5
- data/lib/interbezier.rb +87 -0
- data/lib/interpolation.rb +6 -5
- data/lib/parametriclength.rb +87 -0
- data/lib/render.rb +4 -9
- data/lib/samplation.rb +71 -82
- data/lib/shape.rb +47 -25
- data/lib/style.rb +2 -1
- data/lib/trace.rb +2 -0
- data/lib/utils.rb +111 -17
- data/lib/xrvg.rb +16 -6
- data/test/test_attributable.rb +34 -2
- data/test/test_bezier.rb +93 -2
- data/test/test_bezierbuilders.rb +92 -0
- data/test/test_beziertools.rb +97 -0
- data/test/test_color.rb +65 -24
- data/test/test_fitting.rb +47 -0
- data/test/test_frame.rb +7 -2
- data/test/test_geometry2D.rb +26 -7
- data/test/test_interbezier.rb +29 -0
- data/test/test_interpolation.rb +16 -1
- data/test/test_parametric_length.rb +15 -0
- data/test/test_render.rb +54 -6
- data/test/test_shape.rb +103 -10
- data/test/test_trace.rb +13 -0
- data/test/test_utils.rb +114 -12
- data/test/test_xrvg.rb +3 -0
- metadata +16 -5
- data/lib/assertion.rb +0 -14
- data/lib/attributable.rb +0 -152
data/lib/color.rb
CHANGED
@@ -8,8 +8,8 @@ require 'interpolation'
|
|
8
8
|
require 'attributable'
|
9
9
|
require 'utils'
|
10
10
|
require 'shape'; # for gradient
|
11
|
-
require 'matrix'
|
12
11
|
|
12
|
+
module XRVG
|
13
13
|
#
|
14
14
|
# Color class
|
15
15
|
#
|
@@ -35,6 +35,10 @@ class Color
|
|
35
35
|
#
|
36
36
|
# r, g, b, a must be between 0.0 and 1.0
|
37
37
|
def initialize( r, g, b, a)
|
38
|
+
r = Range.O.trim( r )
|
39
|
+
g = Range.O.trim( g )
|
40
|
+
b = Range.O.trim( b )
|
41
|
+
a = Range.O.trim( a )
|
38
42
|
@items = [r,g,b,a]
|
39
43
|
end
|
40
44
|
|
@@ -96,31 +100,31 @@ class Color
|
|
96
100
|
# set the red composant
|
97
101
|
# Color[0.1,0.2,0.3,0.4].r = 0.5 => Color[0.5,0.2,0.3,0.4]
|
98
102
|
def r=(n)
|
99
|
-
|
103
|
+
@items[0]= n
|
100
104
|
end
|
101
105
|
|
102
106
|
# set the green composant
|
103
107
|
# Color[0.1,0.2,0.3,0.4].g = 0.5 => Color[0.1,0.5,0.3,0.4]
|
104
108
|
def g=(n)
|
105
|
-
|
109
|
+
@items[1] = n
|
106
110
|
end
|
107
111
|
|
108
112
|
# set the blue composant
|
109
113
|
# Color[0.1,0.2,0.3,0.4].b = 0.5 => Color[0.1,0.2,0.5,0.4]
|
110
114
|
def b=(n)
|
111
|
-
|
115
|
+
@items[2] = n
|
112
116
|
end
|
113
117
|
|
114
118
|
# set the opacity composant
|
115
119
|
# Color[0.1,0.2,0.3,0.4].a = 0.5 => Color[0.1,0.2,0.3,0.5]
|
116
120
|
def a=(n)
|
117
|
-
|
121
|
+
@items[3] = n
|
118
122
|
end
|
119
123
|
|
120
124
|
# return an array containing colors on 255 integer format
|
121
125
|
# Color[0.0,1.0,0.0,1.0].format255 => [0,255,0,255]
|
122
126
|
def format255()
|
123
|
-
return
|
127
|
+
return @items.map {|v| (v * 255.0).to_i}
|
124
128
|
end
|
125
129
|
|
126
130
|
# return a random color vector, with 1.0 opacity !!
|
@@ -165,13 +169,23 @@ class Color
|
|
165
169
|
end
|
166
170
|
|
167
171
|
# build a color vector from hsv parametrization (convert from hsv to rgb) h, s, v being between 0.0 and 1.0
|
172
|
+
#
|
168
173
|
# taken from wikipedia[http://en.wikipedia.org/wiki/HSV_color_space]
|
174
|
+
#
|
175
|
+
# error on algo with h = 1.0 => hi == 6 mustbe taken into account
|
169
176
|
def Color.hsv( h, s, v, a)
|
177
|
+
h = Range.O.trim( h )
|
178
|
+
s = Range.O.trim( s )
|
179
|
+
v = Range.O.trim( v )
|
180
|
+
a = Range.O.trim( a )
|
170
181
|
if s == 0.0
|
171
182
|
return Color[v, v, v, a]
|
172
183
|
end
|
173
184
|
h *= 360.0
|
174
185
|
hi = (h/60.0).floor
|
186
|
+
if hi == 6
|
187
|
+
hi = 5
|
188
|
+
end
|
175
189
|
f = (h/60.0) - hi
|
176
190
|
p = v * ( 1 - s )
|
177
191
|
q = v * ( 1 - f * s )
|
@@ -220,6 +234,10 @@ class Color
|
|
220
234
|
# taken from [[http://en.wikipedia.org/wiki/HSV_color_space]]
|
221
235
|
# h, s, l must be between 0.0 and 1.0
|
222
236
|
def Color.hsl( h, s, l, a)
|
237
|
+
h = Range.O.trim( h )
|
238
|
+
s = Range.O.trim( s )
|
239
|
+
l = Range.O.trim( l )
|
240
|
+
a = Range.O.trim( a )
|
223
241
|
h *= 360.0
|
224
242
|
if l < 0.5
|
225
243
|
q = l * (1.0 + s)
|
@@ -292,7 +310,7 @@ end
|
|
292
310
|
|
293
311
|
class Gradient < Palette #:nodoc:
|
294
312
|
def defsvg()
|
295
|
-
|
313
|
+
raise NotImplementedError.new("#{self.class.name}#defsvg is an abstract method.")
|
296
314
|
end
|
297
315
|
end
|
298
316
|
|
@@ -332,3 +350,4 @@ class CircularGradient < Gradient #:nodoc:
|
|
332
350
|
"%r%" => circle.radius} )
|
333
351
|
end
|
334
352
|
end
|
353
|
+
end
|
data/lib/fitting.rb
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
#
|
2
|
+
# Fitting file. See +Fitting+
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'matrix'; # for matrix inversion
|
6
|
+
require 'bezier.rb'; # for error computation
|
7
|
+
|
8
|
+
module XRVG
|
9
|
+
#
|
10
|
+
# = Fitting computation class
|
11
|
+
# == Intro
|
12
|
+
# Used to compute cubic curve fitting on a list of points (that is sampling inverse operation). Only 2D.
|
13
|
+
# == Example
|
14
|
+
# Compute the most fitting single piece bezier curve given list of points
|
15
|
+
# bezier = Fitting.compute( points )
|
16
|
+
# Compute multipieces bezier curve given list of points
|
17
|
+
# bezier = Fitting.adaptative_compute( points )
|
18
|
+
class Fitting
|
19
|
+
|
20
|
+
# compute first parameter t estimated values from length between consecutive points
|
21
|
+
def Fitting.initparameters( pointlist, parameters=nil ) #:nodoc:
|
22
|
+
lengths = [0.0]
|
23
|
+
pointlist.pairs do |p1, p2|
|
24
|
+
lengths.push( lengths[-1] + (p1-p2).r )
|
25
|
+
end
|
26
|
+
tlength = lengths[-1]
|
27
|
+
if not parameters
|
28
|
+
if not tlength == 0.0
|
29
|
+
parameters = lengths.map {|length| length / tlength}
|
30
|
+
else
|
31
|
+
parameters = [0.0] * pointlist.length
|
32
|
+
end
|
33
|
+
end
|
34
|
+
return [parameters, tlength]
|
35
|
+
end
|
36
|
+
|
37
|
+
# compute control points from polynomial bezier representation
|
38
|
+
#
|
39
|
+
# a, b, c, d are such as
|
40
|
+
# piece( t ) = at3 + bt2 + ct + d
|
41
|
+
def Fitting.bezierpiece( a, b, c, d )
|
42
|
+
p0 = d
|
43
|
+
p1 = p0 + c / 3.0
|
44
|
+
p2 = p1 + c / 3.0 + b / 3.0
|
45
|
+
p3 = p0 + c + b + a
|
46
|
+
return [p0, p1, p2, p3]
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Base method
|
51
|
+
#
|
52
|
+
# Given a pointlist, compute the closest matching cubic bezier curve
|
53
|
+
#
|
54
|
+
# Result is in the form [p1, pc1, pc2, p2], with [p1, pc1, pc2, p2] V2D
|
55
|
+
#
|
56
|
+
# maxerror is normalized with curve length. In case of good match (that is pointlist can be modelized by cubic bezier curve),
|
57
|
+
# result error will be under maxerror. If not, result may be above maxerror. In that case, computation is stopped because error
|
58
|
+
# no longer decrease, or because iteration is too long.
|
59
|
+
def Fitting.compute( pointlist, maxerror=0.01, maxiter=100 )
|
60
|
+
parameters, tlength = Fitting.initparameters( pointlist )
|
61
|
+
perror = 1.0
|
62
|
+
niter = 0
|
63
|
+
while true
|
64
|
+
bezier, coeffs = Fitting.iterate( pointlist, parameters )
|
65
|
+
error = Fitting.error( bezier, pointlist, parameters ) / tlength
|
66
|
+
parameters = Fitting.renormalize( bezier, coeffs, pointlist, parameters )
|
67
|
+
if (error < maxerror || (error-perror).abs < 0.00001 || niter > maxiter )
|
68
|
+
break
|
69
|
+
end
|
70
|
+
niter += 1
|
71
|
+
end
|
72
|
+
return bezier
|
73
|
+
end
|
74
|
+
|
75
|
+
# adaptative computation with automatic splitting if error not low enough, or if convergence is not fast enough
|
76
|
+
#
|
77
|
+
#
|
78
|
+
def Fitting.adaptative_compute( pointlist, maxerror=0.0001, maxiter=10, tlength=nil )
|
79
|
+
parameters, tlengthtmp = Fitting.initparameters( pointlist )
|
80
|
+
if parameters == [0] * pointlist.length
|
81
|
+
return [Bezier.single(:vector, pointlist[0], V2D::O, pointlist[0], V2D::O),0.0]
|
82
|
+
end
|
83
|
+
tlength ||= tlengthtmp
|
84
|
+
niter = 0
|
85
|
+
bezier = nil
|
86
|
+
while true
|
87
|
+
bezier, coeffs = Fitting.iterate( pointlist, parameters )
|
88
|
+
error = Fitting.error( bezier, pointlist, parameters ) / tlength
|
89
|
+
parameters = Fitting.renormalize( bezier, coeffs, pointlist, parameters )
|
90
|
+
|
91
|
+
# pointlist.length > 8 because matching with a bezier needs at least 4 points
|
92
|
+
if (niter > maxiter and error > maxerror and pointlist.length > 8)
|
93
|
+
pointlists = [pointlist[0..pointlist.length/2 - 1], pointlist[pointlist.length/2 - 1 ..-1]]
|
94
|
+
beziers = []
|
95
|
+
errors = []
|
96
|
+
pointlists.each do |subpointlist|
|
97
|
+
subbezier, suberror = Fitting.adaptative_compute( subpointlist, maxerror, maxiter, tlength )
|
98
|
+
beziers << subbezier
|
99
|
+
errors << suberror
|
100
|
+
end
|
101
|
+
bezier = beziers.sum
|
102
|
+
error = errors.max
|
103
|
+
break
|
104
|
+
elsif (error < maxerror || niter > maxiter)
|
105
|
+
break
|
106
|
+
end
|
107
|
+
perror = error
|
108
|
+
niter += 1
|
109
|
+
end
|
110
|
+
return [bezier, error]
|
111
|
+
end
|
112
|
+
|
113
|
+
# algo comes from http://www.tinaja.com/glib/bezdist.pdf
|
114
|
+
def Fitting.renormalize( bezier, coeffs, pointlist, parameters )
|
115
|
+
a3, a2, a1, a0 = coeffs
|
116
|
+
dxdu = Proc.new {|u| 3.0*a3.x*u**2 + 2.0*a2.x*u + a1.x}
|
117
|
+
dydu = Proc.new {|u| 3.0*a3.y*u**2 + 2.0*a2.y*u + a1.y}
|
118
|
+
container = V2D[]
|
119
|
+
z = Proc.new {|u,p4| p = bezier.point( u, container, :parameter ); (p.x - p4.x) * dxdu.call( u ) + (p.y - p4.y) * dydu.call( u )}
|
120
|
+
newparameters = []
|
121
|
+
[pointlist, parameters].forzip do |point, parameter|
|
122
|
+
u1 = parameter
|
123
|
+
if parameter < 0.99
|
124
|
+
u2 = parameter + 0.01
|
125
|
+
else
|
126
|
+
u2 = parameter - 0.01
|
127
|
+
end
|
128
|
+
z1 = z.call(u1,point)
|
129
|
+
z2 = z.call(u2,point)
|
130
|
+
if z1 == z2
|
131
|
+
u2 += 0.01
|
132
|
+
z2 = z.call(u2,point)
|
133
|
+
end
|
134
|
+
if z1 == z2
|
135
|
+
u2 -= 0.01
|
136
|
+
z2 = z.call(u2,point)
|
137
|
+
end
|
138
|
+
newparameters << (z2 * u1 - z1 * u2)/(z2-z1)
|
139
|
+
end
|
140
|
+
return newparameters
|
141
|
+
end
|
142
|
+
|
143
|
+
# error is max error between points in pointlist and points sampled from bezier with parameters
|
144
|
+
def Fitting.error( bezier, pointlist, parameters )
|
145
|
+
maxerror = 0.0
|
146
|
+
container = V2D[]
|
147
|
+
[pointlist, parameters].forzip do |point, parameter|
|
148
|
+
Trace("point #{point.inspect} parameter #{parameter}")
|
149
|
+
error = (point - bezier.point( parameter, container, :parameter )).r
|
150
|
+
if error > maxerror
|
151
|
+
maxerror = error
|
152
|
+
end
|
153
|
+
end
|
154
|
+
Trace("Fitting.error #{maxerror}")
|
155
|
+
return maxerror
|
156
|
+
end
|
157
|
+
|
158
|
+
# iterate method compute new bezier parameters from pointlist and previous bezier parameters
|
159
|
+
#
|
160
|
+
# Algo comes from http://www.tinaja.com/glib/bezdist.pdf
|
161
|
+
#
|
162
|
+
# TODO : optimized
|
163
|
+
def Fitting.iterate( pointlist, parameters )
|
164
|
+
p0 = pointlist[0]
|
165
|
+
p1 = pointlist[-1]
|
166
|
+
|
167
|
+
sumt0 = parameters.map{ |t| t**0.0 }.sum
|
168
|
+
sumt1 = parameters.map{ |t| t**1.0 }.sum
|
169
|
+
sumt2 = parameters.map{ |t| t**2.0 }.sum
|
170
|
+
sumt3 = parameters.map{ |t| t**3.0 }.sum
|
171
|
+
sumt4 = parameters.map{ |t| t**4.0 }.sum
|
172
|
+
sumt5 = parameters.map{ |t| t**5.0 }.sum
|
173
|
+
sumt6 = parameters.map{ |t| t**6.0 }.sum
|
174
|
+
|
175
|
+
psumt1 = [pointlist, parameters].forzip.foreach(2).map {|point, t| point * (t**1.0) }.inject(V2D::O){|sum, item| sum + item}
|
176
|
+
psumt2 = [pointlist, parameters].forzip.foreach(2).map {|point, t| point * (t**2.0) }.inject(V2D::O){|sum, item| sum + item}
|
177
|
+
psumt3 = [pointlist, parameters].forzip.foreach(2).map {|point, t| point * (t**3.0) }.inject(V2D::O){|sum, item| sum + item}
|
178
|
+
|
179
|
+
coeff11 = sumt6 - 2 * sumt4 + sumt2
|
180
|
+
coeff12 = sumt5 - sumt4 - sumt3 + sumt2
|
181
|
+
|
182
|
+
coeff21 = coeff12
|
183
|
+
coeff22 = sumt4 - 2 * sumt3 + sumt2
|
184
|
+
|
185
|
+
result1 = (p0 - p1) * (sumt4 - sumt2) - p0 * (sumt3 - sumt1) + psumt3 - psumt1
|
186
|
+
result2 = (p0 - p1) * (sumt3 - sumt2) - p0 * (sumt2 - sumt1) + psumt2 - psumt1
|
187
|
+
|
188
|
+
matrix = Matrix[ [coeff11, coeff12], [coeff21, coeff22] ]
|
189
|
+
matrixinv = matrix.inverse
|
190
|
+
ax, bx = (matrixinv * Vector[result1.x, result2.x])[0..-1]
|
191
|
+
ay, by = (matrixinv * Vector[result1.y, result2.y])[0..-1]
|
192
|
+
|
193
|
+
a = V2D[ax, ay]
|
194
|
+
b = V2D[bx, by]
|
195
|
+
d = p0
|
196
|
+
c = p1- (a + b + p0)
|
197
|
+
|
198
|
+
piece = Fitting.bezierpiece( a, b, c, d )
|
199
|
+
return [Bezier.raw( *piece ), [a, b, c, d] ]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
end # end XRVG
|
data/lib/frame.rb
CHANGED
data/lib/geometry2D.rb
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
|
6
6
|
require 'Attributable'
|
7
7
|
|
8
|
+
module XRVG
|
8
9
|
#
|
9
10
|
# 2D vector
|
10
11
|
#
|
@@ -98,9 +99,9 @@ class V2D
|
|
98
99
|
|
99
100
|
# method necessary to make V2D Ranges
|
100
101
|
#
|
101
|
-
# simply
|
102
|
+
# simply add 1.0 to each coord
|
102
103
|
def succ()
|
103
|
-
return V2D[ self.x.
|
104
|
+
return V2D[ self.x + 1.0, self.y + 1.0 ]
|
104
105
|
end
|
105
106
|
|
106
107
|
# compute length of 2D vector (r notation to be compatible with V2D)
|
@@ -169,8 +170,8 @@ class V2D
|
|
169
170
|
return V2D[ -self.y, self.x ]
|
170
171
|
end
|
171
172
|
|
172
|
-
# compute the symetric of vector
|
173
|
-
# V2D[1.0,2.0].sym( V2D[0.0,0.0] ) => V2D[
|
173
|
+
# compute the symetric of vector "other" considering self as symetry center
|
174
|
+
# V2D[1.0,2.0].sym( V2D[0.0,0.0] ) => V2D[2.0,4.0]
|
174
175
|
def sym( other )
|
175
176
|
return self * 2.0 - other
|
176
177
|
end
|
@@ -230,4 +231,4 @@ class V2D
|
|
230
231
|
return [xmax - xmin, ymax - ymin]
|
231
232
|
end
|
232
233
|
end
|
233
|
-
|
234
|
+
end
|
data/lib/interbezier.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'bezier'
|
2
|
+
|
3
|
+
module XRVG
|
4
|
+
class InterBezier
|
5
|
+
include Attributable
|
6
|
+
attribute :bezierlist
|
7
|
+
|
8
|
+
include Interpolation
|
9
|
+
|
10
|
+
def initialize( *args )
|
11
|
+
super( *args )
|
12
|
+
self.init_interpolation_structures
|
13
|
+
end
|
14
|
+
|
15
|
+
def init_interpolation_structures
|
16
|
+
beziers = []
|
17
|
+
indexes = []
|
18
|
+
@bezierlist.foreach do |index, bezier|
|
19
|
+
beziers.push( bezier )
|
20
|
+
indexes.push( index )
|
21
|
+
end
|
22
|
+
|
23
|
+
lengthH = {}
|
24
|
+
alllengths = []
|
25
|
+
beziers.each do |bezier|
|
26
|
+
lengths = bezier.piecelengths
|
27
|
+
# Trace("bezier lengths #{lengths.inspect}")
|
28
|
+
lengthH[ bezier ] = lengths
|
29
|
+
alllengths += lengths
|
30
|
+
end
|
31
|
+
alllengths = Float.sort_float_list( alllengths )
|
32
|
+
# Trace("alllengths #{alllengths.inspect}")
|
33
|
+
|
34
|
+
newbezierlist = []
|
35
|
+
beziers.each do |bezier|
|
36
|
+
newpieces = []
|
37
|
+
initlengths = lengthH[ bezier ]
|
38
|
+
alllengths.pairs do |l1, l2|
|
39
|
+
newpieces += bezier.subbezier( l1, l2 ).pieces
|
40
|
+
end
|
41
|
+
newbezier = Bezier[ :pieces, newpieces ]
|
42
|
+
newbezierlist << newbezier
|
43
|
+
end
|
44
|
+
|
45
|
+
# Trace("newbezierlist #{newbezierlist.inspect}")
|
46
|
+
beziers = newbezierlist
|
47
|
+
bezierpointlists = beziers.map {|bezier| bezier.pointlist(:vector) }
|
48
|
+
# Trace("bezierpointlists #{bezierpointlists.map {|list| list.length}.inspect}")
|
49
|
+
pointsequencelist = bezierpointlists.forzip
|
50
|
+
@interpolatorlist = []
|
51
|
+
pointsequencelist.foreach(beziers.size) do |pointsequence|
|
52
|
+
interlist = [indexes, pointsequence].forzip
|
53
|
+
@interpolatorlist.push( Interpolator.new( :samplelist, interlist ) )
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def interpolate( abs, container=nil )
|
58
|
+
pieces = []
|
59
|
+
@interpolatorlist.foreach(4) do |interpiece|
|
60
|
+
piece = interpiece.map {|inter| inter.interpolate( abs )}
|
61
|
+
pieces.push( [:vector] + piece )
|
62
|
+
end
|
63
|
+
return Bezier.multi( pieces )
|
64
|
+
end
|
65
|
+
|
66
|
+
include Samplable
|
67
|
+
alias apply_sample interpolate
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
class GradientBezier < InterBezier
|
72
|
+
|
73
|
+
# TODO : does not work !!
|
74
|
+
def samples( nsamples, &block )
|
75
|
+
return super( nsamples + 1, &block )
|
76
|
+
end
|
77
|
+
|
78
|
+
def apply_samples( samples )
|
79
|
+
samples = super( samples )
|
80
|
+
result = []
|
81
|
+
samples.pairs do |bezier1, bezier2|
|
82
|
+
result.push( ClosureBezier.build( :bezierlist, [bezier1, bezier2.reverse]) )
|
83
|
+
end
|
84
|
+
return result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end # XRVG
|
data/lib/interpolation.rb
CHANGED
@@ -7,7 +7,9 @@
|
|
7
7
|
|
8
8
|
require 'utils'
|
9
9
|
require 'attributable'
|
10
|
+
require 'samplation'
|
10
11
|
|
12
|
+
module XRVG
|
11
13
|
# Interpolation module
|
12
14
|
# = Intro
|
13
15
|
# Defines an interpolation service from a samplelist that must be a list [value1, index1, value2, index2, ..., valueN, indexN],
|
@@ -24,7 +26,7 @@ module Interpolation
|
|
24
26
|
# for example, Palette redefines samplelist as
|
25
27
|
# alias samplelist colorlist
|
26
28
|
def samplelist()
|
27
|
-
|
29
|
+
raise NotImplementedError.new("#{self.class.name}#samplelist is an abstract method.")
|
28
30
|
end
|
29
31
|
|
30
32
|
# computing method
|
@@ -59,6 +61,8 @@ class Interpolator
|
|
59
61
|
include Attributable
|
60
62
|
attribute :samplelist
|
61
63
|
include Interpolation
|
64
|
+
include Samplable
|
65
|
+
alias apply_sample interpolate
|
62
66
|
end
|
63
67
|
|
64
68
|
class QuadRange
|
@@ -70,10 +74,6 @@ class QuadRange
|
|
70
74
|
@range = range
|
71
75
|
end
|
72
76
|
|
73
|
-
def limit
|
74
|
-
return @limit
|
75
|
-
end
|
76
|
-
|
77
77
|
def range( index )
|
78
78
|
if @limit
|
79
79
|
if index < @limit
|
@@ -156,3 +156,4 @@ class InterpolatorQuad < Interpolator
|
|
156
156
|
return result
|
157
157
|
end
|
158
158
|
end
|
159
|
+
end
|