Class: HDLRuby::Viz::Node
- Inherits:
-
Object
- Object
- HDLRuby::Viz::Node
- Defined in:
- lib/HDLRuby/hruby_viz.rb
Overview
An Flow node block
Instance Attribute Summary collapse
-
#arrows ⇒ Object
readonly
Returns the value of attribute arrows.
-
#box ⇒ Object
readonly
Returns the value of attribute box.
-
#branches ⇒ Object
readonly
Returns the value of attribute branches.
-
#height ⇒ Object
Returns the value of attribute height.
-
#idC ⇒ Object
readonly
Returns the value of attribute idC.
-
#matrix ⇒ Object
readonly
Returns the value of attribute matrix.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#port_width ⇒ Object
readonly
Returns the value of attribute port_width.
-
#routes ⇒ Object
readonly
Returns the value of attribute routes.
-
#scale ⇒ Object
Returns the value of attribute scale.
-
#successor ⇒ Object
Returns the value of attribute successor.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
-
#width ⇒ Object
Returns the value of attribute width.
-
#xpos ⇒ Object
Returns the value of attribute xpos.
-
#ypos ⇒ Object
Returns the value of attribute ypos.
Instance Method Summary collapse
-
#arrow_svg(x0, y0, x1, y1) ⇒ Object
Generate an arrow description SVG text for connection nodes.
-
#assign_svg(n) ⇒ Object
Generate an assign description SVG text for node +n+.
-
#block_svg(n) ⇒ Object
Generate a block description SVG text for node +n+.
-
#case_svg(n, no = false) ⇒ Object
Generate a case description SVG text for node +n+, where +no+ tells if there is an else branch.
-
#fill_place_matrix(matrix, stmnt, r, c, w, h) ⇒ Object
Fill the place matrix with statement +stmnt+ at position +r+,+c+ stretched by +w+,+h+.
-
#if_svg(n, no = false) ⇒ Object
Generate an if description SVG text for node +n+, where +no+ tells if there is an else branch.
-
#initialize(type, parent = nil, name = nil) ⇒ Node
constructor
A new instance of Node.
-
#move_deep(dx, dy) ⇒ Object
Move deeply the position.
-
#next_place_matrix(matrix, c0, r, c) ⇒ Object
Find the next free position in the place matrix +matrix+.
-
#next_row_matrix(matrix, c0, r) ⇒ Object
Find the next row free from column +c0+ starting for position row +r+ in the place matrix +matrix+.
-
#number_statements ⇒ Object
Get the number of statements within and from current node.
-
#operator_svg(n) ⇒ Object
Generate an operator description SVG text for node +n+.
-
#place_and_route_deep ⇒ Object
Deeply place and route.
-
#place_and_route_par(x = 0, y = 0) ⇒ Object
Do the full place and route for a par block with initial position +x+ and +y+.
-
#place_and_route_seq(x = 1, y = 1) ⇒ Object
Do the full place and route for a seq block with initial position +x+ and +y+.
-
#place_and_route_statement_matrix(stmnt, matrix, r, c) ⇒ Object
Place statements in a matrix from statement +stmnt+ at using +matrix+ as guide for current row +r+ and column +c+.
-
#place_and_route_statement_vertically(stmnt, x, y, cond_succ = nil) ⇒ Object
Place statements vertically from statement +stmnt+ at position +x+, +y+.
-
#print_svg(n) ⇒ Object
Generate a print description SVG text for node +n+.
-
#repeat_svg(n) ⇒ Object
Generate a repeat description SVG text for node +n+.
-
#statement_svg_deep(stmnt, no = false) ⇒ Object
Generate recursively the content of a flow from statement +stmnt+, where +no+ tells if there is an else branch.
-
#terminal_svg(n) ⇒ Object
Generate a terminal description SVG for node +n+.
-
#terminate_svg(n) ⇒ Object
Generate a terminate description SVG text for node +n+.
-
#to_s(spc = "") ⇒ Object
Convert to a string.
-
#to_s_control ⇒ Object
Convert to a string as a control flow, i.e., the successor is also converted.
-
#to_svg(top = true, tx = 0, ty = 0, width = nil, height = nil) ⇒ Object
Generate in SVG format the graphical representation of the flow.
-
#wait_svg(n) ⇒ Object
Generate a wait description SVG text for node +n+.
Constructor Details
#initialize(type, parent = nil, name = nil) ⇒ Node
Returns a new instance of Node.
3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3057 def initialize(type, parent = nil, name = nil) @type = type.to_sym if name then @name = name.to_s else @name = HDLRuby.uniq_name("node").to_s end @parent = parent @parent.branches << self if @parent @successor = nil @branches = [] @xpos = 0 @ypos = 0 @width = 10 # Width in number of IC routes @height = 2 # Height in number of IC routes @arrows = [] # The flow arrows (routes) @scale = 1.0 # The scale for SVG generation end |
Instance Attribute Details
#arrows ⇒ Object (readonly)
Returns the value of attribute arrows.
3049 3050 3051 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3049 def arrows @arrows end |
#box ⇒ Object (readonly)
Returns the value of attribute box.
3051 3052 3053 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3051 def box @box end |
#branches ⇒ Object (readonly)
Returns the value of attribute branches.
3049 3050 3051 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3049 def branches @branches end |
#height ⇒ Object
Returns the value of attribute height.
3050 3051 3052 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3050 def height @height end |
#idC ⇒ Object (readonly)
Returns the value of attribute idC.
3547 3548 3549 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3547 def idC @idC end |
#matrix ⇒ Object (readonly)
Returns the value of attribute matrix.
3052 3053 3054 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3052 def matrix @matrix end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
3049 3050 3051 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3049 def name @name end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
3049 3050 3051 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3049 def parent @parent end |
#port_width ⇒ Object (readonly)
Returns the value of attribute port_width.
3054 3055 3056 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3054 def port_width @port_width end |
#routes ⇒ Object (readonly)
Returns the value of attribute routes.
3053 3054 3055 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3053 def routes @routes end |
#scale ⇒ Object
Returns the value of attribute scale.
3055 3056 3057 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3055 def scale @scale end |
#successor ⇒ Object
Returns the value of attribute successor.
3049 3050 3051 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3049 def successor @successor end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
3049 3050 3051 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3049 def type @type end |
#width ⇒ Object
Returns the value of attribute width.
3050 3051 3052 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3050 def width @width end |
#xpos ⇒ Object
Returns the value of attribute xpos.
3050 3051 3052 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3050 def xpos @xpos end |
#ypos ⇒ Object
Returns the value of attribute ypos.
3050 3051 3052 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3050 def ypos @ypos end |
Instance Method Details
#arrow_svg(x0, y0, x1, y1) ⇒ Object
Generate an arrow description SVG text for connection nodes. +x0+, +y0+, +x1+ and +y1+ are the coordinates of the arrow.
3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3794 def arrow_svg(x0,y0,x1,y1) # Draw the line. # Vertical part res = "<line stroke=\"#000\" " + "stroke-width=\"#{@scale/12.0}\" stroke-linecap=\"round\" " + "x1=\"#{x0*@scale}\" " + "y1=\"#{y0*@scale}\" " + "x2=\"#{x0*@scale}\" " + "y2=\"#{y1*@scale}\" " + "/>\n" # Horizontal part res += "<line stroke=\"#000\" " + "stroke-width=\"#{@scale/12.0}\" stroke-linecap=\"round\" " + "x1=\"#{x0*@scale}\" " + "y1=\"#{y1*@scale}\" " + "x2=\"#{x1*@scale}\" " + "y2=\"#{y1*@scale}\" " + "/>\n" # The head. if x0 == x1 then # Vertical case res += "<polygon fill=\"#000\" stroke=\"none\" " + "points=\"#{(x1-1/4.0)*@scale},#{(y1-1/2.0-1/8.0)*@scale} " + "#{(x1+1/4.0)*@scale},#{(y1-1/2.0-1/8.0)*@scale} " + "#{(x1)*@scale},#{(y1)*@scale}\"/>\n" elsif x0 < x1 then # Horizontal left case: always end horizontally. res += "<polygon fill=\"#000\" stroke=\"none\" " + "points=\"#{(x1-1/2.0)*@scale},#{(y1-1/4.0)*@scale} " + "#{(x1-1/2.0)*@scale},#{(y1+1/4.0)*@scale} " + "#{(x1+1/8.0)*@scale},#{(y1)*@scale}\"/>\n" else # Horizontal right case: always end horizontally. res += "<polygon fill=\"#000\" stroke=\"none\" " + "points=\"#{(x1)*@scale},#{(y1+1/4.0)*@scale} " + "#{(x1)*@scale},#{(y1-1/4.0)*@scale} " + "#{(x1-1/8.0-1/2.0)*@scale},#{(y1)*@scale}\"/>\n" end return res end |
#assign_svg(n) ⇒ Object
Generate an assign description SVG text for node +n+
3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3550 def assign_svg(n) # The shape representing the instance. res = "<path fill=\"#B0E2FF\" stroke=\"#000\" " + "stroke-width=\"#{@scale/12.0}\" " + # "d=\"M #{n.xpos*@scale} #{(n.ypos + n.height/2.0)*@scale} " + # "L #{(n.xpos + 1.0)*@scale} #{n.ypos*@scale} " + # "L #{(n.xpos + n.width-n.height/2.0)*@scale} #{n.ypos*@scale} " + # "A #{n.height/2.0*@scale} #{n.height/2.0*@scale} 0 0 1 " + # "#{(n.xpos + n.width-n.height/2.0)*@scale} #{(n.ypos+n.height)*@scale} " + # "L #{(n.xpos + 1.0)*@scale} #{(n.ypos+n.height)*@scale} " + "d=\"M #{n.xpos*@scale} #{(n.ypos + n.height)*@scale} " + "L #{(n.xpos + 1.0)*@scale} #{n.ypos*@scale} " + "L #{(n.xpos + n.width)*@scale} #{n.ypos*@scale} " + "L #{(n.xpos + n.width-1.0)*@scale} #{(n.ypos+n.height)*@scale} " + "Z \" />\n" # Its text. res += "<text id=\"text#{n.name}\" " + "style=\"text-anchor: middle; dominant-baseline: middle;\" " + "font-family=\"monospace\" font-size=\"1px\" " + "x=\"#{(n.xpos + n.width/2.0)*@scale}\" "+ "y=\"#{(n.ypos + n.height/2.0)*@scale}\">" + n.to_s + "</text>\n" # Its text resizing. res += Viz.svg_text_fit("text#{n.name}",(n.width-2)*@scale, 0.6*@scale) return res end |
#block_svg(n) ⇒ Object
Generate a block description SVG text for node +n+
3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3579 def block_svg(n) res = "<rect fill=\"#fff\" fill-opacity=\"0.4\" stroke=\"#000\" " + "stroke-width=\"#{@scale/10.0}\" " + "stroke-dasharray=\"#{@scale/10.0},#{@scale/10.0}\" " + # "x=\"#{n.xpos*@scale}\" y=\"#{n.ypos*@scale}\" " + # "rx=\"#{@scale*2.0}\" " + # "width=\"#{n.width*@scale}\" "+ # "height=\"#{n.height*@scale}\"/>\n" "x=\"#{(n.xpos-0.3)*@scale}\" y=\"#{(n.ypos-0.3)*@scale}\" " + "rx=\"#{@scale*0.6}\" " + "width=\"#{(n.width+0.6)*@scale}\" "+ "height=\"#{(n.height+0.6)*@scale}\"/>\n" return res end |
#case_svg(n, no = false) ⇒ Object
Generate a case description SVG text for node +n+, where +no+ tells if there is an else branch.
3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3680 def case_svg(n,no=false) # The shape representing the instance. res = "<path fill=\"#B0E2FF\" stroke=\"#000\" " + "stroke-width=\"#{@scale/12.0}\" " + "d=\"M #{(n.xpos)*@scale} #{(n.ypos+n.height/2.0)*@scale} " + "L #{(n.xpos+n.width/2.0)*@scale} #{(n.ypos+n.height)*@scale} " + "L #{(n.xpos+n.width)*@scale} #{(n.ypos+n.height/2.0)*@scale} " + "L #{(n.xpos+n.width/2.0)*@scale} #{(n.ypos)*@scale} " + "Z \" />\n" # Its text. res += "<text id=\"text#{n.name}\" " + "style=\"text-anchor: middle; dominant-baseline: middle;\" " + "font-family=\"monospace\" font-size=\"1px\" " + "x=\"#{(n.xpos + n.width/2.0)*@scale}\" "+ "y=\"#{(n.ypos + n.height/2.0)*@scale}\">" + n.to_s + "</text>\n" # Its text resizing. res += Viz.svg_text_fit("text#{n.name}",(n.width-3)*@scale, 0.6*@scale) # The yes text. res += "<text " + "style=\"text-anchor: middle; dominant-baseline: middle;\" " + "font-family=\"monospace\" font-size=\"#{@scale/2.0}px\" " + "x=\"#{(n.xpos + n.width+0.1)*@scale}\" "+ "y=\"#{(n.ypos + n.height/2.0+0.5)*@scale}\">" + "Yes" + "</text>\n" # The no text if any. if no then res += "<text " + "style=\"text-anchor: middle; dominant-baseline: middle;\" " + "font-family=\"monospace\" font-size=\"#{@scale/2.0}px\" " + "x=\"#{(n.xpos + n.width/2.0+0.7)*@scale}\" "+ "y=\"#{(n.ypos + n.height+0.3)*@scale}\">" + "No" + "</text>\n" end return res end |
#fill_place_matrix(matrix, stmnt, r, c, w, h) ⇒ Object
Fill the place matrix with statement +stmnt+ at position +r+,+c+ stretched by +w+,+h+
3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3364 def fill_place_matrix(matrix,stmnt,r,c,w,h) puts "fill_place_matrix for stmnt=#{stmnt.name} at r=#{r} c=#{c} w=#{w} h=#{h}" h.times do |y| while matrix.size <= r+y do # Need to increase the size of the matrix on y. matrix << ([nil] * matrix[0].size) end w.times do |x| while matrix[r+y].size <= c+x do # Need to increase the size of the matrix on x. matrix.each {|row| row << nil } end # Fill in. matrix[r+y][c+x] = stmnt end end end |
#if_svg(n, no = false) ⇒ Object
Generate an if description SVG text for node +n+, where +no+ tells if there is an else branch.
3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3640 def if_svg(n,no=false) # The shape representing the instance. res = "<path fill=\"#B0E2FF\" stroke=\"#000\" " + "stroke-width=\"#{@scale/12.0}\" " + "d=\"M #{(n.xpos)*@scale} #{(n.ypos+n.height/2.0)*@scale} " + "L #{(n.xpos+n.width/2.0)*@scale} #{(n.ypos+n.height)*@scale} " + "L #{(n.xpos+n.width)*@scale} #{(n.ypos+n.height/2.0)*@scale} " + "L #{(n.xpos+n.width/2.0)*@scale} #{(n.ypos)*@scale} " + "Z \" />\n" # Its text. res += "<text id=\"text#{n.name}\" " + "style=\"text-anchor: middle; dominant-baseline: middle;\" " + "font-family=\"monospace\" font-size=\"1px\" " + "x=\"#{(n.xpos + n.width/2.0)*@scale}\" "+ "y=\"#{(n.ypos + n.height/2.0)*@scale}\">" + n.to_s + "</text>\n" # Its text resizing. res += Viz.svg_text_fit("text#{n.name}",(n.width-3)*@scale, 0.6*@scale) # The yes text. res += "<text " + "style=\"text-anchor: middle; dominant-baseline: middle;\" " + "font-family=\"monospace\" font-size=\"#{@scale/2.0}px\" " + "x=\"#{(n.xpos + n.width+0.1)*@scale}\" "+ "y=\"#{(n.ypos + n.height/2.0+0.5)*@scale}\">" + "Yes" + "</text>\n" # The no text if any. if no then res += "<text " + "style=\"text-anchor: middle; dominant-baseline: middle;\" " + "font-family=\"monospace\" font-size=\"#{@scale/2.0}px\" " + "x=\"#{(n.xpos + n.width/2.0+0.7)*@scale}\" "+ "y=\"#{(n.ypos + n.height+0.3)*@scale}\">" + "No" + "</text>\n" end return res end |
#move_deep(dx, dy) ⇒ Object
Move deeply the position.
3082 3083 3084 3085 3086 3087 3088 3089 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3082 def move_deep(dx,dy) @xpos += dx @ypos += dy @branches.each {|branch| branch.move_deep(dx,dy) } @arrows.map! do |coord| [coord[0]+dx, coord[1]+dy, coord[2]+dx, coord[3]+dy ] end end |
#next_place_matrix(matrix, c0, r, c) ⇒ Object
Find the next free position in the place matrix +matrix+. +c0+ is the left-most column that can be used. +r+ and +c+ are the current row and column. Retuns the new rows and columns.
3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3328 def next_place_matrix(matrix,c0,r,c) puts "next_place_matrix: matrix[0].size=#{matrix[0].size} r=#{r} c=#{c}" while matrix[r][c] do c += 1 if c >= matrix[0].size then c = c0 r += 1 if r >= matrix.size then # Need to increase the size of the matrix. matrix << ([nil] * matrix[0].size) end end end puts "r=#{r} c=#{c}" return r,c end |
#next_row_matrix(matrix, c0, r) ⇒ Object
Find the next row free from column +c0+ starting for position row +r+ in the place matrix +matrix+. Retuns the new rows and columns.
3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3348 def next_row_matrix(matrix,c0,r) puts "next_row_matrix: matrix[0].size=#{matrix[0].size} r=#{r} c0=#{c0}" cM = matrix[0].size-1 # Max column. while (c0..cM).each.any? { |c| matrix[r][c] } do r += 1 if r >= matrix.size then # Need to increase the size of the matrix. matrix << ([nil] * matrix[0].size) end end puts "r=#{r}" return r end |
#number_statements ⇒ Object
Get the number of statements within and from current node.
3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3164 def number_statements # puts "number_statements from #{self.name} (#{self.type})" case self.type when :par, :seq # Recurse on branch. snum = @branches[0].number_statements when :if, :repeat # Recurse on the statement branches. snum = @branches[1..-1].reduce(1) do |sum,branch| sum + branch.number_statements end when :case # Recurse on the statement branches. snum = @branches[2..-1].reduce(1) do |sum,branch| sum + branch.number_statements end else # Other cases: count one. snum = 1 end # And recurse on the successor. snum += self.successor.number_statements if self.successor return snum end |
#operator_svg(n) ⇒ Object
Generate an operator description SVG text for node +n+
3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3595 def operator_svg(n) ICIICI res = "<rect fill=\"#eee\" stroke=\"#000\" " + "stroke-width=\"#{@scale/16.0}\" " + "x=\"#{ic.xpos*@scale}\" y=\"#{ic.ypos*@scale}\" " + "rx=\"#{@scale}\" " + "width=\"#{ic.width*@scale}\" "+ "height=\"#{ic.height*@scale}\"/>\n" # Its name. res += "<text class=\"medium#{self.idC}\" " + "style=\"inline-size=#{ic.width*@scale}px; text-anchor: middle; " + "dominant-baseline: middle;\" " + "x=\"#{(ic.xpos + ic.width/2.0)*@scale}\" "+ "y=\"#{(ic.ypos + ic.height/2.0)*@scale}\">" + ic.name + "</text>\n" return res end |
#place_and_route_deep ⇒ Object
Deeply place and route.
3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3527 def place_and_route_deep # puts "place_and_route_deep @type=#{@type}" case @type when :par, :seq # Place and route current block. if @type == :seq self.place_and_route_seq else self.place_and_route_par end # Place and route each of its statements. stmnt = @branches[0] while stmnt stmnt.place_and_route_deep stmnt = stmnt.successor end end end |
#place_and_route_par(x = 0, y = 0) ⇒ Object
Do the full place and route for a par block with initial position +x+ and +y+.
3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3486 def place_and_route_par(x = 0, y = 0) puts "place_and_route_par for node: #{self.name} at x=#{x} y=#{y}" @xpos = 0 @ypos = 0 # First compute the number of statements to place horizontally. snum = self.number_statements # Also compute the width of a statement. swidth = self.branches[0].width puts "snum=#{snum}" # With is the rounded square root of the number of statements. hnum = Math.sqrt(snum).round # Create the matrix for placing the statements. matrix = [ [ nil ] * (hnum * swidth) ] # Do the placement inside the matrix. stmnt = @branches[0] self.place_and_route_statement_matrix(stmnt,matrix,0,0) # Place the statements according to the matrix. placed = Set.new # Set of already placed statement (to handle stretched statements) max_r, max_c = 0,0 matrix.each_with_index do |row,r| row.each_with_index do |stmnt,c| next unless stmnt # Increase the size of the enclosing block max_r = r if max_r < r max_c = c if max_c < c next if placed.include?(stmnt) # Statement position already done stmnt.xpos = c stmnt.ypos = r # puts "position for statement: #{stmnt.name} xpos=#{stmnt.xpos} ypos=#{stmnt.ypos}" placed.add(stmnt) # The statement is placed. end end # Update the position and size of the block. self.move_deep(x,y) @width = max_c @height = max_r # @height += 1 if matrix[-1].any? end |
#place_and_route_seq(x = 1, y = 1) ⇒ Object
Do the full place and route for a seq block with initial position +x+ and +y+.
3314 3315 3316 3317 3318 3319 3320 3321 3322 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3314 def place_and_route_seq(x = 1, y = 1) puts "place_and_route_seq for node: #{self.name} at x=#{x} y=#{y}" stmnt = @branches[0] w, h = self.place_and_route_statement_vertically(stmnt,x,y) puts "Result: width=#{w} height=#{h}" # Update the size of the block. @width = w @height = h + 1 end |
#place_and_route_statement_matrix(stmnt, matrix, r, c) ⇒ Object
Place statements in a matrix from statement +stmnt+ at using +matrix+ as guide for current row +r+ and column +c+. Returns the width and height to fill from current position.
3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3385 def place_and_route_statement_matrix(stmnt, matrix, r, c) # The initial area to fill from current statement. fW, fH = stmnt.width + 1, stmnt.height puts "Placing stmnt=#{stmnt.name} type=#{stmnt.type} at #{r},#{c}" # Recurse Depending of the kind of statement. case stmnt.type when :if, :case # There no repeat in parallel blocks. fs = stmnt.type != :case ? 1 : 2 # First statement position. # First set the current statement in the matrix. self.fill_place_matrix(matrix,stmnt,r,c,stmnt.width+1,3) # Recurse on the branches. stmnt.branches[fs..-1].each do |branch| # Update the position in the matrix # Depending on the type of branch. if branch.type == :if or branch.type == :case then # If branch, go down cur_r = self.next_row_matrix(matrix,c,r) cur_c = c # Route to it downward. @arrows << [c + stmnt.width/2, r-1, c + stmnt.width/2, cur_r] else if stmnt.branches[fs] != branch then # # Not if/case branch and secondary branch, # # put a placeholder to forbid placing # # an element between the if/case and the else. # self.fill_place_matrix(matrix,stmnt,r,c,stmnt.width+1, # # stmnt.branches[fs].height-3) # fH-3) # # And Route to it with a long diagonal arrow. # @arrows << [c + stmnt.width/2, r-1, # # c + stmnt.width+1, r+stmnt.branches[fs].height-1] # c + stmnt.width+1, r+fH-1] # # c + stmnt.width+1, fH-1] # # And update the row to start with. # # r += stmnt.branches[fs].height-2 # r += fH-2 # # r = fH-2 # Else branch, go down cur_r = self.next_row_matrix(matrix,c,r) # put a placeholder to forbid placing # an element between the if/case and the else. self.fill_place_matrix(matrix,stmnt,r,c,stmnt.width+1, cur_r-r-1) # Route to it downward. @arrows << [c + stmnt.width/2, r-1, c + stmnt.width + 1, cur_r + 1] r = cur_r else # Route it with a short left arrow. @arrows << [c + stmnt.width, r+1, c + stmnt.width+1, r+1] end # And go left. cur_r = r cur_c = c + stmnt.width + 1 end # Place and route the branch. nW, nH =self.place_and_route_statement_matrix(branch,matrix,cur_r,cur_c) # Update the total fill size. fW = nW + 1 if fW < nW + 1 fH = nH if fH < nH # Update the current row. r = cur_r + 3 # Update the size of the matrix if required. while r >= matrix.size do matrix << ([ nil ] * matrix[0].size) end end # Fill again all the place used by the if/case. # self.fill_place_matrix(matrix,stmnt,r,c,fW,fH-3) when :par # Recurse on the branches. stmnt.place_and_route_par(c,r) # Then set the current statement in the matrix. self.fill_place_matrix(matrix,stmnt,r,c,stmnt.width+1,stmnt.height+1) # Update the fill size. fW = stmnt.width+1 if fW < stmnt.width + 1 fH = stmnt.height if fH < stmnt.height when :seq # Recurse on the branches. stmnt.place_and_route_seq(c,r) # Then set the current statement in the matrix. self.fill_place_matrix(matrix,stmnt,r,c,stmnt.width+1,stmnt.height+1) # Update the fill size. fW = stmnt.width+1 if fW < stmnt.width + 1 fH = stmnt.height if fH < stmnt.height else # Just set the current statement in the matrix. self.fill_place_matrix(matrix,stmnt,r,c,stmnt.width+1,3) end # Update the position in the matrix. r,c = self.next_place_matrix(matrix,0,r,c) # Recurse on successor if any. if stmnt.successor then self.place_and_route_statement_matrix(stmnt.successor,matrix,r,c) end puts "matrix placed for statement: #{stmnt.name}" return fW,fH end |
#place_and_route_statement_vertically(stmnt, x, y, cond_succ = nil) ⇒ Object
Place statements vertically from statement +stmnt+ at position +x+, +y+.
+cond_succ+ the upper conditional successor if any.
Returns the width and height of the enclosing block.
3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3194 def place_and_route_statement_vertically(stmnt,x,y,cond_succ=nil) # def place_and_route_statement_vertically(stmnt,x,y) puts "place_and_route_statement_vertically with type=#{stmnt.type} x=#{x} y=#{y}" # Set the current statement y position. stmnt.ypos = y stmnt.xpos = x w = x + stmnt.width + 1 # Depending of the kind of statement. case stmnt.type when :seq cur_w, last_y = place_and_route_statement_vertically(stmnt.branches[0],x,y) w = cur_w if cur_w > w # Ensure seq has an height last_y = y+3 if last_y <= y # Update the size of the block. stmnt.height = last_y - y - 1 stmnt.width = w - x - 1 # Update the y position. y = last_y when :par stmnt.place_and_route_par(x,y) last_y = stmnt.height + y + 2 w = stmnt.width + x + 1 # Update the y position. y = last_y-1 when :if, :case, :repeat fs = stmnt.type != :case ? 1 : 2 # First statement position. last_y = y cur_x = x cur_w = w last_y += 3 # The yes is left. branch = stmnt.branches[fs] cur_w, cur_y = place_and_route_statement_vertically(branch, # cur_x+stmnt.width+2,y) cur_w+2,y) # And connect it with an arrow. @arrows << [x+stmnt.width, y+stmnt.height/2, # cur_x+stmnt.width+2, y+stmnt.height/2] cur_w-branch.width-1, y+stmnt.height/2] # And starts the connection it to the successor if any. # But maybe there is a new successor, check it. cond_succ = stmnt.successor if stmnt.successor if cond_succ and stmnt.type != :repeat then @arrows << [cur_w-1, cur_y-stmnt.height/2, cur_w, cur_y-stmnt.height/2] end # The no and elsif are down fy = y + 2 last_y = cur_y if cur_y > last_y w = cur_w if cur_w > w stmnt.branches[fs+1..-1].each do |branch| # Place and route the branch cur_w, cur_y = place_and_route_statement_vertically(branch,x,cur_y, stmnt.successor) # place_and_route_statement_vertically(branch,x,cur_y) # And connect it with an arrow. # @arrows << [x+stmnt.width/2, last_y-1, @arrows << [x+stmnt.width/2, fy, x+stmnt.width/2, last_y] fy = last_y + 2 # Update the width and height from the branch size. w = cur_w if cur_w > w last_y = cur_y if cur_y > last_y # if branch.type != :if and branch.type != :case then # # End of if/case. # last_y += 1 # end end if fs+1 == stmnt.branches.size and stmnt.successor then # There were no "no" branches, add an arrow up to the successor. @arrows << [x+stmnt.width/2, fy, x+stmnt.width/2, last_y] end # Update the width and height from the branch size. w = cur_w if cur_w > w # cur_x += cur_w + 1 cur_x += cur_w last_y = cur_y if cur_y > last_y # Prepare the next step. y = last_y when :empty w -= 2 # @arrows << [x+stmnt.width/2, y, # x+stmnt.width/2, y+3] # else # y += 3 # end else unless stmnt.type == :assign or stmnt.type == :wait or stmnt.type == :print or stmnt.type == :terminate then raise "Unknown statement: #{stmnt.type}" end y += 3 end # Recurse on successor if any. if stmnt.successor then puts "For stmnt type: #{stmnt.type} Successor is #{stmnt.successor.name}" py = y nw, y = place_and_route_statement_vertically(stmnt.successor,x,y) w = nw if nw > w # And connect it with an arrow. # @arrows << [x + self.width/2, py-1, x + stmnt.width/2, py] @arrows << [x + self.width/2, py-1, x + self.width/2, py] # And connect it to the other branches if condition. if stmnt.type == :if or stmnt.type == :case then # @arrows << [w, stmnt.ypos+stmnt.height/2, @arrows << [w, stmnt.branches[fs].ypos+stmnt.branches[fs].height, x+self.width, py+stmnt.successor.height/2] end end return [ w, y ] end |
#print_svg(n) ⇒ Object
Generate a print description SVG text for node +n+
3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3772 def print_svg(n) # The shape representing the instance. res = "<rect fill=\"#B0E2FF\" stroke=\"#000\" " + "stroke-width=\"#{@scale/12.0}\" " + "x=\"#{n.xpos*@scale}\" y=\"#{(n.ypos)*@scale}\" " + "width=\"#{n.width*@scale}\" height=\"#{n.height*@scale}\" " + "/>\n" # Its text. res += "<text id=\"text#{n.name}\" " + "style=\"text-anchor: middle; dominant-baseline: middle;\" " + "font-family=\"monospace\" font-size=\"1px\" " + "x=\"#{(n.xpos + n.width/2.0)*@scale}\" "+ "y=\"#{(n.ypos + n.height/2.0)*@scale}\">" + n.to_s + "</text>\n" # Its text resizing. res += Viz.svg_text_fit("text#{n.name}",(n.width-1)*@scale, 0.6*@scale) return res end |
#repeat_svg(n) ⇒ Object
Generate a repeat description SVG text for node +n+
3743 3744 3745 3746 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3743 def repeat_svg(n) # Just like an if. return if_svg(n) end |
#statement_svg_deep(stmnt, no = false) ⇒ Object
Generate recursively the content of a flow from statement +stmnt+, where +no+ tells if there is an else branch.
3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3837 def statement_svg_deep(stmnt,no=false) case stmnt.type when :assign res = assign_svg(stmnt) when :seq, :par res = block_svg(stmnt) # And its arrows. stmnt.arrows.each { |x0,y0,x1,y1| res += arrow_svg(x0,y0,x1,y1) } when :if res = if_svg(stmnt, no || stmnt.branches[2]) when :case res = case_svg(stmnt, no || stmnt.branches[3]) when :repeat res = repeat_svg(stmnt) when :wait res = wait_svg(stmnt) when :terminate res = terminate_svg(stmnt) when :print res = print_svg(stmnt) else # The other types are the condition expression, they are # not statements so they are skipped. return "" end # Recurse on the branches. case stmnt.type when :if, :case, :repeat fs = stmnt.type != :case ? 1 : 2 # First statement position. stmnt.branches[fs..-2].each {|b| res += statement_svg_deep(b,true) } res += statement_svg_deep(stmnt.branches[-1],false) when :seq, :par res += statement_svg_deep(stmnt.branches[0]) end # And the successor res += statement_svg_deep(stmnt.successor) if stmnt.successor return res end |
#terminal_svg(n) ⇒ Object
Generate a terminal description SVG for node +n+
3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3614 def terminal_svg(n) ICIICI res = "<rect fill=\"#ddd\" stroke=\"#000\" " + "stroke-width=\"#{@scale/32.0}\" " + "x=\"#{(ic.xpos-1/16.0)*@scale}\" y=\"#{(ic.ypos-1/16.0)*@scale}\" " + "rx=\"#{(1+1/16.0)*@scale}\" " + "width=\"#{(ic.width+1/8.0)*@scale}\" "+ "height=\"#{(ic.height+1/8.0)*@scale}\"/>\n" res += "<rect fill=\"#ddd\" stroke=\"#000\" " + "stroke-width=\"#{@scale/32.0}\" " + "x=\"#{ic.xpos*@scale}\" y=\"#{ic.ypos*@scale}\" " + "rx=\"#{@scale}\" " + "width=\"#{ic.width*@scale}\" "+ "height=\"#{ic.height*@scale}\"/>\n" # Its name. res += "<text class=\"medium#{self.idC}\" " + "style=\"inline-size=#{ic.width*@scale}px; text-anchor: middle; " + "dominant-baseline: middle;\" " + "x=\"#{(ic.xpos + ic.width/2.0)*@scale}\" "+ "y=\"#{(ic.ypos + ic.height/2.0)*@scale}\">" + ic.name + "</text>\n" return res end |
#terminate_svg(n) ⇒ Object
Generate a terminate description SVG text for node +n+
3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3749 def terminate_svg(n) # The shape representing the instance. res = "<ellipse fill=\"#CC0202\" stroke=\"#000\" " + "stroke-width=\"#{@scale/12.0}\" " + "cx=\"#{n.xpos*@scale+n.width*@scale/2.0}\" " + "cy=\"#{(n.ypos)*@scale+n.height*@scale/2.0}\" " + "rx=\"#{n.width*@scale/2.0}\" ry=\"#{n.height*@scale/2.0}\" " + "/>\n" # Its text. res += "<text id=\"text#{n.name}\" " + "style=\"text-anchor: middle; dominant-baseline: middle;\" " + "font-family=\"monospace\" font-size=\"1px\" " + "fill=\"white\" " + "x=\"#{(n.xpos + n.width/2.0)*@scale}\" " + "y=\"#{(n.ypos + n.height/2.0)*@scale}\">" + "Terminate" + "</text>\n" # Its text resizing. res += Viz.svg_text_fit("text#{n.name}",(n.width-1)*@scale, 0.6*@scale) return res end |
#to_s(spc = "") ⇒ Object
Convert to a string.
3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3092 def to_s(spc = "") case type when :assign return spc + @branches[0].to_s + " <= " + @branches[1].to_s when :if res = spc + "if " + @branches[0].to_s return res when :case res = spc + "case " + @branches[0].to_s + "==" + @branches[1].to_s return res when :wait return spc + "wait(#{@branches[0].to_s})" when :repeat res = spc + "repeat " + @branches[0].to_s return res when :terminate return "terminate" when :value, :delay, :string return self.name when :print return spc + "print(#{@branches.map {|b| b.to_s}.join(",")})" when :cast return spc + "(" + self.name + ")" + "(" + branches[0].to_s + ")" when :concat return spc + "concat(" +@branches.map {|b| b.to_s }.join(",") + ")" when :[] if @branches.size == 2 then return spc + @branches[0].to_s + "[" + @branches[1].to_s + "]" else return spc + @branches[0].to_s + "[" + @branches[1].to_s + ".." + @branches[2].to_s + "]" end when :"." if @branches[0] then return spc + @branches[0].to_s + "." + self.name else return spc + self.name end else case(@branches.size) when 0 return spc + type.to_s when 1 return spc + "(" + HDLRuby::Viz.to_svg_text(type.to_s) + @branches[0].to_s + ")" when 2 return spc + "(" + @branches[0].to_s + HDLRuby::Viz.to_svg_text(type.to_s) + @branches[1].to_s + ")" else return spc + type.to_s + "(" + @branches.join(",") + ")" end end end |
#to_s_control ⇒ Object
Convert to a string as a control flow, i.e., the successor is also converted.
3149 3150 3151 3152 3153 3154 3155 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3149 def to_s_control res = self.to_s + ";" if @successor then res += @successor.to_s_control end return res end |
#to_svg(top = true, tx = 0, ty = 0, width = nil, height = nil) ⇒ Object
Generate in SVG format the graphical representation of the flow. +top+ tells if it is the top IC. +tx+ is the x translation of the full description. +ty+ is the y translation of the full description. +width+ is the forced width of the full description if any. +height+ is the forced height of the full description if any.
3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3882 def to_svg(top = true, tx=0, ty=0, width=nil, height=nil) # puts "Node to_svg for node=#{self.name} top=#{top} type=#{@type}" # Compute the various sizes. x0,y0, x1,y1 = 0,0, @width*@scale, @height*@scale puts "x0,y0, x1,y1 = #{x0},#{y0}, #{x1}, #{y1}" bT = (@scale * 1.5) # Border thickness pT = (bT / 5.0) # Port thickness wT = bT / 30.0 # Wire thickness sF = @scale*0.4 # Small font height mF = @scale*0.6 # Medium font height lF = @scale*1.0 # Large font height width = (x1-x0)+bT*5 unless width height = (y1-y0)+bT*5 unless height # stx = (width - (x1-x0)-bT*5) / 2.0 # X translation of the top system # sty = (height - (y1-y0)-bT*5) / 2.0 # Y translation of the top system stx = (width - (x1-x0)) / 2.0 # X translation of the top system sty = (height - (y1-y0)) / 2.0 # Y translation of the top system puts "bT=#{bT} pT=#{pT} wT=#{wT} width=#{width} height=#{height}" # The initial visibility. visibility = top ? "visible" : "hidden" # The string used as suffix for style class names. @idC = "-" + self.name.gsub(/[:$]/,"-") # Generate the SVG code. if top then # It is the top node flow. # Generate the header. res = Viz.svg_header(self.name,x0,y0,width,height) else # It is not the top, no need of initialization. res = "" end # # Sets the styles. # res += "<style>\n" # # Fonts # res += ".small#{self.idC} { font: #{sF}px monospace; }\n" # res += ".medium#{self.idC} { font: #{mF}px monospace; }\n" # res += ".large#{self.idC} { font: #{lF}px monospace; }\n" # res += "</style>\n" # Generate the group containing all the flow description. res += "<g id=\"#{self.name}\" visibility=\"#{visibility}\" " + "transform=\"translate(#{tx},#{ty})\">\n" # Generate the rectangle of the bounding box. res += "<rect fill=\"#4682B4\" stroke=\"#007\" " + "stroke-width=\"#{@scale/4.0}\" " + # "x=\"#{x0-bT*2.5}\" y=\"#{y0-bT*2.5}\" "+ "x=\"#{x0}\" y=\"#{y0}\" "+ "width=\"#{width}\" height=\"#{height}\"/>\n" # Generate the group containing the top system and its contents. res += "<g transform=\"translate(#{stx},#{sty})\">\n" # Generate the node boxes. puts "Generate node box for self.type=#{self.type}" case self.type when :assign # The SVG object representing an assignment is to draw. res += assign_svg(self) when :seq, :par # The SVG objet repenting a block is to draw. res += block_svg(self) # Also generate its content. res += self.statement_svg_deep(self.branches[0]) # And its arrows. @arrows.each { |x0,y0,x1,y1| res += arrow_svg(x0,y0,x1,y1) } end # Close the group containing the top system and its content. res += "</g>\n" # Close the group containing the description of the IC. res += "</g>\n" if top then # It is the top so close the SVG. res += "</svg>\n" end return res end |
#wait_svg(n) ⇒ Object
Generate a wait description SVG text for node +n+
3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 |
# File 'lib/HDLRuby/hruby_viz.rb', line 3719 def wait_svg(n) # The shape representing the instance. res = "<path fill=\"#B0E2FF\" stroke=\"#000\" " + "stroke-width=\"#{@scale/12.0}\" " + "d=\"M #{n.xpos*@scale} #{(n.ypos)*@scale} " + "L #{(n.xpos + n.width-n.height/2.0)*@scale} #{n.ypos*@scale} " + "A #{n.height/2.0*@scale} #{n.height/2.0*@scale} 0 0 1 " + "#{(n.xpos + n.width-n.height/2.0)*@scale} #{(n.ypos+n.height)*@scale} " + "L #{(n.xpos)*@scale} #{(n.ypos+n.height)*@scale} " + "Z \" />\n" # Its text. res += "<text id=\"text#{n.name}\" " + "style=\"text-anchor: middle; dominant-baseline: middle;\" " + "font-family=\"monospace\" font-size=\"1px\" " + "x=\"#{(n.xpos + n.width/2.0)*@scale}\" "+ "y=\"#{(n.ypos + n.height/2.0)*@scale}\">" + n.to_s + "</text>\n" # Its text resizing. res += Viz.svg_text_fit("text#{n.name}",(n.width-1)*@scale, 0.6*@scale) return res end |