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/lib/fitting.rb DELETED
@@ -1,203 +0,0 @@
1
- #
2
- # Fitting file. See +Fitting+
3
- #
4
-
5
- require 'matrix'; # for matrix inversion
6
- require 'bezier.rb'; # for error computation
7
-
8
- module XRVG
9
- #
10
- # = Fitting computation class
11
- # == Intro
12
- # Used to compute cubic curve fitting on a list of points (that is sampling inverse operation). Only 2D.
13
- # == Example
14
- # Compute the most fitting single piece bezier curve given list of points
15
- # bezier = Fitting.compute( points )
16
- # Compute multipieces bezier curve given list of points
17
- # bezier = Fitting.adaptative_compute( points )
18
- class Fitting
19
-
20
- # compute first parameter t estimated values from length between consecutive points
21
- def Fitting.initparameters( pointlist, parameters=nil ) #:nodoc:
22
- lengths = [0.0]
23
- pointlist.pairs do |p1, p2|
24
- lengths.push( lengths[-1] + (p1-p2).r )
25
- end
26
- tlength = lengths[-1]
27
- if not parameters
28
- if not tlength == 0.0
29
- parameters = lengths.map {|length| length / tlength}
30
- else
31
- parameters = [0.0] * pointlist.length
32
- end
33
- end
34
- return [parameters, tlength]
35
- end
36
-
37
- # compute control points from polynomial bezier representation
38
- #
39
- # a, b, c, d are such as
40
- # piece( t ) = at3 + bt2 + ct + d
41
- def Fitting.bezierpiece( a, b, c, d )
42
- p0 = d
43
- p1 = p0 + c / 3.0
44
- p2 = p1 + c / 3.0 + b / 3.0
45
- p3 = p0 + c + b + a
46
- return [p0, p1, p2, p3]
47
- end
48
-
49
-
50
- # Base method
51
- #
52
- # Given a pointlist, compute the closest matching cubic bezier curve
53
- #
54
- # Result is in the form [p1, pc1, pc2, p2], with [p1, pc1, pc2, p2] V2D
55
- #
56
- # maxerror is normalized with curve length. In case of good match (that is pointlist can be modelized by cubic bezier curve),
57
- # result error will be under maxerror. If not, result may be above maxerror. In that case, computation is stopped because error
58
- # no longer decrease, or because iteration is too long.
59
- def Fitting.compute( pointlist, maxerror=0.01, maxiter=100 )
60
- parameters, tlength = Fitting.initparameters( pointlist )
61
- perror = 1.0
62
- niter = 0
63
- while true
64
- bezier, coeffs = Fitting.iterate( pointlist, parameters )
65
- error = Fitting.error( bezier, pointlist, parameters ) / tlength
66
- parameters = Fitting.renormalize( bezier, coeffs, pointlist, parameters )
67
- if (error < maxerror || (error-perror).abs < 0.00001 || niter > maxiter )
68
- break
69
- end
70
- niter += 1
71
- end
72
- return bezier
73
- end
74
-
75
- # adaptative computation with automatic splitting if error not low enough, or if convergence is not fast enough
76
- #
77
- #
78
- def Fitting.adaptative_compute( pointlist, maxerror=0.0001, maxiter=10, tlength=nil )
79
- parameters, tlengthtmp = Fitting.initparameters( pointlist )
80
- if parameters == [0] * pointlist.length
81
- return [Bezier.single(:vector, pointlist[0], V2D::O, pointlist[0], V2D::O),0.0]
82
- end
83
- tlength ||= tlengthtmp
84
- niter = 0
85
- bezier = nil
86
- while true
87
- bezier, coeffs = Fitting.iterate( pointlist, parameters )
88
- error = Fitting.error( bezier, pointlist, parameters ) / tlength
89
- parameters = Fitting.renormalize( bezier, coeffs, pointlist, parameters )
90
-
91
- # pointlist.length > 8 because matching with a bezier needs at least 4 points
92
- if (niter > maxiter and error > maxerror and pointlist.length > 8)
93
- pointlists = [pointlist[0..pointlist.length/2 - 1], pointlist[pointlist.length/2 - 1 ..-1]]
94
- beziers = []
95
- errors = []
96
- pointlists.each do |subpointlist|
97
- subbezier, suberror = Fitting.adaptative_compute( subpointlist, maxerror, maxiter, tlength )
98
- beziers << subbezier
99
- errors << suberror
100
- end
101
- bezier = beziers.sum
102
- error = errors.max
103
- break
104
- elsif (error < maxerror || niter > maxiter)
105
- break
106
- end
107
- perror = error
108
- niter += 1
109
- end
110
- return [bezier, error]
111
- end
112
-
113
- # algo comes from http://www.tinaja.com/glib/bezdist.pdf
114
- def Fitting.renormalize( bezier, coeffs, pointlist, parameters )
115
- a3, a2, a1, a0 = coeffs
116
- dxdu = Proc.new {|u| 3.0*a3.x*u**2 + 2.0*a2.x*u + a1.x}
117
- dydu = Proc.new {|u| 3.0*a3.y*u**2 + 2.0*a2.y*u + a1.y}
118
- container = V2D[]
119
- z = Proc.new {|u,p4| p = bezier.point( u, container, :parameter ); (p.x - p4.x) * dxdu.call( u ) + (p.y - p4.y) * dydu.call( u )}
120
- newparameters = []
121
- [pointlist, parameters].forzip do |point, parameter|
122
- u1 = parameter
123
- if parameter < 0.99
124
- u2 = parameter + 0.01
125
- else
126
- u2 = parameter - 0.01
127
- end
128
- z1 = z.call(u1,point)
129
- z2 = z.call(u2,point)
130
- if z1 == z2
131
- u2 += 0.01
132
- z2 = z.call(u2,point)
133
- end
134
- if z1 == z2
135
- u2 -= 0.01
136
- z2 = z.call(u2,point)
137
- end
138
- newparameters << (z2 * u1 - z1 * u2)/(z2-z1)
139
- end
140
- return newparameters
141
- end
142
-
143
- # error is max error between points in pointlist and points sampled from bezier with parameters
144
- def Fitting.error( bezier, pointlist, parameters )
145
- maxerror = 0.0
146
- container = V2D[]
147
- [pointlist, parameters].forzip do |point, parameter|
148
- # Trace("point #{point.inspect} parameter #{parameter}")
149
- error = (point - bezier.point( parameter, container, :parameter )).r
150
- if error > maxerror
151
- maxerror = error
152
- end
153
- end
154
- # Trace("Fitting.error #{maxerror}")
155
- return maxerror
156
- end
157
-
158
- # iterate method compute new bezier parameters from pointlist and previous bezier parameters
159
- #
160
- # Algo comes from http://www.tinaja.com/glib/bezdist.pdf
161
- #
162
- # TODO : optimized
163
- def Fitting.iterate( pointlist, parameters )
164
- p0 = pointlist[0]
165
- p1 = pointlist[-1]
166
-
167
- sumt0 = parameters.map{ |t| t**0.0 }.sum
168
- sumt1 = parameters.map{ |t| t**1.0 }.sum
169
- sumt2 = parameters.map{ |t| t**2.0 }.sum
170
- sumt3 = parameters.map{ |t| t**3.0 }.sum
171
- sumt4 = parameters.map{ |t| t**4.0 }.sum
172
- sumt5 = parameters.map{ |t| t**5.0 }.sum
173
- sumt6 = parameters.map{ |t| t**6.0 }.sum
174
-
175
- psumt1 = [pointlist, parameters].forzip.foreach(2).map {|point, t| point * (t**1.0) }.inject(V2D::O){|sum, item| sum + item}
176
- psumt2 = [pointlist, parameters].forzip.foreach(2).map {|point, t| point * (t**2.0) }.inject(V2D::O){|sum, item| sum + item}
177
- psumt3 = [pointlist, parameters].forzip.foreach(2).map {|point, t| point * (t**3.0) }.inject(V2D::O){|sum, item| sum + item}
178
-
179
- coeff11 = sumt6 - 2 * sumt4 + sumt2
180
- coeff12 = sumt5 - sumt4 - sumt3 + sumt2
181
-
182
- coeff21 = coeff12
183
- coeff22 = sumt4 - 2 * sumt3 + sumt2
184
-
185
- result1 = (p0 - p1) * (sumt4 - sumt2) - p0 * (sumt3 - sumt1) + psumt3 - psumt1
186
- result2 = (p0 - p1) * (sumt3 - sumt2) - p0 * (sumt2 - sumt1) + psumt2 - psumt1
187
-
188
- matrix = Matrix[ [coeff11, coeff12], [coeff21, coeff22] ]
189
- matrixinv = matrix.inverse
190
- ax, bx = (matrixinv * Vector[result1.x, result2.x])[0..-1]
191
- ay, by = (matrixinv * Vector[result1.y, result2.y])[0..-1]
192
-
193
- a = V2D[ax, ay]
194
- b = V2D[bx, by]
195
- d = p0
196
- c = p1- (a + b + p0)
197
-
198
- piece = Fitting.bezierpiece( a, b, c, d )
199
- return [Bezier.raw( *piece ), [a, b, c, d] ]
200
- end
201
- end
202
-
203
- end # end XRVG
data/lib/frame.rb DELETED
@@ -1,33 +0,0 @@
1
- # frame.rb file
2
- #
3
- # See +Frame+
4
- require 'attributable'
5
-
6
- module XRVG
7
- #
8
- # Frame class
9
- # = Intro
10
- # Defines a local geometry. Used by +Curve+ interface.
11
- # = Attributes
12
- # attribute :center
13
- # attribute :vector
14
- # attribute :rotation
15
- # attribute :scale
16
- class Frame
17
- include Attributable
18
- attribute :center
19
- attribute :vector
20
- attribute :rotation
21
- attribute :scale
22
-
23
- def ==(other)
24
- if self.center == other.center and
25
- self.vector == other.vector and
26
- self.rotation == other.rotation and
27
- self.scale == other.scale
28
- return true
29
- end
30
- return false
31
- end
32
- end
33
- end
data/lib/geovariety.rb DELETED
@@ -1,128 +0,0 @@
1
- # File for GeoVariety
2
- # See (also):
3
- # - InterBezier
4
- # - Offsetvariety
5
- # - FuseauVariety
6
-
7
- require 'interbezier'
8
-
9
- module XRVG
10
-
11
- # = GeoVariety abstract module
12
- # == Principle
13
- # Base module to define geometrical spaces or canvas different from simple euclidean one to draw curves on.
14
- # It provides three different services:
15
- # - point computation
16
- # - geodesic computation
17
- # - arbitrary bezier computation, this one by computing sampling of euclidean curve on the variety, and then fitting point
18
- # sequence with FitBezierBuilder
19
- module GeoVariety
20
-
21
- # must be overriden
22
- def point( point )
23
- raise NotImplementedError.new("#{self.class.name}#point is an abstract method.")
24
- end
25
-
26
- # must be overriden
27
- def line( x1, x2, y )
28
- raise NotImplementedError.new("#{self.class.name}#line is an abstract method.")
29
- end
30
-
31
- # see GeoVariety module description for algorithm
32
- def bezier( pointrange, bezier )
33
- bezier = bezier.similar( pointrange )
34
- points = bezier.samples( 20 )
35
- points = points.map {|point| self.point( point )}
36
- return FitBezierBuilder[ :points, points ]
37
- end
38
- end
39
-
40
- # = InterBezier GeoVariety implementation
41
- # == Principle
42
- # InterBezier defines a surface by the set of every possible curve sample from one interpolated curve to the other.
43
- # Geodesic corresponds then to one interpolated result, and point to a point of this curve
44
- class InterBezier
45
- include GeoVariety
46
-
47
- # Compute the geodesic curve by doing self.sample with y coord, and then compute point of this curve with length "x"
48
- def point( point )
49
- curve = self.sample( point.y )
50
- return curve.point( point.x )
51
- end
52
-
53
- # Compute the geodesic subcurve with y coord between x1 and x2
54
- def line( x1, x2, y )
55
- # Trace("interbezier line x1 #{x1} x2 #{x2} y #{y}")
56
- curve = self.sample( y )
57
- result = curve.apply_split( x1, x2 )
58
- # Trace("interbezier line result #{result.inspect}")
59
- return result
60
- end
61
-
62
- end
63
-
64
- # = OffsetVariety implementation
65
- # == Principle
66
- # Geovariety is defined by the set of offset curves from -ampl to +ampl
67
- # == Extension
68
- # Parameter could be a :samplable parameter : in that case, ampl will vary
69
- #
70
- # Another extension would be to parametrize range straightforwardly
71
- #
72
- # Finally, the two previous remarks must be synthetized :-)
73
- class OffsetVariety
74
- include Attributable
75
- attribute :support
76
- attribute :ampl, nil, Float
77
-
78
- include GeoVariety
79
-
80
- # builder: init static offset range with (-self.ampl..self.ampl)
81
- def initialize( *args )
82
- super( *args )
83
- @range = (-self.ampl..self.ampl)
84
- end
85
-
86
- # point computed by computing offset curve with ampl y coord mapped onto offset range, and then sampling the curve with x coord
87
- def point( point )
88
- curve = Offset[ :support, @support, :ampl, @range.sample( point.y ) ]
89
- return curve.point( point.x )
90
- end
91
-
92
- # subgeodesic computed by computing offset curve with ampl y coord
93
- def line( x1, x2, y )
94
- curve = Offset[ :support, @support, :ampl, @range.sample( y ) ]
95
- return curve.apply_split( x1, x2 )
96
- end
97
-
98
- end
99
-
100
- # = FuseauVariety implementation
101
- # == Principle
102
- # Same as OffsetVariety, with Fuseau shape, that is with linearly varying ampl range
103
- class FuseauVariety
104
- include Attributable
105
- attribute :support
106
- attribute :ampl, nil, Float
107
-
108
- include GeoVariety
109
-
110
- def initialize( *args )
111
- super( *args )
112
- @range = (-self.ampl..self.ampl)
113
- end
114
-
115
- def point( point )
116
- curve = Offset[ :support, @support, :ampl, (0.0..@range.sample( point.y ))]
117
- return curve.point( point.x )
118
- end
119
-
120
- def line( x1, x2, y )
121
- curve = Offset[ :support, @support, :ampl, (0.0..@range.sample( y ))]
122
- return curve.apply_split( x1, x2 )
123
- end
124
- end
125
-
126
- end # XRVG
127
-
128
- # see geovariety_test to see tests
data/lib/interbezier.rb DELETED
@@ -1,87 +0,0 @@
1
- require 'bezier'
2
-
3
- module XRVG
4
- class InterBezier
5
- include Attributable
6
- attribute :bezierlist
7
-
8
- include Interpolation
9
-
10
- def initialize( *args )
11
- super( *args )
12
- self.init_interpolation_structures
13
- end
14
-
15
- def init_interpolation_structures
16
- beziers = []
17
- indexes = []
18
- @bezierlist.foreach do |index, bezier|
19
- beziers.push( bezier )
20
- indexes.push( index )
21
- end
22
-
23
- lengthH = {}
24
- alllengths = []
25
- beziers.each do |bezier|
26
- lengths = bezier.piecelengths
27
- Trace("bezier lengths #{lengths.inspect}")
28
- lengthH[ bezier ] = lengths
29
- alllengths += lengths
30
- end
31
- alllengths = Float.sort_float_list( alllengths )
32
- Trace("alllengths #{alllengths.inspect}")
33
-
34
- newbezierlist = []
35
- beziers.each do |bezier|
36
- newpieces = []
37
- initlengths = lengthH[ bezier ]
38
- alllengths.pairs do |l1, l2|
39
- newpieces += bezier.subbezier( l1, l2 ).pieces
40
- end
41
- newbezier = Bezier[ :pieces, newpieces ]
42
- newbezierlist << newbezier
43
- end
44
-
45
- Trace("newbezierlist #{newbezierlist.length}")
46
- beziers = newbezierlist
47
- bezierpointlists = beziers.map {|bezier| bezier.pointlist(:vector) }
48
- Trace("bezierpointlists #{bezierpointlists.map {|list| list.length}.inspect}")
49
- pointsequencelist = bezierpointlists.forzip
50
- @interpolatorlist = []
51
- pointsequencelist.foreach(beziers.size) do |pointsequence|
52
- interlist = [indexes, pointsequence].forzip
53
- @interpolatorlist.push( Interpolator.new( :samplelist, interlist ) )
54
- end
55
- end
56
-
57
- def interpolate( abs, container=nil )
58
- pieces = []
59
- @interpolatorlist.foreach(4) do |interpiece|
60
- piece = interpiece.map {|inter| inter.interpolate( abs )}
61
- pieces.push( [:vector] + piece )
62
- end
63
- return Bezier.multi( pieces )
64
- end
65
-
66
- include Samplable
67
- alias apply_sample interpolate
68
-
69
- end
70
-
71
- class GradientBezier < InterBezier
72
-
73
- # TODO : does not work !!
74
- def samples( nsamples, &block )
75
- return super( nsamples + 1, &block )
76
- end
77
-
78
- def apply_samples( samples )
79
- samples = super( samples )
80
- result = []
81
- samples.pairs do |bezier1, bezier2|
82
- result.push( ClosureBezier.build( :bezierlist, [bezier1, bezier2.reverse]) )
83
- end
84
- return result
85
- end
86
- end
87
- end # XRVG
data/lib/render.rb DELETED
@@ -1,266 +0,0 @@
1
- #
2
- # Render file. See
3
- # - +Render+ for render "abstraction"
4
- # - +SVGRender+ for effective SVG render
5
-
6
- require 'color'
7
- require 'style'
8
-
9
- module XRVG
10
- # Render abstract class
11
- #
12
- # Is pretty useless for the moment
13
- class Render
14
- include Attributable
15
- attr_accessor :width
16
- attr_accessor :height
17
- end
18
-
19
- # SVG Render class
20
- #
21
- # In charge of generating a svg output file from different object passed to it
22
- # = Use
23
- # Canonical use of the class
24
- # render = SVGRender[ :filename, "essai.svg" ]
25
- # render.add( Circle[] )
26
- # render.end
27
- # = Improvements
28
- # Allows also the "with" syntax
29
- # = Attributes
30
- # attribute :filename, "", String
31
- # attribute :imagesize, "2cm", String
32
- # attribute :background, Color.white, [Color, String]
33
- class SVGRender < Render
34
- attribute :filename, "", String
35
- attribute :imagesize, "2cm", String
36
- attribute :background, "white", [Color, String]
37
- attr_reader :viewbox
38
-
39
- # SVGRender builder
40
- #
41
- # Allows to pass a block, to avoid using .end
42
- # SVGRender.[] do |render|
43
- # render.add( Circle[] )
44
- # end
45
- def SVGRender.[](*args,&block)
46
- result = self.new( *args )
47
- if block
48
- yield result
49
- result.end
50
- end
51
- return result
52
- end
53
-
54
-
55
- def initialize ( *args, &block ) #:nodoc:
56
- super( *args )
57
- @layers = {}
58
- @defs = ""
59
- @ngradients = 0
60
- if @filename.length == 0
61
- @filename = $0.split(".")[0..-2].join(".") + ".svg"
62
- Trace("filename is #{filename}")
63
- end
64
- end
65
-
66
- def layers=( backtofront ) #:nodoc:
67
- @sortlayers = backtofront
68
- @sortlayers.each do |key|
69
- @layers[ key ] = ""
70
- end
71
- end
72
-
73
- def add_content (string, layer) #:nodoc:
74
- if not @layers.key? layer
75
- @layers[ layer ] = ""
76
- end
77
- @layers[ layer ] += string
78
- end
79
-
80
- def svg_template #:nodoc:
81
- return '<?xml version="1.0" standalone="no"?>
82
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
83
- <svg width="%SIZE%" height="%SIZE%" %VIEWBOX% version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
84
- %DEFS%
85
- %BACKGROUND%
86
- %CONTENT%
87
- </svg>'
88
- end
89
-
90
- def add_def (object) #:nodoc:
91
- @defs += object
92
- end
93
-
94
- def add_gradient( gradient ) #:nodoc:
95
- id = "gradient#{@ngradients}"
96
- add_def( gradient.svgdef.subreplace( {"%ID%" => id} ) )
97
- @ngradients += 1
98
- return id
99
- end
100
-
101
- # render fundamental method
102
- #
103
- # used to render an object, with a particular style, on an optional layer.
104
- # render.add( Circle[], Style[ :fill, Color.black ], 1 )
105
- # If style is not provided, render asked to object its default_style, if any
106
- def add(object, style=nil, layer=0, type=:object)
107
- add_content( render( object, style ), layer)
108
- refresh_viewbox( object )
109
- end
110
-
111
- def render (object, style=nil) #:nodoc:
112
- owidth, oheight = object.size
113
-
114
- res = 0.0000001
115
- if owidth < res and oheight < res
116
- return ""
117
- end
118
-
119
- if not style
120
- style = object.default_style
121
- end
122
-
123
- result = "<g #{style.svgline}>\n"
124
- result += object.svg + "\n"
125
- result += "</g>\n"
126
-
127
- # puts "result #{result}"
128
-
129
- if style.fill.is_a? Gradient
130
- gradientID = add_gradient( style.fill )
131
- result = result.subreplace( {"%fillgradient%" => "url(##{gradientID})"} )
132
- end
133
-
134
- if style.stroke.is_a? Gradient
135
- gradientID = add_gradient( style.stroke )
136
- result = result.subreplace( {"%strokegradient%" => "url(##{gradientID})"} )
137
- end
138
- return result
139
- end
140
-
141
- def viewbox #:nodoc:
142
- return @viewbox
143
- end
144
-
145
- def size #:nodoc:
146
- xmin, ymin, xmax, ymax = viewbox
147
- return [xmax - xmin, ymax - ymin]
148
- end
149
-
150
- def refresh_viewbox (object) #:nodoc:
151
- newviewbox = object.viewbox
152
- if newviewbox.length > 0
153
- if @viewbox == nil
154
- @viewbox = newviewbox
155
- else
156
- newxmin, newymin, newxmax, newymax = newviewbox
157
- xmin, ymin, xmax, ymax = viewbox
158
-
159
- if newxmin < xmin
160
- xmin = newxmin
161
- end
162
- if newymin < ymin
163
- ymin = newymin
164
- end
165
- if newxmax > xmax
166
- xmax = newxmax
167
- end
168
- if newymax > ymax
169
- ymax = newymax
170
- end
171
-
172
- @viewbox = [xmin, ymin, xmax, ymax]
173
- end
174
- end
175
- end
176
-
177
- def get_background_svg #:nodoc:
178
- xmin, ymin, width, height = get_carre_viewbox( get_final_viewbox() )
179
- template = '<rect x="%x%" y="%y%" width="%width%" height="%height%" fill="%fill%"/>'
180
- bg = self.background
181
- if bg.respond_to? :svg
182
- bg = bg.svg
183
- end
184
- return template.subreplace( {"%x%" => xmin,
185
- "%y%" => ymin,
186
- "%width%" => width,
187
- "%height%" => height,
188
- "%fill%" => bg} )
189
- end
190
-
191
- def get_final_viewbox #:nodoc:
192
- marginfactor = 0.2
193
- xmin, ymin, xmax, ymax = viewbox()
194
- width, height = size()
195
-
196
- xcenter = (xmin + xmax)/2.0
197
- ycenter = (ymin + ymax)/2.0
198
-
199
- width *= 1.0 + marginfactor
200
- height *= 1.0 + marginfactor
201
-
202
- if width == 0.0
203
- width = 1.0
204
- end
205
- if height == 0.0
206
- height = 1.0
207
- end
208
-
209
- xmin = xcenter - width / 2.0
210
- ymin = ycenter - height / 2.0
211
-
212
- return xmin, ymin, width, height
213
- end
214
-
215
- def get_viewbox_svg #:nodoc:
216
- return viewbox_svg( get_final_viewbox() )
217
- end
218
-
219
- def get_carre_viewbox( viewbox ) #:nodoc:
220
- xmin, ymin, width, height = viewbox
221
- xcenter = xmin + width / 2.0
222
- ycenter = ymin + height / 2.0
223
- maxsize = width < height ? height : width
224
- return [xcenter - maxsize/2.0, ycenter - maxsize/2.0, maxsize, maxsize]
225
- end
226
-
227
- def viewbox_svg( viewbox ) #:nodoc:
228
- xmin, ymin, width, height = viewbox
229
- return "viewBox=\"#{xmin} #{ymin} #{width} #{height}\""
230
- end
231
-
232
- def content #:nodoc:
233
- keys = @sortlayers ? @sortlayers : @layers.keys.sort
234
- return keys.inject("") {|result,key| result += @layers[key]}
235
- end
236
-
237
- def svgdef #:nodoc:
238
- return "<defs>\n#{@defs}\n</defs>\n"
239
- end
240
-
241
- def end () #:nodoc:
242
- svgcontent = content()
243
- svgviewbox = get_viewbox_svg()
244
- svgbackground = get_background_svg()
245
-
246
- content = svg_template().subreplace( {"%VIEWBOX%" => svgviewbox,
247
- "%SIZE%" => @imagesize,
248
- "%DEFS%" => svgdef,
249
- "%BACKGROUND%" => svgbackground,
250
- "%CONTENT%" => svgcontent})
251
-
252
- File.open(filename(), "w") do |f|
253
- f << content
254
- end
255
-
256
- puts "render #{filename()} OK"; # necessary for Emacs to get output name !!!!
257
- end
258
-
259
- def raster () #:nodoc:
260
- # bg = background.format255
261
-
262
- # Kernel.system( "ruby", "svg2png.rb", filename(), "2.0" )
263
- # Kernel.system( "i_view32", filename().subreplace( ".svg" => ".png" ), "/fs" )
264
- end
265
- end
266
- end