xrvg 0.0.6 → 0.0.7
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 +12 -1
- data/Rakefile +30 -8
- data/lib/samplation.rb +10 -2
- data/lib/trace.rb +1 -0
- data/lib/utils.rb +24 -1
- data/test/test_color.rb +19 -13
- data/test/test_utils.rb +10 -0
- metadata +2 -17
- data/lib/bezier.rb +0 -536
- data/lib/bezierbuilders.rb +0 -210
- data/lib/beziermotifs.rb +0 -121
- data/lib/bezierspline.rb +0 -235
- data/lib/beziertools.rb +0 -245
- data/lib/color.rb +0 -401
- data/lib/fitting.rb +0 -203
- data/lib/frame.rb +0 -33
- data/lib/geovariety.rb +0 -128
- data/lib/interbezier.rb +0 -87
- data/lib/render.rb +0 -266
- data/lib/shape.rb +0 -421
- data/lib/spiral.rb +0 -72
- data/lib/style.rb +0 -76
- data/lib/xrvg.rb +0 -46
data/lib/bezier.rb
DELETED
@@ -1,536 +0,0 @@
|
|
1
|
-
# +Bezier+ source
|
2
|
-
#
|
3
|
-
|
4
|
-
require 'bezierspline'
|
5
|
-
require 'shape'
|
6
|
-
|
7
|
-
module XRVG
|
8
|
-
# = Base class for cubic bezier curves
|
9
|
-
# == Basics
|
10
|
-
# See http://en.wikipedia.org/wiki/B%C3%A9zier_curve
|
11
|
-
# == Examples
|
12
|
-
# Basically, a Bezier curve is a multi-pieces cubic bezier curve. As a first example, you can create bezier curves as follows :
|
13
|
-
# b = Bezier[ :pieces, [[:raw, p1, pc1, pc2, p2]] ]; # raw description, as SVG
|
14
|
-
# b = Bezier[ :pieces, [[:vector, p1, v1, p2, v2]] ]; # more "symetrical" description.
|
15
|
-
# For more extensive description, see http://xrvg.rubyforge.org/XRVGBezierCurve.html
|
16
|
-
# == Discussion
|
17
|
-
# In XRVG, bezier curves must be also viewed as a way to create smooth and non linear interpolation between values (see +Interpolation+)
|
18
|
-
#
|
19
|
-
# Other point : to run along a bezier curve, you can use two different parametrization :
|
20
|
-
# - the curve generic one, that is "curviligne" abscissa, that is length
|
21
|
-
# - the bezier parameter, as bezier curves are parametrized curves. For multi-pieces curve, by extension, parameter goes from one integer value to the next one
|
22
|
-
# As Bezier class provides several methods with a parameter input, it is necessary to specify with parameter type you want to use ! For example,
|
23
|
-
# to compute a point from a bezier curve, Bezier class defines the point method as follows :
|
24
|
-
# def point( t, parametertype=:length )
|
25
|
-
# This is a general declaration : every method with a parameter input will propose such a kind of interface :
|
26
|
-
# - t as Float parameter value
|
27
|
-
# - parametertype, by default :length, that can have two values, :length or :parameter. :parameter is kept because is far faster than other indexation.
|
28
|
-
# == Attributes
|
29
|
-
# attribute :pieces
|
30
|
-
class Bezier < Curve
|
31
|
-
attribute :pieces
|
32
|
-
|
33
|
-
# -------------------------------------------------------------
|
34
|
-
# builders
|
35
|
-
# -------------------------------------------------------------
|
36
|
-
|
37
|
-
# Initialize with the Attributable format
|
38
|
-
#
|
39
|
-
#
|
40
|
-
# Licit formats :
|
41
|
-
# b = Bezier.new( :pieces, [BezierSpline[:raw, p1, pc1, pc2, p2]] )
|
42
|
-
# b = Bezier[ :pieces, [BezierSpline[:vector, p1, v1, p2, v2]] ]
|
43
|
-
# However, prefer the use of the following builders
|
44
|
-
# b = Bezier.vector( p1, v1, p2, v2 )
|
45
|
-
# b = Bezier.raw( p1, pc1, pc2, p2 )
|
46
|
-
# b = Bezier.single( :raw, p1, pc1, pc2, p2 )
|
47
|
-
# b = Bezier.multi( [[:raw, p1, pc1, pc2, p2], [:raw, p1, pc1, pc2, p2]] )
|
48
|
-
# The two last syntaxes are provided as shortcuts, as used quite frequently, and must be used instead of :pieces attributable builder
|
49
|
-
def Bezier.[]( *args )
|
50
|
-
self.new( *args )
|
51
|
-
end
|
52
|
-
|
53
|
-
# Uni Bezier builder
|
54
|
-
#
|
55
|
-
# type can be :raw or :vector
|
56
|
-
def Bezier.single( type, p1, p2, p3, p4 )
|
57
|
-
return Bezier.new( :pieces, [BezierSpline[type, p1, p2, p3, p4]] )
|
58
|
-
end
|
59
|
-
|
60
|
-
# Uni Bezier builder in :raw format
|
61
|
-
def Bezier.raw( p1, pc1, pc2, p2 )
|
62
|
-
return Bezier.single( :raw, p1, pc1, pc2, p2 )
|
63
|
-
end
|
64
|
-
|
65
|
-
# Uni Bezier builder in :vector format
|
66
|
-
def Bezier.vector( p1, v1, p2, v2 )
|
67
|
-
return Bezier.single( :vector, p1, v1, p2, v2 )
|
68
|
-
end
|
69
|
-
|
70
|
-
# Basic Multi Bezier builder
|
71
|
-
#
|
72
|
-
# raw pieces must be an array of arrays of the form [type, p1, p2, p3, p4] as defined for single
|
73
|
-
def Bezier.multi( rawpieces )
|
74
|
-
return Bezier.new( :pieces, rawpieces.map {|piece| BezierSpline[*piece]} )
|
75
|
-
end
|
76
|
-
|
77
|
-
# "regular" Multi Bezier :raw specification
|
78
|
-
#
|
79
|
-
# args is a list of points and control points as [p1, pc1, p2, pc2, p3, pc3]
|
80
|
-
#
|
81
|
-
# Beware that
|
82
|
-
# Bezier.raw( p1, pc1, pc2, p2 ) == Bezier.raws( p1, pc1, p2, p2 + (p2-pc2))
|
83
|
-
def Bezier.raws( *args )
|
84
|
-
rawpieces = []
|
85
|
-
args.foreach(2).pairs do |pair1, pair2|
|
86
|
-
p1, pc1 = pair1
|
87
|
-
p2, pc2 = pair2
|
88
|
-
rawpieces << [:raw, p1, pc1, p2+(p2-pc2), p2]
|
89
|
-
end
|
90
|
-
return Bezier.multi( rawpieces )
|
91
|
-
end
|
92
|
-
|
93
|
-
# "regular" Multi Bezier :vector specification
|
94
|
-
#
|
95
|
-
# args is a list of points and control points as [p1, v1, p2, v2, p3, v3]
|
96
|
-
#
|
97
|
-
# Beware that
|
98
|
-
# Bezier.vector( p1, v1, p2, v2 ) == Bezier.vectors( p1, v1, p2, -v2)
|
99
|
-
def Bezier.vectors( *args )
|
100
|
-
rawpieces = []
|
101
|
-
args.foreach(2).pairs do |pair1, pair2|
|
102
|
-
p1, v1 = pair1
|
103
|
-
p2, v2 = pair2
|
104
|
-
rawpieces << [:vector, p1, v1, p2, -v2]
|
105
|
-
end
|
106
|
-
return Bezier.multi( rawpieces )
|
107
|
-
end
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
# bezier point, as
|
113
|
-
# Bezier[:raw, V2D::O, V2D::O, V2D::O, V2D::O]
|
114
|
-
O = Bezier.raw( V2D::O, V2D::O, V2D::O, V2D::O )
|
115
|
-
|
116
|
-
|
117
|
-
# return piece of index "index",as BezierSpline object
|
118
|
-
#
|
119
|
-
# index can be
|
120
|
-
# - integer : in that case, simple return @pieces[index]
|
121
|
-
# - float : in that case, use second default argument
|
122
|
-
# this method must actually be very rarely called, as usually
|
123
|
-
# we want to compute something with index, and in that case we
|
124
|
-
# want to delegate computation to a BezierSpline, with parameter
|
125
|
-
# mapping parametermapping
|
126
|
-
def piece( index, parametertype=:length )
|
127
|
-
pieceindex = index
|
128
|
-
if index.is_a? Float
|
129
|
-
pieceindex, t = self.parametermapping( index, parametertype )
|
130
|
-
end
|
131
|
-
return @pieces[ pieceindex ]
|
132
|
-
end
|
133
|
-
|
134
|
-
# return number of pieces
|
135
|
-
def piecenumber
|
136
|
-
return @pieces.length
|
137
|
-
end
|
138
|
-
|
139
|
-
# -------------------------------------------------------------
|
140
|
-
# curve interface
|
141
|
-
# -------------------------------------------------------------
|
142
|
-
|
143
|
-
# overload Curve::viewbox
|
144
|
-
def viewbox
|
145
|
-
return V2D.viewbox( self.pointlist() )
|
146
|
-
end
|
147
|
-
|
148
|
-
|
149
|
-
# -------------------------------------------------------------
|
150
|
-
# piece shortcuts
|
151
|
-
# -------------------------------------------------------------
|
152
|
-
|
153
|
-
# generic method to return points list of a curve
|
154
|
-
# b = Bezier[ :pieces, [[:raw, p1, pc1, pc2, p2], [:raw, p2, pc2b, pc3, p3]] ]
|
155
|
-
# b.pointlist #=> equiv to b.pointlist(:raw)
|
156
|
-
# b.pointlist(:raw) #=> [p1, pc1, pc2, p2, p2, pc2b, pc3, p3]
|
157
|
-
# if you want to get a particular piece pointlist, do
|
158
|
-
# b.piece( t ).pointlist(nil|:raw|:vector)
|
159
|
-
# TODO : result must be cached by type
|
160
|
-
def pointlist( type=:raw )
|
161
|
-
result = []
|
162
|
-
@pieces.each {|piece| result = result + piece.pointlist(type)}
|
163
|
-
# Trace("Bezier.pointlist result #{result.inspect}")
|
164
|
-
return result
|
165
|
-
end
|
166
|
-
|
167
|
-
# shortcut method to get curve first point
|
168
|
-
def firstpoint
|
169
|
-
return self.pointlist()[0]
|
170
|
-
end
|
171
|
-
|
172
|
-
# shortcut method to get curve last point
|
173
|
-
def lastpoint
|
174
|
-
return self.pointlist()[-1]
|
175
|
-
end
|
176
|
-
|
177
|
-
# shortcut method to build Bezier objects for each piece
|
178
|
-
def beziers
|
179
|
-
return self.pieces.map{ |piece| Bezier.single( *piece.data ) }
|
180
|
-
end
|
181
|
-
|
182
|
-
# shortcut method to retrieve a piece as an Bezier object
|
183
|
-
def bezier( index )
|
184
|
-
return Bezier.single( *self.piece( index ).data )
|
185
|
-
end
|
186
|
-
|
187
|
-
# shortcut method to retrieve data list of a bezier
|
188
|
-
def data
|
189
|
-
return self.pieces.map{ |piece| piece.data }
|
190
|
-
end
|
191
|
-
|
192
|
-
|
193
|
-
# -------------------------------------------------------------
|
194
|
-
# piece delegation computation
|
195
|
-
# -------------------------------------------------------------
|
196
|
-
|
197
|
-
# with index (must be Float) and parametertype as inputs, must compute :
|
198
|
-
# - the index of the piece on which the computation must take place
|
199
|
-
# - the new parameter value corresponding to bezier computation input
|
200
|
-
def parametermapping( index, parametertype=:length, side=:right ) #:nodoc:
|
201
|
-
check_parametertype( parametertype )
|
202
|
-
result = []
|
203
|
-
if parametertype == :length
|
204
|
-
index = (0.0..1.0).trim( index )
|
205
|
-
result = length_parameter_mapping( index, side )
|
206
|
-
else # no need to test parametertype value, as check_parametertype already do it
|
207
|
-
index = (0.0..self.piecenumber.to_f).trim( index )
|
208
|
-
pieceindex = index < self.piecenumber ? index.to_i : (index-1).to_i
|
209
|
-
t = index - pieceindex
|
210
|
-
result = [pieceindex, t]
|
211
|
-
end
|
212
|
-
|
213
|
-
return result
|
214
|
-
end
|
215
|
-
|
216
|
-
# utilitary method to factorize abscissa parameter type value checking
|
217
|
-
def check_parametertype( parametertype ) #:nodoc:
|
218
|
-
if !(parametertype == :parameter or parametertype == :length )
|
219
|
-
Kernel::raise("Invalid parametertype value #{parametertype}")
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
# -------------------------------------------------------------
|
224
|
-
# bezier computations
|
225
|
-
# -------------------------------------------------------------
|
226
|
-
|
227
|
-
# compute a point at curviligne abscissa or parameter t
|
228
|
-
#
|
229
|
-
# curve method redefinition
|
230
|
-
def point( t, container=nil, parametertype=:length )
|
231
|
-
pieceindex, t = parametermapping( t, parametertype )
|
232
|
-
return self.piece( pieceindex ).point( t, container )
|
233
|
-
end
|
234
|
-
|
235
|
-
# compute tangent at curviligne abscissa or parameter t
|
236
|
-
#
|
237
|
-
# curve method redefinition
|
238
|
-
def tangent ( t, container=nil, parametertype=:length )
|
239
|
-
pieceindex, t = parametermapping( t, parametertype )
|
240
|
-
return self.piece( pieceindex ).tangent( t, container )
|
241
|
-
end
|
242
|
-
|
243
|
-
# compute acceleration at curviligne abscissa or parameter t
|
244
|
-
#
|
245
|
-
# curve method redefinition
|
246
|
-
def acc( t, container=nil, parametertype=:length )
|
247
|
-
pieceindex, t = parametermapping( t, parametertype )
|
248
|
-
return self.piece( pieceindex ).acc( t, container )
|
249
|
-
end
|
250
|
-
|
251
|
-
# curve method redefinition to factorize parametermapping
|
252
|
-
def frame( t, container=nil, parametertype=:length )
|
253
|
-
pieceindex, t = parametermapping( t, parametertype )
|
254
|
-
containerpoint = container ? container.center : nil
|
255
|
-
containertangent = container ? container.vector : nil
|
256
|
-
point = self.piece( pieceindex ).point( t, containerpoint )
|
257
|
-
tangent = self.piece( pieceindex ).tangent( t, containertangent )
|
258
|
-
rotation = self.rotation( nil, tangent )
|
259
|
-
scale = self.scale( nil, tangent )
|
260
|
-
result = container ? container : Frame[ :center, point, :vector, tangent, :rotation, rotation, :scale, scale ]
|
261
|
-
return result
|
262
|
-
end
|
263
|
-
|
264
|
-
# -------------------------------------------------------------
|
265
|
-
# subpiece computation
|
266
|
-
# -------------------------------------------------------------
|
267
|
-
|
268
|
-
# generalize Bezier method
|
269
|
-
def subpieces (t1, t2) #:nodoc:
|
270
|
-
# Trace("subpieces t1 #{t1} t2 #{t2}")
|
271
|
-
pieceindex1, t1 = parametermapping( t1, :length, :left )
|
272
|
-
pieceindex2, t2 = parametermapping( t2, :length, :right )
|
273
|
-
# Trace("after translation pieceindex1 #{pieceindex1} t1 #{t1} pieceindex2 #{pieceindex2} t2 #{t2}")
|
274
|
-
result = []
|
275
|
-
|
276
|
-
if pieceindex1 == pieceindex2
|
277
|
-
result = [self.piece( pieceindex1 ).subpiece( t1, t2 )]
|
278
|
-
else
|
279
|
-
result << self.piece( pieceindex1 ).subpiece( t1, 1.0 )
|
280
|
-
if pieceindex1 + 1 != pieceindex2
|
281
|
-
result += self.pieces[pieceindex1+1..pieceindex2-1]
|
282
|
-
end
|
283
|
-
result << self.piece( pieceindex2 ).subpiece( 0.0, t2 )
|
284
|
-
end
|
285
|
-
return result
|
286
|
-
end
|
287
|
-
|
288
|
-
# compute the sub curve between abscissa t1 and t2
|
289
|
-
#
|
290
|
-
# may result in a multi-pieces Bezier
|
291
|
-
#
|
292
|
-
# Note: special modulo effect to deal with closed bezier curve
|
293
|
-
#
|
294
|
-
# TODO: improve code (bas design)
|
295
|
-
def subbezier( t1, t2)
|
296
|
-
# return Bezier.new( :pieces, self.subpieces( t1, t2 ) )
|
297
|
-
ranges = (0.0..1.0).modulos( (t1..t2) )
|
298
|
-
# Trace("Bezier::subbezier t1 #{t1} t2 #{t2} ranges #{ranges.inspect}")
|
299
|
-
pieces = []
|
300
|
-
ranges.each do |range|
|
301
|
-
range = range.sort
|
302
|
-
pieces += self.subpieces( range.begin, range.end )
|
303
|
-
end
|
304
|
-
|
305
|
-
bezier = Bezier.new( :pieces, pieces )
|
306
|
-
if t1 > t2
|
307
|
-
bezier = bezier.reverse
|
308
|
-
end
|
309
|
-
return bezier
|
310
|
-
end
|
311
|
-
|
312
|
-
# -------------------------------------------------------------
|
313
|
-
# reverse
|
314
|
-
# -------------------------------------------------------------
|
315
|
-
|
316
|
-
# return a new Bezier curve reversed from current one
|
317
|
-
#
|
318
|
-
# simply reverse BezierSpline pieces, both internally and in the :pieces list
|
319
|
-
def reverse
|
320
|
-
newpieces = @pieces.map {|piece| piece.reverse()}
|
321
|
-
return Bezier.new( :pieces, newpieces.reverse )
|
322
|
-
end
|
323
|
-
|
324
|
-
# -------------------------------------------------------------
|
325
|
-
# translation
|
326
|
-
# -------------------------------------------------------------
|
327
|
-
|
328
|
-
# translate the Bezier curve, by translating its points
|
329
|
-
def translate( v )
|
330
|
-
return Bezier.new( :pieces, @pieces.map { |piece| piece.translate( v ) } )
|
331
|
-
end
|
332
|
-
|
333
|
-
# rotate the Bezier curve, by rotating its points
|
334
|
-
def rotate( angle, center=V2D::O )
|
335
|
-
return Bezier.new( :pieces, @pieces.map { |piece| piece.rotate( angle, center ) } )
|
336
|
-
end
|
337
|
-
|
338
|
-
# central symetry
|
339
|
-
def sym( center )
|
340
|
-
return Bezier.new( :pieces, @pieces.map { |piece| piece.sym( center ) } )
|
341
|
-
end
|
342
|
-
|
343
|
-
# axis symetry
|
344
|
-
def axesym( point, v )
|
345
|
-
return Bezier.new( :pieces, @pieces.map { |piece| piece.axesym( point, v ) } )
|
346
|
-
end
|
347
|
-
|
348
|
-
# -------------------------------------------------------------
|
349
|
-
# similar (transform is used for samplation)
|
350
|
-
# see XRVG#33
|
351
|
-
# -------------------------------------------------------------
|
352
|
-
|
353
|
-
# "Similitude" geometric transformation
|
354
|
-
#
|
355
|
-
# See http://en.wikipedia.org/wiki/Similitude_%28geometry%29
|
356
|
-
#
|
357
|
-
# Similtude geometric transformation is (firspoint..lastpoint) -> pointrange
|
358
|
-
#
|
359
|
-
# TODO : method must be put in Curve interface
|
360
|
-
def similar( pointrange )
|
361
|
-
oldRepere = [self.firstpoint, self.lastpoint - self.firstpoint]
|
362
|
-
newRepere = [pointrange.begin, pointrange.end - pointrange.begin]
|
363
|
-
rotation = V2D.angle( newRepere[1], oldRepere[1] )
|
364
|
-
if oldRepere[1].r == 0.0
|
365
|
-
Kernel::raise("similar error : bezier is length 0")
|
366
|
-
end
|
367
|
-
scale = newRepere[1].r / oldRepere[1].r
|
368
|
-
newpoints = []
|
369
|
-
self.pointlist.each do |oldpoint|
|
370
|
-
oldvector = oldpoint - oldRepere[0]
|
371
|
-
newvector = oldvector.rotate( rotation ) * scale
|
372
|
-
newpoints.push( newRepere[0] + newvector )
|
373
|
-
end
|
374
|
-
splines = []
|
375
|
-
newpoints.foreach do |p1, p2, p3, p4|
|
376
|
-
splines.push( BezierSpline[:raw, p1, p2, p3, p4] )
|
377
|
-
end
|
378
|
-
return Bezier[ :pieces, splines ]
|
379
|
-
end
|
380
|
-
|
381
|
-
# -------------------------------------------------------------
|
382
|
-
# concatenation
|
383
|
-
# -------------------------------------------------------------
|
384
|
-
|
385
|
-
# Bezier curve concatenation
|
386
|
-
def +( other )
|
387
|
-
return Bezier.new( :pieces, self.pieces + other.pieces )
|
388
|
-
end
|
389
|
-
|
390
|
-
# -------------------------------------------------------------
|
391
|
-
# svg
|
392
|
-
# -------------------------------------------------------------
|
393
|
-
|
394
|
-
# return the svg description of the curve
|
395
|
-
#
|
396
|
-
# if firstpoint == lastpoint, curve is considered as closed
|
397
|
-
def svg()
|
398
|
-
# Trace("Bezier::svg #{self.inspect}")
|
399
|
-
path = ""
|
400
|
-
previous = nil
|
401
|
-
self.pieces().each do |piece|
|
402
|
-
p1, pc1, pc2, p2 = piece.pointlist
|
403
|
-
# Trace("previous #{previous.inspect} p1 #{p1.inspect}")
|
404
|
-
if previous == nil or not (previous - p1).r <= 0.0000001
|
405
|
-
# Trace("svg bezier not equal => M")
|
406
|
-
path += "M #{p1.x},#{p1.y}"
|
407
|
-
end
|
408
|
-
previous = p2
|
409
|
-
path += "C #{pc1.x},#{pc1.y} #{pc2.x},#{pc2.y} #{p2.x},#{p2.y}"
|
410
|
-
end
|
411
|
-
|
412
|
-
if self.firstpoint == self.lastpoint
|
413
|
-
path += " z"
|
414
|
-
end
|
415
|
-
|
416
|
-
result = "<path d=\"#{path}\"/>"
|
417
|
-
return result
|
418
|
-
end
|
419
|
-
|
420
|
-
# -------------------------------------------------------------
|
421
|
-
# gdebug
|
422
|
-
# -------------------------------------------------------------
|
423
|
-
|
424
|
-
# Display Bezier curve decorated with points and control points
|
425
|
-
def gdebug(render)
|
426
|
-
self.pieces.each {|piece| piece.gdebug(render)}
|
427
|
-
end
|
428
|
-
|
429
|
-
|
430
|
-
# -------------------------------------------------------------
|
431
|
-
# length computation
|
432
|
-
# -------------------------------------------------------------
|
433
|
-
|
434
|
-
# return the length of the bezier curve
|
435
|
-
#
|
436
|
-
# simply add pieces lengths
|
437
|
-
def length
|
438
|
-
if not @length
|
439
|
-
@length = compute_length
|
440
|
-
end
|
441
|
-
return @length
|
442
|
-
end
|
443
|
-
|
444
|
-
# Note : lengthranges building should be more functional ...
|
445
|
-
# must use an interpolator ?
|
446
|
-
def compute_length #:nodoc:
|
447
|
-
lengths = self.pieces.map {|piece| piece.length}
|
448
|
-
# Trace("pieces #{self.pieces.inspect} lenghts #{lengths.inspect}")
|
449
|
-
result = lengths.sum
|
450
|
-
if result == 0.0
|
451
|
-
lengths = [1.0]
|
452
|
-
else
|
453
|
-
psum = 0.0
|
454
|
-
lengths = lengths.map {|v| psum += v/result}
|
455
|
-
end
|
456
|
-
lmin = 0.0
|
457
|
-
@lengthranges = []
|
458
|
-
lengths.each do |llength|
|
459
|
-
# Trace("lmin #{lmin} llength #{llength}")
|
460
|
-
@lengthranges << (lmin..llength)
|
461
|
-
lmin = llength
|
462
|
-
end
|
463
|
-
@lengthranges[-1] = @lengthranges[-1].begin..1.0
|
464
|
-
return result
|
465
|
-
end
|
466
|
-
|
467
|
-
# utilitary method for interbezier
|
468
|
-
#
|
469
|
-
# return list of piece lengths relatives to total bezier lengths, and cumulated
|
470
|
-
# Bezier.new( :pieces, [piece1, piece2] ).piecelengths; => [0.0, piece1.length / bezier.length, 1.0]
|
471
|
-
def piecelengths
|
472
|
-
result = self.lengthranges.map {|range| range.begin}
|
473
|
-
result << 1.0
|
474
|
-
return result
|
475
|
-
end
|
476
|
-
|
477
|
-
# private method, to compute lengthranges if not existing
|
478
|
-
def lengthranges #:nodoc:
|
479
|
-
if not @lengthranges
|
480
|
-
compute_length
|
481
|
-
end
|
482
|
-
return @lengthranges
|
483
|
-
end
|
484
|
-
|
485
|
-
def length_parameter_mapping( t, side ) #:nodoc:
|
486
|
-
pieceindex = -1
|
487
|
-
# Trace("self.lengthranges #{self.lengthranges.inspect}")
|
488
|
-
self.lengthranges.each_with_index do |lrange,i|
|
489
|
-
if lrange.include?( t )
|
490
|
-
pieceindex = i
|
491
|
-
t = lrange.abscissa( t )
|
492
|
-
t = self.piece( i ).parameterfromlength( t )
|
493
|
-
# Trace("pieceindex #{pieceindex} t #{t}")
|
494
|
-
break
|
495
|
-
end
|
496
|
-
end
|
497
|
-
if ((side == :left) and t.fequal?(1.0) and (pieceindex < self.piecenumber - 1))
|
498
|
-
pieceindex += 1
|
499
|
-
t = 0.0
|
500
|
-
end
|
501
|
-
if pieceindex == -1
|
502
|
-
Kernel::raise("length_parameter_mapping error : t #{t} is not in length range #{self.lengthranges.inspect}")
|
503
|
-
end
|
504
|
-
return [pieceindex, t]
|
505
|
-
end
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
# -------------------------------------------------------------
|
510
|
-
# sampler computation
|
511
|
-
# -------------------------------------------------------------
|
512
|
-
include Samplable
|
513
|
-
include Splittable
|
514
|
-
|
515
|
-
# filter, sampler methods
|
516
|
-
#
|
517
|
-
# just a shortcut to define easily specific sampler on bezier curve
|
518
|
-
#
|
519
|
-
# TODO : must be defined on Curve interface !!
|
520
|
-
def filter(type=:point, &block)
|
521
|
-
return super(type, &block).addfilter( (0.0..1.0) )
|
522
|
-
end
|
523
|
-
|
524
|
-
def apply_split( t1, t2 ) #:nodoc:
|
525
|
-
return self.subbezier( t1, t2 )
|
526
|
-
end
|
527
|
-
|
528
|
-
alias apply_sample point
|
529
|
-
# alias apply_split subbezier
|
530
|
-
alias sampler filter
|
531
|
-
|
532
|
-
# TODO : add generic bezier builder from points : must be adaptative !! (use Fitting)
|
533
|
-
end
|
534
|
-
end
|
535
|
-
|
536
|
-
|