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/lib/shape.rb DELETED
@@ -1,421 +0,0 @@
1
- # shape.rb file
2
- # See
3
- # - Shape interface
4
- # - Curve interface
5
- # - Line class
6
- # - Circle class
7
- require 'utils'
8
- require 'frame'
9
- require 'geometry2D'
10
-
11
-
12
- module XRVG
13
- # Shape abstract interface
14
- # = Intro
15
- # To provide a set of services a shape class must provide
16
- class Shape
17
- include Attributable
18
-
19
- # must return the contour of the shape, of Curve type
20
- #
21
- # abstract
22
- #
23
- # not yet used
24
- def contour( *args )
25
- raise NotImplementedError.new("#{self.class.name}#contour is an abstract method.")
26
- end
27
-
28
- # must return the svg description of the shape
29
- #
30
- # abstract
31
- #
32
- # must be defined
33
- def svg()
34
- raise NotImplementedError.new("#{self.class.name}#svg is an abstract method.")
35
- end
36
-
37
- # must return the enclosing box of the shape, that is [xmin, ymin, xmax, ymax]
38
- #
39
- # abstract
40
- #
41
- # must be defined
42
- def viewbox()
43
- raise NotImplementedError.new("#{self.class.name}#viewbox is an abstract method.")
44
- end
45
-
46
- # compute size of the shape, from viewbox
47
- def size()
48
- xmin, ymin, xmax, ymax = self.viewbox
49
- return [xmax-xmin, ymax-ymin]
50
- end
51
-
52
- # return the default style for a Shape instance
53
- #
54
- # is done on instance, because for Curve for example, strokewidth is proportional to length
55
- def default_style()
56
- return Style[:fill, Color.black ]
57
- end
58
-
59
- # compute the "surface" of the viewbox of the shape
60
- #
61
- # use size method
62
- def surface
63
- width, height = self.size
64
- return width * height
65
- end
66
-
67
- end
68
-
69
- # Curve abstract interface
70
- # = Intro
71
- # To define a set of services a curve class must provide
72
- class Curve < Shape
73
- # must compute the point at curve abscissa
74
- #
75
- # abstract
76
- #
77
- # must be defined
78
- def point( abscissa, container=nil )
79
- raise NotImplementedError.new("#{self.class.name}#curve is an abstract method.")
80
- end
81
-
82
- # must compute the tangent at curve abscissa
83
- #
84
- # abstract
85
- #
86
- # must be defined
87
- def tangent( abscissa, container=nil )
88
- raise NotImplementedError.new("#{self.class.name}#tangent is an abstract method.")
89
- end
90
-
91
- # must compute the acceleration at curve abscissa
92
- #
93
- # abstract
94
- #
95
- # must be defined
96
- def acc( abscissa, container=nil )
97
- raise NotImplementedError.new("#{self.class.name}#acc is an abstract method.")
98
- end
99
-
100
- # must return the length at abscissa, or total length if abscissa nil
101
- #
102
- # abstract
103
- #
104
- # must be defined
105
- def length(abscissa=nil)
106
- raise NotImplementedError.new("#{self.class.name}#length is an abstract method.")
107
- end
108
-
109
- # default style of a curve, as stroked with stroke width 1% of length
110
- def default_style
111
- return Style[ :stroke, Color.black, :strokewidth, self.length / 100.0 ]
112
- end
113
-
114
- # compute the rotation at curve abscissa, or directly from tangent (for frame computation speed up),
115
- # as angle between tangent0 angle and tangent( abscissa ) (or tangent) angle
116
- def rotation( abscissa, tangent=nil )
117
- if not tangent
118
- tangent = self.tangent( abscissa )
119
- end
120
- return (tangent.angle - self.tangent0_angle)
121
- end
122
-
123
- # must compute the scale at curve abscissa, or directly from tangent (for frame computation speed up)
124
- # as ratio between tangent0 size and tangent( abscissa ) (or tangent) size
125
- def scale( abscissa, tangent=nil )
126
- if not tangent
127
- tangent = self.tangent( abscissa )
128
- end
129
- result = 0.0
130
- if not self.tangent0_length == 0.0
131
- result = (tangent.r / self.tangent0_length)
132
- end
133
- return result
134
- end
135
-
136
- def tangent0
137
- if not @tangent0
138
- @tangent0 = self.tangent( 0.0 )
139
- end
140
- return @tangent0
141
- end
142
-
143
- # TODO : must be cached in vector
144
- def tangent0_angle
145
- if not @tangent0_angle
146
- @tangent0_angle = self.tangent0.angle
147
- end
148
- return @tangent0_angle
149
- end
150
-
151
- # TODO : must be cached in vector
152
- def tangent0_length
153
- if not @tangent0_length
154
- @tangent0_length = self.tangent0.r
155
- end
156
- return @tangent0_length
157
- end
158
-
159
- # compute frame vector at abscissa t, that is [curve.point( t ), curve.tangent( t ) ]
160
- def framev( t )
161
- return [self.point( t ), self.tangent( t ) ]
162
- end
163
-
164
- # compute frame at abscissa t
165
- def frame( t )
166
- point, tangent = self.framev( t )
167
- return Frame[ :center, point, :vector, tangent, :rotation, self.rotation( nil, tangent ), :scale, self.scale( nil, tangent ) ]
168
- end
169
-
170
- # compute normal at abscissa t
171
- #
172
- # do tangent.ortho
173
- def normal( t )
174
- return self.tangent( t ).ortho
175
- end
176
-
177
- # compute normal acceleration at abscissa t
178
- def acc_normal( t )
179
- normal = self.normal( t ).norm
180
- result = self.acc( t ).inner_product( normal )
181
- return result
182
- end
183
-
184
- # compute curvature at abscissa t
185
- def curvature( t )
186
- acc_normal = self.acc_normal( t )
187
- if acc_normal == 0.0
188
- return 0.0
189
- end
190
- return 1.0 / (self.tangent( t ).r / acc_normal )
191
- end
192
-
193
- # shortcut method to map frames from abscissas
194
- def frames (abscissas)
195
- return abscissas.map { |abscissa| self.frame( abscissa ) }
196
- end
197
-
198
- # shortcut method to map points from abscissas
199
- def points (abscissas)
200
- result = abscissas.map { |abscissa| self.point( abscissa ) }
201
- return result
202
- end
203
-
204
- # shortcut method to map tangents from abscissas
205
- def tangents (abscissas)
206
- return abscissas.map { |abscissa| self.tangent( abscissa ) }
207
- end
208
-
209
- # shortcut method, map of normal
210
- def normals( indexes )
211
- return indexes.map {|i| self.normal( i )}
212
- end
213
-
214
- end
215
-
216
-
217
- # Line class
218
- # = Intro
219
- # Used to draw polylines and polygons
220
- # = Attributes
221
- # attribute :points, [V2D[0.0, 0.0], V2D[1.0, 1.0]]
222
- # WARNING : getter "points" is not defined, because is defined as Curve.points( abscissa ) !!!
223
- # = Example
224
- # line = Line[ :points, [V2D::O, V2D::X] ]
225
- class Line < Curve
226
- attribute :points, [V2D[0.0, 0.0], V2D[1.0, 1.0]]
227
-
228
- def initialize (*args) #:nodoc:
229
- super( *args )
230
- self.init_tangents
231
- end
232
-
233
- def init_tangents #:nodoc:
234
- index = 0
235
- @tangents = Array.new
236
- @points.pairs { |p1, p2|
237
- @tangents[ index ] = (p2-p1).norm
238
- index += 1
239
- }
240
- end
241
-
242
- # return the total length of the polyline
243
- def length
244
- if not @length
245
- @length = 0.0
246
- @points.pairs do |p1, p2|
247
- @length += (p1 - p2).r
248
- end
249
- end
250
- return @length
251
- end
252
-
253
- # compute line point at abscissa
254
- # Line[ :points, [V2D::O, V2D::X] ].point( 0.3 ) => V2D[0.0,0.3]
255
- def point (abscissa, container=nil)
256
- container ||= V2D[]
257
- piece1 = abscissa.to_int
258
- if piece1 == @points.size - 1
259
- container.xy = @points[-1]
260
- else
261
- abscissa -= piece1
262
- cpoints = @points.slice( piece1, 2 )
263
- container.xy = [(cpoints[0].x..cpoints[1].x).sample( abscissa ),
264
- (cpoints[0].y..cpoints[1].y).sample( abscissa )]
265
- end
266
- return container
267
- end
268
-
269
- # redefining to discriminate between @points and map.point
270
- def points(arg=nil)
271
- if not arg
272
- return @points
273
- else
274
- super(arg)
275
- end
276
- end
277
-
278
- # compute line tangent at abscissa
279
- def tangent (abscissa, container=nil)
280
- container ||= V2D[]
281
- container.xy = @tangents[abscissa.to_int]
282
- return container
283
- end
284
-
285
- # acc V2D.O
286
- def acc( abscissa, container=nil )
287
- container ||= V2D[]
288
- container.xy = [0.0,0.0]
289
- return container
290
- end
291
-
292
- # compute viewbox of the line
293
- #
294
- # simply call V2D.viewbox on :points
295
- def viewbox
296
- return V2D.viewbox( @points )
297
- end
298
-
299
- # translate a line of v offset, v being a vector
300
- #
301
- # return a new line with every point of :points translated
302
- def translate( v )
303
- return Line[ :points, @points.map {|ext| ext + v } ]
304
- end
305
-
306
- # reverse a line
307
- #
308
- # return a new line with :points reversed
309
- def reverse
310
- return Line[ :points, @points.reverse ]
311
- end
312
-
313
- # return line svg description
314
- def svg
315
- path = "M #{points[0].x} #{points[0].y} "
316
- @points[1..-1].each { |p|
317
- path += "L #{p.x} #{p.y}"
318
- }
319
- return "<path d=\"" + path + "\"/>"
320
- end
321
-
322
- include Samplable
323
- alias apply_sample point
324
- end
325
-
326
- # Circle class
327
- # = Intro
328
- # define a circle curve
329
- # = Attributes
330
- # attribute :center, V2D[0.0,0.0]
331
- # attribute :radius, 1.0
332
- # attribute :initangle, 0.0
333
- # = Example
334
- # c = Circle[ :center, V2D::O, :radius, 1.0 ] # equiv Circle[]
335
- class Circle < Curve
336
- attribute :center, V2D[0.0,0.0]
337
- attribute :radius, 1.0
338
- attribute :initangle, 0.0
339
-
340
- # Circle builder from points diametraly opposed
341
- # Circle.diameter( V2D[-1.0,0.0], V2D[1.0,0.0] ) == Circle[ :center, V2D::O, :radius, 1.0 ]
342
- def Circle.diameter( p1, p2 )
343
- initangle = ( p1 - p2 ).angle
344
- return Circle[ :center, (p1 + p2)/2.0, :radius, (p1 - p2).r/2.0, :initangle, initangle ]
345
- end
346
-
347
- # compute length of the circle
348
- def length
349
- if not @length
350
- @length = 2.0 * Math::PI * self.radius
351
- end
352
- return @length
353
- end
354
-
355
- # shortcut method to retun center.x
356
- def cx
357
- return self.center.x
358
- end
359
-
360
- # shortcut method to retun center.y
361
- def cy
362
- return self.center.y
363
- end
364
-
365
- # viewbox of the circle
366
- def viewbox
367
- return [ self.cx - self.radius,
368
- self.cy - self.radius,
369
- self.cx + self.radius,
370
- self.cy + self.radius ]
371
- end
372
-
373
- # size of the circle
374
- def size
375
- return [ self.radius, self.radius ]
376
- end
377
-
378
- def rotate( angle )
379
- return Circle[:center, self.center, :radius, self.radius, :initangle, self.initangle + angle]
380
- end
381
-
382
- # svg description of the circle
383
- def svg
384
- template = '<circle cx="%cx%" cy="%cy%" r="%r%"/>'
385
- return template.subreplace( {"%cx%" => cx,
386
- "%cy%" => cy,
387
- "%r%" => radius} )
388
- end
389
-
390
- # compute point at abscissa
391
- def point (abscissa, container=nil)
392
- angle = Range::Angle.sample( abscissa ) + @initangle
393
- container ||=V2D[]
394
- container.x = self.cx + self.radius * Math.cos( angle )
395
- container.y = self.cy + self.radius * Math.sin( angle )
396
- return container
397
- end
398
-
399
- # compute tangent at abscissa
400
- def tangent( abscissa, container=nil )
401
- angle = Range::Angle.sample( abscissa ) + @initangle
402
- container ||=V2D[]
403
- container.x = -self.radius * Math.sin( angle )
404
- container.y = self.radius * Math.cos( angle )
405
- return container
406
- end
407
-
408
- # compute acc at abscissa
409
- def acc( abscissa, container=nil )
410
- angle = Range::Angle.sample( abscissa ) + @initangle
411
- container ||=V2D[]
412
- container.x = -self.radius * Math.cos( angle )
413
- container.y = -self.radius * Math.sin( angle )
414
- return container
415
- end
416
-
417
-
418
- include Samplable
419
- alias apply_sample point
420
- end
421
- end
data/lib/spiral.rb DELETED
@@ -1,72 +0,0 @@
1
- # File dedicated to Spiral curves
2
- # - Spiral
3
- # - SpiralParam
4
- # - SpiralFrise
5
-
6
- require 'shape'
7
-
8
- module XRVG
9
-
10
- # abstract class to define spiral types
11
- #
12
- # use compute_radius to compute nsamples reference points, before interpolating with SimpleBezier
13
- class GSpiral < BezierBuilder
14
- attribute :center, V2D::O, V2D
15
- attribute :ext, V2D::O + V2D::X, V2D
16
- attribute :curvature, 1.0
17
- attribute :nsamples, 100
18
-
19
- def compute_radius( r0, angle0, curvature, angle )
20
- raise NotImplementedError.new("#{self.class.name}#compute_radius is an abstract method.")
21
- end
22
-
23
- def maxangle( r0, angle0, curvature )
24
- raise NotImplementedError.new("#{self.class.name}#maxangle is an abstract method.")
25
- end
26
-
27
- def compute()
28
- points = []
29
- r0, angle0 = (@ext - @center).coords(:polar)
30
- maxangle = self.maxangle( r0, angle0, @curvature )
31
- [(r0..0.0), (angle0..maxangle)].samples( self.nsamples ) do |radius, angle|
32
- r = self.compute_radius( r0, angle0, @curvature, angle )
33
- point = V2D.polar( r, angle )
34
- points.push( @center + point )
35
- end
36
- return SimpleBezier.build( :support, points ).data
37
- end
38
- end
39
-
40
- # at angle angle0, r = r0
41
- # at angle angle0 + curvature, r = 0.0
42
- class SpiralLinear < GSpiral
43
-
44
- def maxangle( r0, angle0, curvature )
45
- return (angle0 + curvature)
46
- end
47
-
48
- def compute_radius( r0, angle0, curvature, angle )
49
- return r0 * (1.0 - ( 1.0 + (Math.exp( - 10.0 * ( angle- angle0) / curvature ) ) ) * ( angle - angle0 ) /curvature )
50
- # return r0 * (1.0 - ( angle - angle0 ) /curvature )
51
- end
52
-
53
- end
54
-
55
- # curvature is in number of tour before center % extremity
56
- class SpiralLog < GSpiral
57
-
58
- def nsamples
59
- return (curvature * 15.0).to_i
60
- end
61
-
62
- def compute_radius( r0, angle0, curvature, angle )
63
- return r0 * Math.exp( -(angle-angle0) / curvature )
64
- end
65
-
66
- def maxangle( r0, angle0, curvature )
67
- return angle0 - curvature * Math.log( 0.001 )
68
- end
69
- end
70
-
71
- end #XRVG
72
-
data/lib/style.rb DELETED
@@ -1,76 +0,0 @@
1
- #
2
- # See +Style+
3
- #
4
- require 'attributable'
5
- require 'utils'
6
- require 'color'
7
-
8
- module XRVG
9
- #
10
- # Style class
11
- #
12
- # Used to define the way an object has to be rendered.
13
- # For the moment, only the following style attributes are really useful :
14
- # - attribute :fill, "none", [String, Color, Gradient]
15
- # - attribute :stroke, "none", [String, Color, Gradient]
16
- # - attribute :strokewidth, 1.0
17
- #
18
- # For example :
19
- # render.add( Circle[], Style[ :fill, Color.red ] )
20
- # render.add( Circle[], Style[ :stroke, Color.red ] )
21
- class Style
22
- include Attributable
23
- # attribute :opacity, 1.0
24
- attribute :fill, "none", [String, Color, Gradient]
25
- # attribute :fillopacity, 1.0
26
- attribute :stroke, "none", [String, Color, Gradient]
27
- attribute :strokewidth, 1.0
28
- # attribute :strokeopacity, 1.0
29
-
30
- def fillopacity()
31
- if @fill.is_a? Color
32
- return @fill.a
33
- end
34
- return 1.0
35
- end
36
-
37
- def strokeopacity()
38
- if @stroke.is_a? Color
39
- return @stroke.a
40
- end
41
- return 1.0
42
- end
43
-
44
-
45
- def svgfill
46
- if fill.is_a? Color
47
- return fill.svg
48
- elsif fill.is_a? Gradient
49
- return "%fillgradient%"
50
- else
51
- return fill
52
- end
53
- end
54
-
55
- def svgstroke
56
- if stroke.is_a? Color
57
- return stroke.svg
58
- elsif stroke.is_a? Gradient
59
- return "%strokegradient%"
60
- else
61
- return stroke
62
- end
63
- end
64
-
65
- def svgline
66
- template = 'style="opacity:%opacity%;fill:%fill%;fill-opacity:%fillopacity%;stroke:%stroke%;stroke-width:%strokewidth%;stroke-opacity:%strokeopacity%"'
67
-
68
- return template.subreplace( {"%opacity%" => 1.0,
69
- "%fill%" => svgfill,
70
- "%fillopacity%" => fillopacity,
71
- "%stroke%" => svgstroke,
72
- "%strokewidth%" => strokewidth,
73
- "%strokeopacity%" => strokeopacity} )
74
- end
75
- end
76
- end
data/lib/xrvg.rb DELETED
@@ -1,46 +0,0 @@
1
- # This file has to be included if you want to start a XRVG script
2
- #
3
- # Please refer to README for XRVG introduction
4
-
5
- # XRVG version (used in rakefile)
6
- XRVG_VERSION = "0.0.6"
7
-
8
- # XRVG namespace
9
- module XRVG
10
- end
11
-
12
- # Standard Ruby extensions
13
- require 'enumerator'
14
-
15
- # XRVG Infrastructure
16
- require 'trace'
17
-
18
- # XRVG new mixins
19
- require 'samplation'
20
- require 'attributable'
21
- require 'interpolation'
22
- require 'parametriclength'
23
-
24
- # XRVG base class extensions
25
- require 'utils'
26
- require 'geometry2D'
27
-
28
- # XRVG base classes
29
- require 'color'
30
- require 'frame'
31
- require 'shape'
32
- require 'render'
33
- require 'bezier'
34
-
35
- # XRVG extensions
36
- require 'fitting'
37
- require 'bezierbuilders'
38
- require 'beziermotifs'
39
- require 'beziertools'
40
- require 'interbezier'
41
- require 'geovariety'
42
- require 'spiral'
43
- # require 'graph'
44
-
45
-
46
-