xrvg 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|