xrvg 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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/bezierbuilders.rb
DELETED
@@ -1,210 +0,0 @@
|
|
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
|
-
# following computation is too expensive
|
190
|
-
# return FitBezierBuilder[ :points, self.samples( 20 ) ]
|
191
|
-
|
192
|
-
# based on http://www.whizkidtech.redprince.net/bezier/circle/
|
193
|
-
kappa = 0.5522847498
|
194
|
-
|
195
|
-
beziers = []
|
196
|
-
self.frames( (0.0..1.0).samples(5) ).pairs do |f1,f2|
|
197
|
-
beziers << Bezier.vector( f1.center, f1.vector.norm * kappa * self.radius, f2.center, f2.vector.norm * kappa * (-self.radius) )
|
198
|
-
end
|
199
|
-
|
200
|
-
result = beziers[0]
|
201
|
-
beziers[1..-1].each do |b|
|
202
|
-
result = result + b
|
203
|
-
end
|
204
|
-
|
205
|
-
return result
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
|
210
|
-
end # end XRVG
|
data/lib/beziermotifs.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
# See
|
2
|
-
# - BezierMotif
|
3
|
-
# - PicBezier
|
4
|
-
# - ArcBezier
|
5
|
-
# - LinearBezier
|
6
|
-
|
7
|
-
require 'bezierbuilders'
|
8
|
-
|
9
|
-
module XRVG
|
10
|
-
|
11
|
-
# = BezierMotif class
|
12
|
-
# == Content
|
13
|
-
# Abstract class to define prototype of a motif bezier factory
|
14
|
-
# Motif is localized by the :support attribute
|
15
|
-
# == Attributes
|
16
|
-
# attribute :support
|
17
|
-
class BezierMotif < BezierBuilder
|
18
|
-
include Attributable
|
19
|
-
attribute :support
|
20
|
-
|
21
|
-
def BezierMotif.build( *args )
|
22
|
-
builder = self.new( *args )
|
23
|
-
result = []
|
24
|
-
builder.support.pairs do |p1,p2|
|
25
|
-
builder.support = [p1,p2]
|
26
|
-
result << Bezier.multi( builder.compute )
|
27
|
-
end
|
28
|
-
return result.sum
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
# = PicBezier class
|
36
|
-
# == Content
|
37
|
-
# Build a curved "pic" bezier whose base is specified by two points, and whose shape is controlled by two attributes, :height and :curvature.
|
38
|
-
# :height parameter is a factor of base length
|
39
|
-
# == Attributes
|
40
|
-
# attribute :height, 1.0
|
41
|
-
# attribute :curvature, 1.0
|
42
|
-
# == Example
|
43
|
-
# pic = PicBezier[ :support, [V2D::O, V2D::X], :height, 1.0, :curvature, 2.0 ]
|
44
|
-
class PicBezier < BezierMotif
|
45
|
-
attribute :height, 1.0
|
46
|
-
attribute :curvature, 1.0
|
47
|
-
|
48
|
-
# BezierBuilder compute overloading.
|
49
|
-
#
|
50
|
-
# See code for algorithm
|
51
|
-
def compute
|
52
|
-
p1, p2 = self.support
|
53
|
-
onethird = (1.0 / 3.0)
|
54
|
-
p1top2 = p2 - p1
|
55
|
-
pp1 = p1 + p1top2.ortho.*(@height)
|
56
|
-
pp2 = pp1 + ( p1top2 * @curvature )
|
57
|
-
|
58
|
-
p1topp2 = pp2 - p1
|
59
|
-
pc1 = p1 + ( p1topp2 * onethird )
|
60
|
-
pc2 = p2 + ( p1topp2 * onethird )
|
61
|
-
|
62
|
-
p3 = p1 + ( p1top2 * @curvature )
|
63
|
-
p4 = p1 + ( p1top2 * ( @curvature + 1.0 ) )
|
64
|
-
|
65
|
-
pp1top2 = p3 - pp1
|
66
|
-
pp1top3 = p4 - pp1
|
67
|
-
|
68
|
-
pp1c1 = pp1 + ( pp1top2 * onethird )
|
69
|
-
pp1c2 = pp1 + ( pp1top3 * onethird )
|
70
|
-
|
71
|
-
return [[:raw, p1, pc1, pp1c1, pp1], [:raw, pp1, pp1c2, pc2, p2]]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# = ArcBezier class
|
76
|
-
# == Content
|
77
|
-
# Build an "arc" bezier whose base is specified by two points, and whose shape is controlled by a :height attribute.
|
78
|
-
# :height parameter is a factor of base length
|
79
|
-
# == Attributes
|
80
|
-
# attribute :height, 1.0
|
81
|
-
# == Example
|
82
|
-
# arc = ArcBezier[ :support, [V2D::O, V2D::X], :height, 1.0 ]
|
83
|
-
class ArcBezier < BezierMotif
|
84
|
-
attribute :height, 1.0
|
85
|
-
|
86
|
-
# BezierBuilder compute overloading.
|
87
|
-
#
|
88
|
-
# See code for algorithm
|
89
|
-
def compute
|
90
|
-
p1, p2 = self.support
|
91
|
-
v = (p2 - p1).ortho * @height
|
92
|
-
return [[:vector, p1, v, p2, v]]
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# = LinearBezier class
|
97
|
-
# == Content
|
98
|
-
# Build an line bezier whose base is specified by two points.
|
99
|
-
# == Attributes
|
100
|
-
# None, apart from :support
|
101
|
-
# == Example
|
102
|
-
# line = LinearBezier[ :support, [V2D::O, V2D::X] ]
|
103
|
-
class LinearBezier < BezierMotif
|
104
|
-
attribute :support, [V2D::O, V2D::X]
|
105
|
-
|
106
|
-
# BezierBuilder compute overloading.
|
107
|
-
#
|
108
|
-
# See code for algorithm
|
109
|
-
def compute
|
110
|
-
p1, p2 = self.support
|
111
|
-
return [[:vector, p1, (p2-p1) * 1.0 / 3.0, p2, (p1 - p2) * 1.0 / 3.0]]
|
112
|
-
end
|
113
|
-
|
114
|
-
# Utilitary method to build a unit bezier line with angle
|
115
|
-
def LinearBezier.buildwithangle( angle )
|
116
|
-
return LinearBezier[ :support, [V2D::O, V2D::X.rotate( angle )]]
|
117
|
-
end
|
118
|
-
|
119
|
-
end
|
120
|
-
|
121
|
-
end # end XRVG
|
data/lib/bezierspline.rb
DELETED
@@ -1,235 +0,0 @@
|
|
1
|
-
# +BezierSpline+ source
|
2
|
-
|
3
|
-
require 'interpolation'
|
4
|
-
require 'parametriclength'
|
5
|
-
|
6
|
-
module XRVG
|
7
|
-
# BezierSpline class
|
8
|
-
#
|
9
|
-
# Internal class to represent a single-piece cubic bezier curve, defined by four points or two point + two vectors.
|
10
|
-
# You may never have to use this class. Prefer the use of +Bezier+ class
|
11
|
-
class BezierSpline #:nodoc:
|
12
|
-
|
13
|
-
def BezierSpline.[](*args)
|
14
|
-
return BezierSpline.new( *args )
|
15
|
-
end
|
16
|
-
|
17
|
-
def initialize( type, v1, v2, v3, v4 )
|
18
|
-
self.checktype( type )
|
19
|
-
self.checkvalues( v1, v2, v3, v4 )
|
20
|
-
self.initdata( type, v1, v2, v3, v4 )
|
21
|
-
end
|
22
|
-
|
23
|
-
def checkvalues( v1, v2, v3, v4 )
|
24
|
-
[v1, v2, v3, v4].each do |v|
|
25
|
-
if not (v.respond_to?(:x) || v.respond_to?(:y))
|
26
|
-
Kernel::raise( "BezierSpline : init value #{v.inspect} does not respond to :x or :y" )
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def checktype( type )
|
32
|
-
if not type == :raw || type == :vector
|
33
|
-
Kernel::raise( "BezierSpline : type #{type.inspect} is not :raw or :vector" )
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def data()
|
38
|
-
return [:raw] + self.pointlist
|
39
|
-
end
|
40
|
-
|
41
|
-
def initdata( type, v1, v2, v3, v4 )
|
42
|
-
@rawpointlist = nil
|
43
|
-
@vectorpointlist = nil
|
44
|
-
if type == :raw
|
45
|
-
@rawpointlist = [v1, v2, v3, v4]
|
46
|
-
else
|
47
|
-
@vectorpointlist = [v1, v2, v3, v4]
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def compute_rawpointlist
|
52
|
-
# Assert{ @vectorpointlist }
|
53
|
-
@rawpointlist = [@vectorpointlist[0], @vectorpointlist[0] + @vectorpointlist[1], @vectorpointlist[2] + @vectorpointlist[3], @vectorpointlist[2]]
|
54
|
-
end
|
55
|
-
|
56
|
-
def compute_vectorpointlist
|
57
|
-
# Assert{ @rawpointlist }
|
58
|
-
@vectorpointlist = [@rawpointlist[0], @rawpointlist[1] - @rawpointlist[0], @rawpointlist[3], @rawpointlist[2] - @rawpointlist[3]]
|
59
|
-
end
|
60
|
-
|
61
|
-
|
62
|
-
def pointlist(type=:raw)
|
63
|
-
self.checktype( type )
|
64
|
-
if type == :raw
|
65
|
-
if not @rawpointlist
|
66
|
-
self.compute_rawpointlist
|
67
|
-
end
|
68
|
-
return @rawpointlist
|
69
|
-
elsif type == :vector
|
70
|
-
if not @vectorpointlist
|
71
|
-
self.compute_vectorpointlist
|
72
|
-
end
|
73
|
-
return @vectorpointlist
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# shortcut method to get piece first point
|
78
|
-
def firstpoint
|
79
|
-
return self.pointlist()[0]
|
80
|
-
end
|
81
|
-
|
82
|
-
# shortcut method to get piece last point
|
83
|
-
def lastpoint
|
84
|
-
return self.pointlist()[-1]
|
85
|
-
end
|
86
|
-
|
87
|
-
# shortcut method to get piece first vector
|
88
|
-
def firstvector
|
89
|
-
return self.pointlist(:vector)[1]
|
90
|
-
end
|
91
|
-
|
92
|
-
# shortcut method to get piece last vector
|
93
|
-
def lastvector
|
94
|
-
return self.pointlist(:vector)[-1]
|
95
|
-
end
|
96
|
-
|
97
|
-
# -------------------------------------------------------------
|
98
|
-
# bezier formula
|
99
|
-
# -------------------------------------------------------------
|
100
|
-
|
101
|
-
def compute_factors
|
102
|
-
p1, p2, p3, p4 = self.pointlist
|
103
|
-
@factors = [-(p1 - p2 * 3.0 + p3 * 3.0 - p4), (p1 - p2 * 2.0 + p3) * 3.0, (p2 - p1) * 3.0, p1]
|
104
|
-
@tfactors = [@factors[0], @factors[1] * 2.0 / 3.0, @factors[2] / 3.0]
|
105
|
-
@afactors = [@tfactors[0] * 2.0, @tfactors[1]]
|
106
|
-
end
|
107
|
-
|
108
|
-
# get point from the bezier curve
|
109
|
-
# this method use the definition of the bezier curve
|
110
|
-
def point( t, result=nil )
|
111
|
-
t2 = t * t
|
112
|
-
t3 = t2 * t
|
113
|
-
if not result
|
114
|
-
result = V2D[0.0,0.0]
|
115
|
-
end
|
116
|
-
|
117
|
-
if not @factors
|
118
|
-
compute_factors
|
119
|
-
end
|
120
|
-
|
121
|
-
# decomposed because avoid to build useless V2D
|
122
|
-
result.x = @factors[3].x + @factors[2].x * t + @factors[1].x * t2 + @factors[0].x * t3
|
123
|
-
result.y = @factors[3].y + @factors[2].y * t + @factors[1].y * t2 + @factors[0].y * t3
|
124
|
-
|
125
|
-
return result
|
126
|
-
end
|
127
|
-
|
128
|
-
# compute the bezier tangent vector
|
129
|
-
#
|
130
|
-
# Beware that what is actually computed here is 1/3 tangent !!
|
131
|
-
def tangent( t, result=nil )
|
132
|
-
t2 = t * t
|
133
|
-
if not result
|
134
|
-
result = V2D[0.0,0.0]
|
135
|
-
end
|
136
|
-
|
137
|
-
if not @factors
|
138
|
-
compute_factors
|
139
|
-
end
|
140
|
-
|
141
|
-
# decomposed because avoid to build useless V2D
|
142
|
-
result.x = @tfactors[2].x + @tfactors[1].x * t + @tfactors[0].x * t2
|
143
|
-
result.y = @tfactors[2].y + @tfactors[1].y * t + @tfactors[0].y * t2
|
144
|
-
|
145
|
-
return result
|
146
|
-
end
|
147
|
-
|
148
|
-
# compute the acc of bezier curve at t abscissa
|
149
|
-
def acc( t, result=nil )
|
150
|
-
if not result
|
151
|
-
result = V2D[0.0,0.0]
|
152
|
-
end
|
153
|
-
|
154
|
-
if not @factors
|
155
|
-
compute_factors
|
156
|
-
end
|
157
|
-
|
158
|
-
result.x = @afactors[1].x + @afactors[0].x * t
|
159
|
-
result.y = @afactors[1].y + @afactors[0].y * t
|
160
|
-
|
161
|
-
return result
|
162
|
-
end
|
163
|
-
|
164
|
-
# compute tangent vectors corresponding to the new subbezier
|
165
|
-
# very strange method, but effective
|
166
|
-
def subtangents (t1, t2 )
|
167
|
-
v1 = self.tangent( t1 ) * (t2 - t1)
|
168
|
-
v2 = self.tangent( t2 ) * (t1 - t2)
|
169
|
-
return [v1, v2]
|
170
|
-
end
|
171
|
-
|
172
|
-
# compute a subpiece of the current bezier
|
173
|
-
# t1 and t2 must correspond to the same atomic bezier
|
174
|
-
def subpiece (t1, t2)
|
175
|
-
tan1, tan2 = self.subtangents( t1, t2 )
|
176
|
-
return BezierSpline.new( :vector, self.point( t1 ), tan1, self.point( t2 ), tan2 )
|
177
|
-
end
|
178
|
-
|
179
|
-
def reverse()
|
180
|
-
return BezierSpline[ :raw, *self.pointlist().reverse ]
|
181
|
-
end
|
182
|
-
|
183
|
-
# simple translation operation : translate every point of the piece
|
184
|
-
# return a new BezierSpline
|
185
|
-
def translate( v )
|
186
|
-
newpoints = self.pointlist.map {|point| point + v}
|
187
|
-
return BezierSpline[ :raw, *newpoints ]
|
188
|
-
end
|
189
|
-
|
190
|
-
# simple rotation operation : rotate every point of the piece
|
191
|
-
# return a new BezierSpline
|
192
|
-
def rotate( angle, center )
|
193
|
-
newpoints = self.pointlist.map {|point| center + (point-center).rotate( angle )}
|
194
|
-
return BezierSpline[ :raw, *newpoints ]
|
195
|
-
end
|
196
|
-
|
197
|
-
# simple sym operation : sym every point of the piece
|
198
|
-
# return a new BezierSpline
|
199
|
-
def sym( center )
|
200
|
-
newpoints = self.pointlist.map {|point| center.sym( point )}
|
201
|
-
return BezierSpline[ :raw, *newpoints ]
|
202
|
-
end
|
203
|
-
|
204
|
-
|
205
|
-
# simple axe sym operation : sym every point of the piece
|
206
|
-
# return a new BezierSpline
|
207
|
-
def axesym( origin, v )
|
208
|
-
newpoints = self.pointlist.map {|point| point.axesym( origin, v )}
|
209
|
-
return BezierSpline[ :raw, *newpoints ]
|
210
|
-
end
|
211
|
-
|
212
|
-
def gdebug(render)
|
213
|
-
p1, pc1, pc2, p2 = self.pointlist()
|
214
|
-
v1 = pc1 - p1
|
215
|
-
r1 = v1.r / 30.0
|
216
|
-
v2 = pc2 - p2
|
217
|
-
r2 = v2.r / 30.0
|
218
|
-
render.add( Circle[ :center, p1, :radius, r1 ], Style[ :fill, "red" ])
|
219
|
-
render.add( Circle[ :center, pc1, :radius, r1 ], Style[ :fill, "red" ])
|
220
|
-
render.add( Line[ :points, [p1, pc1] ], Style[ :stroke, "red", :strokewidth, (r1 / 10.0) ])
|
221
|
-
render.add( Circle[ :center, p2, :radius, r2 ], Style[ :fill, "red" ])
|
222
|
-
render.add( Circle[ :center, pc2, :radius, r1 ], Style[ :fill, "red" ])
|
223
|
-
render.add( Line[ :points, [p2, pc2] ], Style[ :stroke, "red", :strokewidth, (r2 / 10.0) ])
|
224
|
-
end
|
225
|
-
|
226
|
-
# length computation
|
227
|
-
include ParametricLength
|
228
|
-
def parameter_range
|
229
|
-
return (0.0..1.0)
|
230
|
-
end
|
231
|
-
|
232
|
-
alias pointfromparameter point
|
233
|
-
|
234
|
-
end
|
235
|
-
end
|