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/beziertools.rb
CHANGED
@@ -63,6 +63,29 @@ class SimpleBezier < BezierBuilder
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
#
|
67
|
+
# Interpolation extension with SimpleBezier
|
68
|
+
#
|
69
|
+
module Interpolation
|
70
|
+
|
71
|
+
def compute_simplebezier
|
72
|
+
points = self.samplelist.foreach(2).map { |index, value| V2D[index,value] }
|
73
|
+
@simplebezier = SimpleBezier[ :support, points ]
|
74
|
+
end
|
75
|
+
|
76
|
+
def getcurve
|
77
|
+
if not @simplebezier
|
78
|
+
self.compute_simplebezier
|
79
|
+
end
|
80
|
+
return @simplebezier
|
81
|
+
end
|
82
|
+
|
83
|
+
def simplebezier( dindex )
|
84
|
+
return self.getcurve.sample( dindex ).y
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
66
89
|
|
67
90
|
# = Offset bezier builder
|
68
91
|
# == Content
|
@@ -179,7 +202,31 @@ class Ondulation < BezierBuilder
|
|
179
202
|
attribute :abscissasampler, (0.0..1.0), Samplable
|
180
203
|
attribute :freq, 10
|
181
204
|
|
205
|
+
# atomic pattern computation
|
206
|
+
#
|
207
|
+
def compute_arc( abs1, abs2, amplitude, sens )
|
208
|
+
mabs = (abs1 + abs2)/2.0
|
209
|
+
p1, halfpoint, p2 = self.support.points( [abs1, mabs, abs2] )
|
210
|
+
# Trace("mabs #{mabs} abs1 #{abs1} abs2 #{abs2} halfpoint #{halfpoint.inspect} p1 #{p1.inspect} p2 #{p2.inspect}")
|
211
|
+
# Trace("normal #{@support.normal( mabs )}")
|
212
|
+
halfnormal = self.support.normal( mabs ).norm * ( sens * amplitude * (p2 - p1).length)
|
213
|
+
# Trace("halfnormal #{halfnormal.inspect}")
|
214
|
+
newpoint = halfpoint + halfnormal
|
215
|
+
tpoint = halfpoint + halfnormal * 3.0
|
216
|
+
t1 = (tpoint - p1 ) / 6.0
|
217
|
+
t2 = (tpoint - p2 ) / 6.0
|
218
|
+
# Trace("newpoint #{newpoint.inspect} p1 #{p1.inspect} (newpoint - p1) #{(newpoint - p1).inspect}")
|
219
|
+
halftangent = self.support.tangent( mabs ).norm * (newpoint - p1).length / 3.0
|
220
|
+
# halftangent = self.support.tangent( mabs ).norm * (p2 - p1).length / 3.0
|
221
|
+
return [[:vector, p1, t1, newpoint, -halftangent], [:vector, newpoint, halftangent, p2, t2]]
|
222
|
+
end
|
182
223
|
|
224
|
+
def compute_interpol( abs1, abs2, amplitude, sens )
|
225
|
+
arc = Bezier.multi( self.compute_arc( abs1, abs2, 1.0, sens ) )
|
226
|
+
subsupport = self.support.subbezier( abs1, abs2 )
|
227
|
+
return InterBezier[ :bezierlist, [0.0, subsupport, 1.0, arc] ].sample( amplitude ).data
|
228
|
+
end
|
229
|
+
|
183
230
|
# algo : for each abscissa, 0.0 of the curve (given the normal)
|
184
231
|
# and for each mean abscissa, :amp normal
|
185
232
|
def compute
|
@@ -188,20 +235,7 @@ class Ondulation < BezierBuilder
|
|
188
235
|
pieces = []
|
189
236
|
[abscissas.pairs, self.ampl.samples( self.freq )].forzip do |abspair, amplitude|
|
190
237
|
abs1, abs2 = abspair
|
191
|
-
|
192
|
-
p1, halfpoint, p2 = self.support.points( [abs1, mabs, abs2] )
|
193
|
-
# Trace("mabs #{mabs} abs1 #{abs1} abs2 #{abs2} halfpoint #{halfpoint.inspect} p1 #{p1.inspect} p2 #{p2.inspect}")
|
194
|
-
# Trace("normal #{@support.normal( mabs )}")
|
195
|
-
halfnormal = self.support.normal( mabs ).norm * ( sens * amplitude * (p2 - p1).length)
|
196
|
-
# Trace("halfnormal #{halfnormal.inspect}")
|
197
|
-
newpoint = halfpoint + halfnormal
|
198
|
-
tpoint = halfpoint + halfnormal * 3.0
|
199
|
-
t1 = (tpoint - p1 ) / 6.0
|
200
|
-
t2 = (tpoint - p2 ) / 6.0
|
201
|
-
# Trace("newpoint #{newpoint.inspect} p1 #{p1.inspect} (newpoint - p1) #{(newpoint - p1).inspect}")
|
202
|
-
halftangent = self.support.tangent( mabs ).norm * (newpoint - p1).length / 3.0
|
203
|
-
# halftangent = self.support.tangent( mabs ).norm * (p2 - p1).length / 3.0
|
204
|
-
pieces += [[:vector, p1, t1, newpoint, -halftangent], [:vector, newpoint, halftangent, p2, t2]]
|
238
|
+
pieces += self.compute_interpol( abs1, abs2, amplitude, sens )
|
205
239
|
sens *= -1.0
|
206
240
|
end
|
207
241
|
return pieces
|
data/lib/color.rb
CHANGED
@@ -3,10 +3,8 @@
|
|
3
3
|
# - +Palette+
|
4
4
|
# - +Gradient+
|
5
5
|
|
6
|
-
require 'geometry2D'; # for vector extension
|
7
|
-
require 'interpolation'
|
8
|
-
require 'attributable'
|
9
6
|
require 'utils'
|
7
|
+
require 'interpolation'
|
10
8
|
require 'shape'; # for gradient
|
11
9
|
|
12
10
|
module XRVG
|
@@ -130,7 +128,7 @@ class Color
|
|
130
128
|
|
131
129
|
# return a random color vector, with 1.0 opacity !!
|
132
130
|
# Color.rand => Color[0.2345, 0.987623, 0.4123, 1.0]
|
133
|
-
def Color.rand( opacity )
|
131
|
+
def Color.rand( opacity=1.0 )
|
134
132
|
return Color[Kernel::rand,Kernel::rand,Kernel::rand,opacity]
|
135
133
|
end
|
136
134
|
|
@@ -169,6 +167,12 @@ class Color
|
|
169
167
|
return Color[1.0, 1.0, 1.0, opacity]
|
170
168
|
end
|
171
169
|
|
170
|
+
# return a grey color vector
|
171
|
+
def Color.grey(light,opacity=1.0)
|
172
|
+
return Color[light, light, light, opacity]
|
173
|
+
end
|
174
|
+
|
175
|
+
|
172
176
|
# build a color vector from hsv parametrization (convert from hsv to rgb) h, s, v being between 0.0 and 1.0
|
173
177
|
#
|
174
178
|
# taken from wikipedia[http://en.wikipedia.org/wiki/HSV_color_space]
|
@@ -259,7 +263,10 @@ class Color
|
|
259
263
|
|
260
264
|
# get svg description of a color
|
261
265
|
def svg
|
262
|
-
values = self[0..2].map
|
266
|
+
values = self[0..2].map do |v|
|
267
|
+
v = Range.O.trim( v )
|
268
|
+
(255.0 * v).to_i
|
269
|
+
end
|
263
270
|
return "rgb(#{values.join(",")})"
|
264
271
|
end
|
265
272
|
|
@@ -275,7 +282,47 @@ end
|
|
275
282
|
# palette.color( 0.5 ) # => Color.orange
|
276
283
|
class Palette
|
277
284
|
include Attributable
|
278
|
-
attribute :colorlist
|
285
|
+
attribute :colorlist, nil, Array
|
286
|
+
attribute :interpoltype, :linear
|
287
|
+
|
288
|
+
include Samplable
|
289
|
+
include Interpolation
|
290
|
+
|
291
|
+
def initialize( *args )
|
292
|
+
super( *args )
|
293
|
+
build_interpolators
|
294
|
+
end
|
295
|
+
|
296
|
+
# build an interpolator by color componant
|
297
|
+
def build_interpolators()
|
298
|
+
vlists = [[],[],[],[]]
|
299
|
+
self.colorlist.foreach do |index, color|
|
300
|
+
vlists[0] += [index, color.r ]
|
301
|
+
vlists[1] += [index, color.g ]
|
302
|
+
vlists[2] += [index, color.b ]
|
303
|
+
vlists[3] += [index, color.a ]
|
304
|
+
end
|
305
|
+
@interpolators = vlists.map {|samplelist| Interpolator[ :samplelist, samplelist, :interpoltype, self.interpoltype]}
|
306
|
+
end
|
307
|
+
|
308
|
+
# interpolators accessor (for debugging)
|
309
|
+
def interpolators()
|
310
|
+
return @interpolators
|
311
|
+
end
|
312
|
+
|
313
|
+
# overloading to reset interpolators if interpoltype changes
|
314
|
+
def interpoltype=(value)
|
315
|
+
@interpoltype = value
|
316
|
+
if @interpolators
|
317
|
+
self.build_interpolators
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
# method overloading to delegate computation to componant interpolators
|
322
|
+
def interpolate( dindex )
|
323
|
+
vs = self.interpolators.map {|inter| inter.interpolate( dindex )}
|
324
|
+
return Color[ *vs ]
|
325
|
+
end
|
279
326
|
|
280
327
|
# compute color given float pourcentage.
|
281
328
|
# Palette[ :colorlist, [ 0.0, Color.black, 1.0, Color.white ] ].sample( 0.5 ) => Color[0.5,0.5,0.5,1.O]
|
@@ -295,14 +342,14 @@ class Palette
|
|
295
342
|
end
|
296
343
|
|
297
344
|
|
298
|
-
include Samplable
|
299
|
-
include Interpolation
|
300
345
|
|
301
346
|
def apply_sample( abs ) #:nodoc:
|
302
347
|
# Trace("Palette#apply_sample abs #{abs}")
|
303
348
|
return self.color( abs )
|
304
349
|
end
|
305
350
|
|
351
|
+
|
352
|
+
|
306
353
|
# alias apply_sample color
|
307
354
|
# alias apply_split ? => TODO
|
308
355
|
alias samplelist colorlist
|
data/lib/fitting.rb
CHANGED
@@ -145,13 +145,13 @@ class Fitting
|
|
145
145
|
maxerror = 0.0
|
146
146
|
container = V2D[]
|
147
147
|
[pointlist, parameters].forzip do |point, parameter|
|
148
|
-
Trace("point #{point.inspect} parameter #{parameter}")
|
148
|
+
# Trace("point #{point.inspect} parameter #{parameter}")
|
149
149
|
error = (point - bezier.point( parameter, container, :parameter )).r
|
150
150
|
if error > maxerror
|
151
151
|
maxerror = error
|
152
152
|
end
|
153
153
|
end
|
154
|
-
Trace("Fitting.error #{maxerror}")
|
154
|
+
# Trace("Fitting.error #{maxerror}")
|
155
155
|
return maxerror
|
156
156
|
end
|
157
157
|
|
data/lib/geometry2D.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# See :
|
4
4
|
# - +V2D+
|
5
5
|
|
6
|
-
require '
|
6
|
+
require 'attributable'
|
7
7
|
|
8
8
|
module XRVG
|
9
9
|
#
|
@@ -127,8 +127,8 @@ class V2D
|
|
127
127
|
# V2D[0.0,2.0].angle => 0.0
|
128
128
|
def angle
|
129
129
|
r = self.r()
|
130
|
-
if r == 0
|
131
|
-
return 0
|
130
|
+
if r == 0.0
|
131
|
+
return 0.0
|
132
132
|
else
|
133
133
|
unitary = self/r
|
134
134
|
cos, sin = unitary.x, unitary.y
|
@@ -176,6 +176,13 @@ class V2D
|
|
176
176
|
return self * 2.0 - other
|
177
177
|
end
|
178
178
|
|
179
|
+
# compute the symetric of point "self" considering (point,v) as symetry axis
|
180
|
+
def axesym( point, axev )
|
181
|
+
v = self - point
|
182
|
+
angle = V2D.angle( v, axev )
|
183
|
+
return point + v.rotate( -2.0 * angle )
|
184
|
+
end
|
185
|
+
|
179
186
|
# coords management between different coord systems (for the moment only euclidian and polar)
|
180
187
|
# V2D[0.0,1.0].coords => [0.0,1.0]
|
181
188
|
# V2D[0.0,1.0].coords(:polar) => [1.0,Math::PI/2.0]
|
data/lib/geovariety.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
# File for GeoVariety
|
2
|
+
# See (also):
|
3
|
+
# - InterBezier
|
4
|
+
# - Offsetvariety
|
5
|
+
# - FuseauVariety
|
6
|
+
|
7
|
+
require 'interbezier'
|
8
|
+
|
9
|
+
module XRVG
|
10
|
+
|
11
|
+
# = GeoVariety abstract module
|
12
|
+
# == Principle
|
13
|
+
# Base module to define geometrical spaces or canvas different from simple euclidean one to draw curves on.
|
14
|
+
# It provides three different services:
|
15
|
+
# - point computation
|
16
|
+
# - geodesic computation
|
17
|
+
# - arbitrary bezier computation, this one by computing sampling of euclidean curve on the variety, and then fitting point
|
18
|
+
# sequence with FitBezierBuilder
|
19
|
+
module GeoVariety
|
20
|
+
|
21
|
+
# must be overriden
|
22
|
+
def point( point )
|
23
|
+
raise NotImplementedError.new("#{self.class.name}#point is an abstract method.")
|
24
|
+
end
|
25
|
+
|
26
|
+
# must be overriden
|
27
|
+
def line( x1, x2, y )
|
28
|
+
raise NotImplementedError.new("#{self.class.name}#line is an abstract method.")
|
29
|
+
end
|
30
|
+
|
31
|
+
# see GeoVariety module description for algorithm
|
32
|
+
def bezier( pointrange, bezier )
|
33
|
+
bezier = bezier.similar( pointrange )
|
34
|
+
points = bezier.samples( 20 )
|
35
|
+
points = points.map {|point| self.point( point )}
|
36
|
+
return FitBezierBuilder[ :points, points ]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# = InterBezier GeoVariety implementation
|
41
|
+
# == Principle
|
42
|
+
# InterBezier defines a surface by the set of every possible curve sample from one interpolated curve to the other.
|
43
|
+
# Geodesic corresponds then to one interpolated result, and point to a point of this curve
|
44
|
+
class InterBezier
|
45
|
+
include GeoVariety
|
46
|
+
|
47
|
+
# Compute the geodesic curve by doing self.sample with y coord, and then compute point of this curve with length "x"
|
48
|
+
def point( point )
|
49
|
+
curve = self.sample( point.y )
|
50
|
+
return curve.point( point.x )
|
51
|
+
end
|
52
|
+
|
53
|
+
# Compute the geodesic subcurve with y coord between x1 and x2
|
54
|
+
def line( x1, x2, y )
|
55
|
+
# Trace("interbezier line x1 #{x1} x2 #{x2} y #{y}")
|
56
|
+
curve = self.sample( y )
|
57
|
+
result = curve.apply_split( x1, x2 )
|
58
|
+
# Trace("interbezier line result #{result.inspect}")
|
59
|
+
return result
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
# = OffsetVariety implementation
|
65
|
+
# == Principle
|
66
|
+
# Geovariety is defined by the set of offset curves from -ampl to +ampl
|
67
|
+
# == Extension
|
68
|
+
# Parameter could be a :samplable parameter : in that case, ampl will vary
|
69
|
+
#
|
70
|
+
# Another extension would be to parametrize range straightforwardly
|
71
|
+
#
|
72
|
+
# Finally, the two previous remarks must be synthetized :-)
|
73
|
+
class OffsetVariety
|
74
|
+
include Attributable
|
75
|
+
attribute :support
|
76
|
+
attribute :ampl, nil, Float
|
77
|
+
|
78
|
+
include GeoVariety
|
79
|
+
|
80
|
+
# builder: init static offset range with (-self.ampl..self.ampl)
|
81
|
+
def initialize( *args )
|
82
|
+
super( *args )
|
83
|
+
@range = (-self.ampl..self.ampl)
|
84
|
+
end
|
85
|
+
|
86
|
+
# point computed by computing offset curve with ampl y coord mapped onto offset range, and then sampling the curve with x coord
|
87
|
+
def point( point )
|
88
|
+
curve = Offset[ :support, @support, :ampl, @range.sample( point.y ) ]
|
89
|
+
return curve.point( point.x )
|
90
|
+
end
|
91
|
+
|
92
|
+
# subgeodesic computed by computing offset curve with ampl y coord
|
93
|
+
def line( x1, x2, y )
|
94
|
+
curve = Offset[ :support, @support, :ampl, @range.sample( y ) ]
|
95
|
+
return curve.apply_split( x1, x2 )
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
# = FuseauVariety implementation
|
101
|
+
# == Principle
|
102
|
+
# Same as OffsetVariety, with Fuseau shape, that is with linearly varying ampl range
|
103
|
+
class FuseauVariety
|
104
|
+
include Attributable
|
105
|
+
attribute :support
|
106
|
+
attribute :ampl, nil, Float
|
107
|
+
|
108
|
+
include GeoVariety
|
109
|
+
|
110
|
+
def initialize( *args )
|
111
|
+
super( *args )
|
112
|
+
@range = (-self.ampl..self.ampl)
|
113
|
+
end
|
114
|
+
|
115
|
+
def point( point )
|
116
|
+
curve = Offset[ :support, @support, :ampl, (0.0..@range.sample( point.y ))]
|
117
|
+
return curve.point( point.x )
|
118
|
+
end
|
119
|
+
|
120
|
+
def line( x1, x2, y )
|
121
|
+
curve = Offset[ :support, @support, :ampl, (0.0..@range.sample( y ))]
|
122
|
+
return curve.apply_split( x1, x2 )
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end # XRVG
|
127
|
+
|
128
|
+
# see geovariety_test to see tests
|
data/lib/interbezier.rb
CHANGED
@@ -24,12 +24,12 @@ class InterBezier
|
|
24
24
|
alllengths = []
|
25
25
|
beziers.each do |bezier|
|
26
26
|
lengths = bezier.piecelengths
|
27
|
-
|
27
|
+
Trace("bezier lengths #{lengths.inspect}")
|
28
28
|
lengthH[ bezier ] = lengths
|
29
29
|
alllengths += lengths
|
30
30
|
end
|
31
31
|
alllengths = Float.sort_float_list( alllengths )
|
32
|
-
|
32
|
+
Trace("alllengths #{alllengths.inspect}")
|
33
33
|
|
34
34
|
newbezierlist = []
|
35
35
|
beziers.each do |bezier|
|
@@ -42,10 +42,10 @@ class InterBezier
|
|
42
42
|
newbezierlist << newbezier
|
43
43
|
end
|
44
44
|
|
45
|
-
|
45
|
+
Trace("newbezierlist #{newbezierlist.length}")
|
46
46
|
beziers = newbezierlist
|
47
47
|
bezierpointlists = beziers.map {|bezier| bezier.pointlist(:vector) }
|
48
|
-
|
48
|
+
Trace("bezierpointlists #{bezierpointlists.map {|list| list.length}.inspect}")
|
49
49
|
pointsequencelist = bezierpointlists.forzip
|
50
50
|
@interpolatorlist = []
|
51
51
|
pointsequencelist.foreach(beziers.size) do |pointsequence|
|
data/lib/interpolation.rb
CHANGED
@@ -3,11 +3,9 @@
|
|
3
3
|
# See
|
4
4
|
# - +Interpolation+
|
5
5
|
# - +Interpolator+
|
6
|
-
# - +
|
6
|
+
# - +InterpolatorBinaryTree+
|
7
7
|
|
8
8
|
require 'utils'
|
9
|
-
require 'attributable'
|
10
|
-
require 'samplation'
|
11
9
|
|
12
10
|
module XRVG
|
13
11
|
# Interpolation module
|
@@ -29,12 +27,26 @@ module Interpolation
|
|
29
27
|
raise NotImplementedError.new("#{self.class.name}#samplelist is an abstract method.")
|
30
28
|
end
|
31
29
|
|
30
|
+
# must be the overloaded method to adapt Interpolation
|
31
|
+
#
|
32
|
+
# is usually provided by a side-effect of a :attribute declaration in including class
|
33
|
+
def interpoltype()
|
34
|
+
return :linear
|
35
|
+
end
|
36
|
+
|
37
|
+
# overall computation method
|
38
|
+
#
|
39
|
+
# from an input between 0.0 and 1.0, returns an interpolated value computed by interpolation method deduced from interpoltype
|
40
|
+
def interpolate( dindex )
|
41
|
+
return method( self.interpoltype ).call( dindex )
|
42
|
+
end
|
43
|
+
|
32
44
|
# computing method
|
33
45
|
#
|
34
46
|
# from an input between 0.0 and 1.0, returns linear interpolated value
|
35
47
|
#
|
36
48
|
# interpolate uses + and * scalar operators on interpolation values
|
37
|
-
def
|
49
|
+
def linear( dindex )
|
38
50
|
result = nil
|
39
51
|
pindex, pvalue = self.samplelist[0..1]
|
40
52
|
self.samplelist.foreach do |index, value|
|
@@ -43,7 +55,7 @@ module Interpolation
|
|
43
55
|
return value
|
44
56
|
end
|
45
57
|
result = pvalue + ((value + (pvalue * (-1.0)) ) * ((dindex - pindex) / (index - pindex )))
|
46
|
-
Trace("pindex #{pindex} pvalue #{pvalue.inspect} index #{index} value #{value.inspect} dindex #{dindex} result #{result.inspect}")
|
58
|
+
# Trace("pindex #{pindex} pvalue #{pvalue.inspect} index #{index} value #{value.inspect} dindex #{dindex} result #{result.inspect}")
|
47
59
|
break
|
48
60
|
end
|
49
61
|
pvalue, pindex = value, index
|
@@ -61,12 +73,13 @@ end
|
|
61
73
|
class Interpolator
|
62
74
|
include Attributable
|
63
75
|
attribute :samplelist
|
76
|
+
attribute :interpoltype, :linear
|
64
77
|
include Interpolation
|
65
78
|
include Samplable
|
66
79
|
alias apply_sample interpolate
|
67
80
|
end
|
68
81
|
|
69
|
-
class
|
82
|
+
class BinaryTreeRange
|
70
83
|
|
71
84
|
def initialize( limit, quadleft, quadright, range=nil )
|
72
85
|
@limit = limit
|
@@ -88,13 +101,13 @@ class QuadRange
|
|
88
101
|
end
|
89
102
|
end
|
90
103
|
|
91
|
-
#
|
104
|
+
# BinaryTree class
|
92
105
|
# = Intro
|
93
106
|
# Optim class to look for predefine ranges for a value. Is actually a binary tree data structure, but used as unlinear space partitioner.
|
94
107
|
# = Example
|
95
|
-
# quad =
|
108
|
+
# quad = BinaryTree.new( [0.0,1.0, 0.2,0.0, 0.6,1.0, 0.8,0.0, 1.0,1.0] )
|
96
109
|
# quad.range( 0.5 ); #=> [0.2,0.0,0.6,1.0]
|
97
|
-
class
|
110
|
+
class BinaryTree
|
98
111
|
|
99
112
|
def initialize( samplelist ) #:nodoc:
|
100
113
|
quads = []
|
@@ -102,7 +115,7 @@ class QuadTree
|
|
102
115
|
samplelist.foreach(2).pairs do |ppair, pair|
|
103
116
|
pindex, pvalue = ppair
|
104
117
|
index, value = pair
|
105
|
-
quads <<
|
118
|
+
quads << BinaryTreeRange.new( nil, nil, nil, [pindex, pvalue, index, value] )
|
106
119
|
ends << index
|
107
120
|
end
|
108
121
|
@root = build_quads( quads, ends )
|
@@ -113,7 +126,7 @@ class QuadTree
|
|
113
126
|
newends = []
|
114
127
|
index = 0
|
115
128
|
quads.foreach do |quad1, quad2|
|
116
|
-
newquads <<
|
129
|
+
newquads << BinaryTreeRange.new( ends[2*index], quad1, quad2, nil)
|
117
130
|
newends << ends[2*index + 1]
|
118
131
|
index += 1
|
119
132
|
end
|
@@ -125,24 +138,24 @@ class QuadTree
|
|
125
138
|
end
|
126
139
|
|
127
140
|
# utilitary method to retrieve range of index
|
128
|
-
#
|
141
|
+
# BinaryTree.new( [0.0,1.0, 0.2,0.0, 0.6,1.0, 0.8,0.0, 1.0,1.0] ).range( 0.5 ); #=> [0.2,0.0,0.6,1.0]
|
129
142
|
def range( index )
|
130
143
|
return @root.range( index )
|
131
144
|
end
|
132
145
|
end
|
133
146
|
|
134
|
-
#
|
147
|
+
# Binary tree interpolator
|
135
148
|
#
|
136
|
-
# Use
|
149
|
+
# Use BinaryTree to retrieve range of values between linear interpolation.
|
137
150
|
#
|
138
151
|
# Used in BezierSpline to compute parameter from length.
|
139
|
-
class
|
152
|
+
class InterpolatorBinaryTree < Interpolator
|
140
153
|
|
141
154
|
def compute_quad #:nodoc:
|
142
|
-
@quad =
|
155
|
+
@quad = BinaryTree.new( self.samplelist )
|
143
156
|
end
|
144
157
|
|
145
|
-
# - first use
|
158
|
+
# - first use BinaryTree range to retrieve range of dindex,
|
146
159
|
# - then linearly interpolate
|
147
160
|
def interpolate( dindex )
|
148
161
|
if not @quad
|
data/lib/parametriclength.rb
CHANGED
@@ -13,6 +13,7 @@ module ParametricLength
|
|
13
13
|
raise NotImplementedError.new("#{self.class.name}#parameter_range is an abstract method.")
|
14
14
|
end
|
15
15
|
|
16
|
+
# abstract method to compute point from parameter
|
16
17
|
def pointfromparameter( parameter, container )
|
17
18
|
raise NotImplementedError.new("#{self.class.name}#pointfromparameter is an abstract method.")
|
18
19
|
end
|
@@ -56,8 +57,8 @@ module ParametricLength
|
|
56
57
|
end
|
57
58
|
samplelist = newsamplelist
|
58
59
|
end
|
59
|
-
@abs_interpolator =
|
60
|
-
return
|
60
|
+
@abs_interpolator = InterpolatorBinaryTree.new( :samplelist, invsamplelist )
|
61
|
+
return InterpolatorBinaryTree.new( :samplelist, samplelist )
|
61
62
|
end
|
62
63
|
|
63
64
|
def length_interpolator() #:nodoc:
|
data/lib/render.rb
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
# - +SVGRender+ for effective SVG render
|
5
5
|
|
6
6
|
require 'color'
|
7
|
-
require 'attributable'
|
8
7
|
require 'style'
|
9
8
|
|
10
9
|
module XRVG
|
@@ -34,7 +33,7 @@ end
|
|
34
33
|
class SVGRender < Render
|
35
34
|
attribute :filename, "", String
|
36
35
|
attribute :imagesize, "2cm", String
|
37
|
-
attribute :background,
|
36
|
+
attribute :background, "white", [Color, String]
|
38
37
|
attr_reader :viewbox
|
39
38
|
|
40
39
|
# SVGRender builder
|