xrvg 0.0.7 → 0.0.8

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/render.rb ADDED
@@ -0,0 +1,266 @@
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 or style == :default
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
data/lib/samplation.rb CHANGED
@@ -300,13 +300,56 @@ module Splittable
300
300
  # apply_register( :split, :apply_splits )
301
301
  end
302
302
 
303
+ # -------------------------------------------------------------
304
+ # Samplation synchronisation
305
+ # -------------------------------------------------------------
306
+ class SyncS
307
+ attr_accessor :items
308
+
309
+ include Samplable
310
+ include Splittable
311
+
312
+ # FloatFunctor overloading to synchronize content sampling and splitting
313
+ def compute( inputs, type, &block )
314
+ return self.items.map {|v| v.compute( inputs, type )}.forzip(nil,&block)
315
+ end
316
+
317
+ def addfilter( newfilter )
318
+ self.items.each {|v| v.addfilter( newfilter )}
319
+ return self
320
+ end
321
+
322
+
323
+ # create a new samplation synchronizer
324
+ # syncs = SyncS[ Range.O, Range.O.geo( 5.0 )]
325
+ def SyncS.[]( *args )
326
+ return SyncS.new(*args)
327
+ end
328
+
329
+ # builder
330
+ def initialize( *args )
331
+ newitems = []
332
+ args.each do |item|
333
+ if item.is_a? Array
334
+ item = Roller[ *item ]
335
+ end
336
+ newitems << item
337
+ end
338
+ @items = newitems
339
+ end
340
+ end
341
+
342
+
343
+ # -------------------------------------------------------------
344
+ # Filter interface and classes
345
+ # -------------------------------------------------------------
303
346
 
304
347
  # Filter class
305
348
  # = Intro
306
349
  # Filter class allows to call generically a method with arg between 0.0..0.1 on a given object, for use in a +FloatFunctor+ context.
307
350
  # = Example
308
351
  # this allow to do for example
309
- # [bezier1.filter(:point), bezier1.filter(:tangent), palette].samples( 10 ) do |point, tangent, color|
352
+ # SyncS[bezier1.filter(:point), bezier1.filter(:tangent), palette].samples( 10 ) do |point, tangent, color|
310
353
  class Filter
311
354
  include Samplable
312
355