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