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