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/CHANGES
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
= CHANGES
|
2
2
|
|
3
|
+
== 0.0.4 (2008.03.16)
|
4
|
+
Really big functional release. Several additional releases are needed to add appropriate tests and docs.
|
5
|
+
=== Content
|
6
|
+
- XRVG namespace creation: you must now add "include XRVG" after "require 'xrvg'" to make your previous work OK.
|
7
|
+
- bezier curve fitting algorithm implementation
|
8
|
+
- adaptative bezier curve fitting algorithm implementation
|
9
|
+
- bezier builder hierarchy introducing
|
10
|
+
- ArcBezier and PicBezier bezier motifs
|
11
|
+
- Offset, Ondulation, ClosureBezier bezier builders
|
12
|
+
- meta bezier builders: iterator builders, fitting builders
|
13
|
+
=== Other little additions
|
14
|
+
- new FloatFunctor filter Alternate (must be consolidated though)
|
15
|
+
=== Removed Bugs
|
16
|
+
- splits enumerator works again
|
17
|
+
- debug bezier filter method
|
18
|
+
=== Refactoring
|
19
|
+
- make bezier frame with container
|
20
|
+
- ParametricLength module extraction from BezierSpline
|
21
|
+
=== TODO
|
22
|
+
- complete Circle curve, with split interface (maybe add generic method in Curve, from bezier, as circle -> bezier method is available)
|
23
|
+
|
3
24
|
== 0.0.3 (2008.02.17)
|
4
25
|
=== Content
|
5
26
|
- just bug correction, optims and refactoring
|
data/README
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= XRVG -- X Ruby Vector Graphics
|
2
2
|
|
3
|
-
Supporting XRVG version: 0.0.
|
3
|
+
Supporting XRVG version: 0.0.4
|
4
4
|
|
5
5
|
This package contains XRVG, a Ruby vector graphic programming library.
|
6
6
|
|
@@ -64,7 +64,7 @@ new feature to be submitted in the form of new unit tests.
|
|
64
64
|
|
65
65
|
For other information, feel free to ask on the ruby-talk mailing list
|
66
66
|
(which is mirrored to comp.lang.ruby) or contact
|
67
|
-
mailto:
|
67
|
+
mailto:julien.leonard@nospam@ensta.org.
|
68
68
|
|
69
69
|
|
70
70
|
= Other stuff
|
@@ -75,7 +75,7 @@ Thanks for Rake project, whose README file has been adapted to do this one.
|
|
75
75
|
|
76
76
|
== Summary
|
77
77
|
|
78
|
-
Author:: Julien L�onard <
|
78
|
+
Author:: Julien L�onard <julien.leonard@nospam@ensta.org>
|
79
79
|
Requires:: Ruby 1.8.0 or later (but not compatible with 1.9.0)
|
80
80
|
License:: Copyright 2008 by Julien L�onard.
|
81
81
|
Released under an MIT-style license.
|
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ PROJECT = "XRVG"
|
|
11
11
|
MY_NAME = "Julien L�onard"
|
12
12
|
|
13
13
|
# Your email address, used in packaging.
|
14
|
-
MY_EMAIL = "
|
14
|
+
MY_EMAIL = "julien.leonard@nospam@ensta.org"
|
15
15
|
|
16
16
|
# Short summary of your project, used in packaging.
|
17
17
|
PROJECT_SUMMARY = "Ruby vector graphics library"
|
@@ -45,7 +45,7 @@ REQUIRE_PATHS << EXT_DIR if HAVE_EXT
|
|
45
45
|
$LOAD_PATH.concat(REQUIRE_PATHS)
|
46
46
|
# This library file defines the RAKEVERSION constant.
|
47
47
|
require "#{UNIX_NAME}"
|
48
|
-
PROJECT_VERSION = eval("\"#{XRVG_VERSION}\"")
|
48
|
+
PROJECT_VERSION = eval("\"#{XRVG_VERSION}\"")
|
49
49
|
|
50
50
|
#---
|
51
51
|
# Options common to RDocTask AND Gem::Specification.
|
@@ -63,7 +63,7 @@ RDOC_FILES = FileList["README", "CHANGES"]
|
|
63
63
|
|
64
64
|
# Ruby library code.
|
65
65
|
LIB_DIR = "lib"
|
66
|
-
PRE_LIB_FILES = FileList["
|
66
|
+
PRE_LIB_FILES = FileList["trace.rb", "samplation.rb", "interpolation.rb", "parametriclength.rb", "utils.rb", "geometry2D.rb", "color.rb", "frame.rb", "shape.rb", "render.rb", "shape.rb", "style.rb", "bezier.rb", "bezierspline.rb", "fitting.rb", "bezierbuilders.rb", "beziermotifs.rb", "beziertools.rb", "interbezier.rb", "xrvg.rb"]
|
67
67
|
LIB_FILES = FileList["#{LIB_DIR}/*.rb"]
|
68
68
|
|
69
69
|
# Example code.
|
@@ -72,7 +72,7 @@ EXAMPLE_FILES = FileList["#{EXAMPLE_DIR}/*.rb"]
|
|
72
72
|
|
73
73
|
# Filelist with Test::Unit test cases.
|
74
74
|
TEST_DIR = "test"
|
75
|
-
PRE_TEST_FILES = FileList["
|
75
|
+
PRE_TEST_FILES = FileList["test_*.rb"]
|
76
76
|
TEST_FILES = FileList["test/*.rb"]
|
77
77
|
|
78
78
|
# Executable scripts, all non-garbage files under bin/.
|
data/examples/bezierbasic.rb
CHANGED
data/examples/foreach.rb
CHANGED
data/examples/geodash.rb
CHANGED
data/examples/geodash2.rb
CHANGED
data/examples/hellocrown.rb
CHANGED
data/examples/hellocrown2.rb
CHANGED
data/examples/palette_circle.rb
CHANGED
data/examples/randomdash.rb
CHANGED
data/examples/range_examples.rb
CHANGED
data/examples/range_examples2.rb
CHANGED
data/examples/sample.rb
CHANGED
data/examples/simpledash.rb
CHANGED
data/examples/uplets.rb
CHANGED
data/lib/bezier.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
require 'bezierspline'
|
5
5
|
require 'shape'
|
6
6
|
|
7
|
+
module XRVG
|
7
8
|
# = Base class for cubic bezier curves
|
8
9
|
# == Basics
|
9
10
|
# See http://en.wikipedia.org/wiki/B%C3%A9zier_curve
|
@@ -94,7 +95,7 @@ class Bezier < Curve
|
|
94
95
|
# args is a list of points and control points as [p1, v1, p2, v2, p3, v3]
|
95
96
|
#
|
96
97
|
# Beware that
|
97
|
-
# Bezier.vector( p1, v1, p2, v2 ) == Bezier.
|
98
|
+
# Bezier.vector( p1, v1, p2, v2 ) == Bezier.vectors( p1, v1, p2, -v2)
|
98
99
|
def Bezier.vectors( *args )
|
99
100
|
rawpieces = []
|
100
101
|
args.foreach(2).pairs do |pair1, pair2|
|
@@ -182,6 +183,11 @@ class Bezier < Curve
|
|
182
183
|
def bezier( index )
|
183
184
|
return Bezier.single( *self.piece( index ).data )
|
184
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
|
185
191
|
|
186
192
|
|
187
193
|
# -------------------------------------------------------------
|
@@ -195,19 +201,10 @@ class Bezier < Curve
|
|
195
201
|
check_parametertype( parametertype )
|
196
202
|
result = []
|
197
203
|
if parametertype == :length
|
198
|
-
|
199
|
-
index = 0.0
|
200
|
-
elsif index > 1.0
|
201
|
-
index = 1.0
|
202
|
-
end
|
204
|
+
index = (0.0..1.0).trim( index )
|
203
205
|
result = length_parameter_mapping( index, side )
|
204
206
|
else # no need to test parametertype value, as check_parametertype already do it
|
205
|
-
|
206
|
-
index = 0.0
|
207
|
-
elsif index > self.piecenumber
|
208
|
-
index = self.piecenumber.to_f
|
209
|
-
end
|
210
|
-
|
207
|
+
index = (0.0..self.piecenumber.to_f).trim( index )
|
211
208
|
pieceindex = index < self.piecenumber ? index.to_i : (index-1).to_i
|
212
209
|
t = index - pieceindex
|
213
210
|
result = [pieceindex, t]
|
@@ -252,12 +249,16 @@ class Bezier < Curve
|
|
252
249
|
end
|
253
250
|
|
254
251
|
# curve method redefinition to factorize parametermapping
|
255
|
-
def frame( t, parametertype=:length )
|
252
|
+
def frame( t, container=nil, parametertype=:length )
|
256
253
|
pieceindex, t = parametermapping( t, parametertype )
|
257
|
-
|
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
258
|
rotation = self.rotation( nil, tangent )
|
259
259
|
scale = self.scale( nil, tangent )
|
260
|
-
|
260
|
+
result = container ? container : Frame[ :center, point, :vector, tangent, :rotation, rotation, :scale, scale ]
|
261
|
+
return result
|
261
262
|
end
|
262
263
|
|
263
264
|
# -------------------------------------------------------------
|
@@ -291,17 +292,6 @@ class Bezier < Curve
|
|
291
292
|
return Bezier.new( :pieces, self.subpieces( t1, t2 ) )
|
292
293
|
end
|
293
294
|
|
294
|
-
# split method
|
295
|
-
if nil
|
296
|
-
def split(nchildren=2, type=:regular)
|
297
|
-
return self.range.split(nchildren,type).map { |range| self.subbezier( range.begin, range.end ) }
|
298
|
-
end
|
299
|
-
|
300
|
-
def subdivise( samples )
|
301
|
-
return samples.pairs.map { |t1, t2| self.subbezier( t1, t2 ) }
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
295
|
# -------------------------------------------------------------
|
306
296
|
# reverse
|
307
297
|
# -------------------------------------------------------------
|
@@ -365,20 +355,6 @@ class Bezier < Curve
|
|
365
355
|
return Bezier.new( :pieces, self.pieces + other.pieces )
|
366
356
|
end
|
367
357
|
|
368
|
-
# -------------------------------------------------------------
|
369
|
-
# range
|
370
|
-
# -------------------------------------------------------------
|
371
|
-
|
372
|
-
# TODO
|
373
|
-
def ranges #:nodoc:
|
374
|
-
(0..self.piecenumber).to_a.pairs.map {|start,stop| Range.new( start, stop )}
|
375
|
-
end
|
376
|
-
|
377
|
-
# TODO
|
378
|
-
def range #:nodoc:
|
379
|
-
return (0..self.piecenumber)
|
380
|
-
end
|
381
|
-
|
382
358
|
# -------------------------------------------------------------
|
383
359
|
# svg
|
384
360
|
# -------------------------------------------------------------
|
@@ -437,7 +413,7 @@ class Bezier < Curve
|
|
437
413
|
# must use an interpolator ?
|
438
414
|
def compute_length #:nodoc:
|
439
415
|
lengths = self.pieces.map {|piece| piece.length}
|
440
|
-
Trace("pieces #{self.pieces.inspect} lenghts #{lengths.inspect}")
|
416
|
+
# Trace("pieces #{self.pieces.inspect} lenghts #{lengths.inspect}")
|
441
417
|
result = lengths.sum
|
442
418
|
if result == 0.0
|
443
419
|
lengths = [1.0]
|
@@ -476,13 +452,13 @@ class Bezier < Curve
|
|
476
452
|
|
477
453
|
def length_parameter_mapping( t, side ) #:nodoc:
|
478
454
|
pieceindex = -1
|
479
|
-
Trace("self.lengthranges #{self.lengthranges.inspect}")
|
455
|
+
# Trace("self.lengthranges #{self.lengthranges.inspect}")
|
480
456
|
self.lengthranges.each_with_index do |lrange,i|
|
481
457
|
if lrange.include?( t )
|
482
458
|
pieceindex = i
|
483
459
|
t = lrange.abscissa( t )
|
484
460
|
t = self.piece( i ).parameterfromlength( t )
|
485
|
-
Trace("pieceindex #{pieceindex} t #{t}")
|
461
|
+
# Trace("pieceindex #{pieceindex} t #{t}")
|
486
462
|
break
|
487
463
|
end
|
488
464
|
end
|
@@ -510,11 +486,7 @@ class Bezier < Curve
|
|
510
486
|
#
|
511
487
|
# TODO : must be defined on Curve interface !!
|
512
488
|
def filter(type=:point, &block)
|
513
|
-
|
514
|
-
return super(:pointbylength, &block )
|
515
|
-
else
|
516
|
-
return super(type, &block).addfilter( self.range )
|
517
|
-
end
|
489
|
+
return super(type, &block).addfilter( (0.0..1.0) )
|
518
490
|
end
|
519
491
|
|
520
492
|
def apply_split( t1, t2 ) #:nodoc:
|
@@ -527,10 +499,4 @@ class Bezier < Curve
|
|
527
499
|
|
528
500
|
# TODO : add generic bezier builder from points : must be adaptative !! (use Fitting)
|
529
501
|
end
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
502
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# BezierBuilder file
|
2
|
+
# See:
|
3
|
+
# - BezierBuilder
|
4
|
+
# - SimilarMotifIterator
|
5
|
+
# - AttributeMotifIterator
|
6
|
+
# - FitBezierBuilder
|
7
|
+
|
8
|
+
require 'bezier'
|
9
|
+
require 'fitting'
|
10
|
+
|
11
|
+
module XRVG
|
12
|
+
|
13
|
+
# = BezierBuilder class
|
14
|
+
# == Content
|
15
|
+
# Abstract class to define prototype of a bezier factory
|
16
|
+
#
|
17
|
+
# Provides the notation
|
18
|
+
# bezierresult = BezierBuilder[ :parameter1, arg1, :parameter2, arg2 ]
|
19
|
+
# with bezierresult the computed Bezier object from the BezierBuilder algorithm
|
20
|
+
class BezierBuilder
|
21
|
+
include Attributable
|
22
|
+
|
23
|
+
# Hook for subclassing : must return a list of raw pieces, to be provided to Bezier.multi
|
24
|
+
def compute()
|
25
|
+
raise NotImplementedError.new("#{self.class.name}#compute is an abstract method.")
|
26
|
+
end
|
27
|
+
|
28
|
+
# syntax sugar method to replace BezierBuilder.build notation with the simpler BezierBuilder[] one
|
29
|
+
#
|
30
|
+
# Note that BezierBuilder[] does not return a BezierBuilder object, but a Bezier one
|
31
|
+
def BezierBuilder.[](*args)
|
32
|
+
return self.build( *args )
|
33
|
+
end
|
34
|
+
|
35
|
+
# create the BezierBuilder, and build a Bezier.multi by calling BezierBuilder.compute
|
36
|
+
def BezierBuilder.build( *args )
|
37
|
+
builder = self.new( *args )
|
38
|
+
return Bezier.multi( builder.compute )
|
39
|
+
end
|
40
|
+
|
41
|
+
# multipiece bezier operator to smooth tangents of piece junctions
|
42
|
+
#
|
43
|
+
# Algo:
|
44
|
+
# - for each pair of pieces, take last and first vector
|
45
|
+
# - compute the mean of these vectors
|
46
|
+
# - for each vector, linearly interpolate given :factor between initial vector and mean
|
47
|
+
# As a consequence, default :factor value means that by default, we take vector means, and this operator
|
48
|
+
# do nothing if you set :factor to 0.0
|
49
|
+
def BezierBuilder.lissage( bezier, factor=1.0 )
|
50
|
+
result = [[:vector] + (bezier.pieces[0].pointlist(:vector))[0..1]]
|
51
|
+
bezier.pieces.pairs do |piece1, piece2|
|
52
|
+
p = piece1.lastpoint;# equal to piece2.firstpoint
|
53
|
+
v1, v2 = [-piece1.lastvector, piece2.firstvector]
|
54
|
+
mean = (v1..v2).mean
|
55
|
+
newv1 = (v1..mean).sample( factor )
|
56
|
+
newv2 = (v2..mean).sample( factor )
|
57
|
+
result[-1] += [p,-newv1]
|
58
|
+
result << [:vector, p, newv2]
|
59
|
+
end
|
60
|
+
result[-1] += (bezier.pieces[-1].pointlist(:vector))[-2..-1]
|
61
|
+
return Bezier.multi( result )
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
#-------------------------------------------------------------------------------
|
67
|
+
# We can now build on these atomic motifs some motif iterators
|
68
|
+
#-------------------------------------------------------------------------------
|
69
|
+
|
70
|
+
# = Similar Motif Iterator
|
71
|
+
# == Content
|
72
|
+
# Take a bezier curve as :motif, and a "curvesampler" as a support with sampling description, and iterate motif on each pair computed by sampling
|
73
|
+
# == Attributes
|
74
|
+
# attribute :curvesampler, nil, Samplable
|
75
|
+
# attribute :motif, nil, Bezier
|
76
|
+
# attribute :nmotifs, 10
|
77
|
+
# == Example
|
78
|
+
# motif = PicBezier[ :support, [V2D::O, V2D::X], :height, -1.0 ]
|
79
|
+
# curvesampler = bezier.geo( 3.0 )
|
80
|
+
# bezier = SimilarMotifIterator[ :curvesampler, curvesampler, :motif, motif, :nmotifs, 10 ]
|
81
|
+
# == TODO
|
82
|
+
# Represents the basic operator to compute bezier fractal curves !!
|
83
|
+
class SimilarMotifIterator < BezierBuilder
|
84
|
+
attribute :curvesampler, nil, Samplable
|
85
|
+
attribute :motif, nil, Bezier
|
86
|
+
attribute :nmotifs, 10
|
87
|
+
|
88
|
+
# BezierBuilder overloading
|
89
|
+
#
|
90
|
+
# Algo
|
91
|
+
# - sample @nmotif+1 times @curvesampler to get @nmotifs point pairs
|
92
|
+
# - foreach pair, compute new bezier by calling Bezier.similar on @motif
|
93
|
+
def compute
|
94
|
+
result = []
|
95
|
+
self.curvesampler.samples( self.nmotifs + 1).pairs do |p1,p2|
|
96
|
+
Trace("SimilarMotifIterator::compute p1 #{p1.inspect} p2 #{p2.inspect}")
|
97
|
+
newbezier = self.motif.similar( (p1..p2) )
|
98
|
+
result += newbezier.data
|
99
|
+
end
|
100
|
+
return result
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
# = Attribute Motif Iterator
|
106
|
+
# == Content
|
107
|
+
# More advanced motif iterator than SimilarMotifIterator, and also more expensive, AttributeMotifIterator samples
|
108
|
+
# a curvesampler and foreach pair build a new bezier motif, with varying attributes
|
109
|
+
# == Attributes
|
110
|
+
# attribute :curvesampler, nil, Splittable
|
111
|
+
# attribute :motifclass
|
112
|
+
# attribute :nmotifs, 10
|
113
|
+
# attribute :attributes, [], Array
|
114
|
+
# attribute :closed, false
|
115
|
+
# :motifclass is a BezierBuilder class, as ArcBezier, PicBezier, or even AttributeMotifIterator...
|
116
|
+
#
|
117
|
+
# :attributes is of the form [attribute1, specification1, :attribute2, specification, ...] with
|
118
|
+
# - attribute1, attribute2 attributes of the :motifclass
|
119
|
+
# - specification can be :
|
120
|
+
# - single value
|
121
|
+
# - sampler
|
122
|
+
#
|
123
|
+
# :closed attribute state if each subbezier computed for each point pair must be closed with the corresponding subbezier of the :curvesampler
|
124
|
+
# == Example
|
125
|
+
# motif = PicBezier[ :support, [V2D::O, V2D::X], :height, -1.0 ]
|
126
|
+
# curvesampler = bezier.geo( 3.0 )
|
127
|
+
# result = AttributeMotifIterator[ :curvesampler, curvesampler, :motifclass, ArcBezier, :attributes, [:height, (-2.0..0.0).random], :nmotifs, 30, :closed, true ]
|
128
|
+
# == WARNING
|
129
|
+
# Only works with BezierMotif defined by two points
|
130
|
+
class AttributeMotifIterator < BezierBuilder
|
131
|
+
attribute :curvesampler, nil, Splittable
|
132
|
+
attribute :motifclass
|
133
|
+
attribute :nmotifs, 10
|
134
|
+
attribute :attributes, [], Array
|
135
|
+
attribute :closed, false
|
136
|
+
|
137
|
+
# BezierBuilder overloading
|
138
|
+
#
|
139
|
+
# See AttributeMotifIterator class description for details
|
140
|
+
def compute
|
141
|
+
result = []
|
142
|
+
attrvalues = []
|
143
|
+
self.attributes.foreach do |name, spec|
|
144
|
+
attrvalues += [name, Samplable.build( spec ).samples( self.nmotifs )]
|
145
|
+
end
|
146
|
+
self.curvesampler.splits( self.nmotifs ).each_with_index do |subbezier,index|
|
147
|
+
pair = [subbezier.firstpoint, subbezier.lastpoint]
|
148
|
+
p1, p2 = pair
|
149
|
+
args = [:support, pair]
|
150
|
+
attrvalues.foreach do |name, values|
|
151
|
+
args += [name, values[index]]
|
152
|
+
end
|
153
|
+
newbezier = self.motifclass[ *args ]
|
154
|
+
if self.closed
|
155
|
+
newbezier = newbezier + subbezier.reverse
|
156
|
+
end
|
157
|
+
result += newbezier.data
|
158
|
+
end
|
159
|
+
return result
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
# = FitBezierBuilder class
|
165
|
+
# == Content
|
166
|
+
# Build a bezier from a point list defined by :points by computing adaptative multipiece bezier fitting.
|
167
|
+
#
|
168
|
+
# While this class is by itself quite usefull, it can also be subclassed by overloading "points" method to
|
169
|
+
# compute all sorts of curve (as Offset for example)
|
170
|
+
# == Attributes
|
171
|
+
# attribute :points, [], Array; # to be able to subclass FitBezierBuilder to compute points by diverse means
|
172
|
+
# attribute :maxerror, 0.001
|
173
|
+
# :maxerror attribute represents the bezier curve matching error (as explained in Fitting)
|
174
|
+
class FitBezierBuilder < BezierBuilder
|
175
|
+
attribute :points, [], Array; # to be able to subclass FitBezierBuilder to compute points by diverse means
|
176
|
+
attribute :maxerror, 0.001
|
177
|
+
|
178
|
+
def FitBezierBuilder.build( *args )
|
179
|
+
builder = self.new( *args )
|
180
|
+
return Fitting.adaptative_compute( builder.points, builder.maxerror )[0]
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
# Extend Circle class for subcurve definition
|
186
|
+
class Circle
|
187
|
+
# return approximating bezier curve
|
188
|
+
def bezier
|
189
|
+
return FitBezierBuilder[ :points, self.samples( 20 ) ]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
end # end XRVG
|