class Graph

Public Class Methods

new(e_list, metrics, symmetrize, color, leafstyle, multibyte, font, font_size) click to toggle source
# File lib/rsyntaxtree/graph.rb, line 21
def initialize(e_list, metrics, symmetrize, color, leafstyle, multibyte, font, font_size)

  # Set class-specific parameters beforehand in subclass

  # Store parameters
  @e_list     = e_list
  @m          = metrics
  @multibyte  = multibyte
  @leafstyle  = leafstyle
  @symmetrize = symmetrize

  # Calculate image dimensions
  @e_height = font_size + @m[:e_padd] * 2
  h         = @e_list.get_level_height
  w         = calc_level_width(0)
  @width    = w + @m[:b_side] * 2
  @height   = h * @e_height + (h-1) * (@m[:v_space] + font_size) + @m[:b_topbot] * 2

  # Initialize the image and colors
  @col_bg   = "none"
  @col_fg   = "black"
  @col_line = "black"

  if color
    @col_node  = "blue"
    @col_leaf  = "green"
    @col_trace = "red"
  else
    @col_node  = "black"
    @col_leaf  = "black"
    @col_trace = "black"
  end
  
  @main_height = img_get_txt_height("l", font, font_size)
  @sub_size = (font_size * SUBSCRIPT_CONST)
  @sub_space_width = img_get_txt_width("l", font, @sub_size)
end

Public Instance Methods

calc_children_width(id) click to toggle source
# File lib/rsyntaxtree/graph.rb, line 120
def calc_children_width(id)
  left = 0
  right = 0
  c_list = @e_list.get_children(id)
  return nil if c_list.empty?

  c_list.each do |c|
    left =  c.indent if indent == 0 or left > c.indent
  end
  c_list.each do |c|
    right = c.indent + e.width if c.indent + c.width > right
  end
  return [left, right]
end
calc_element_width(e) click to toggle source

Calculate the width of the element. If the element is a node, the calculation will be performed recursively for all child elements.

# File lib/rsyntaxtree/graph.rb, line 83
def calc_element_width(e)
  w = 0

  children = @e_list.get_children(e.id)

  if(children.length == 0)
    w = img_get_txt_width(e.content, @font, @font_size) + @font_size
  else
    children.each do |child|
      child_e = @e_list.get_id(child)
      w += calc_element_width(child_e)
    end

    tw = img_get_txt_width(e.content, @font, @font_size) + @font_size
    if(tw > w)
      fix_child_size(e.id, w, tw)
      w = tw
    end
  end

  @e_list.set_element_width(e.id, w)
  return w
end
calc_level_width(level) click to toggle source

Calculate the width of all elements in a certain level

# File lib/rsyntaxtree/graph.rb, line 108
def calc_level_width(level)
  w = 0
  e = @e_list.get_first
  while e
    if(e.level == level)
      w += calc_element_width(e)
    end
      e = @e_list.get_next
  end
  return w
end
get_children_indent(id) click to toggle source
# File lib/rsyntaxtree/graph.rb, line 135
def get_children_indent(id)
  calc_children_width(id)[0]
end
get_children_width(id) click to toggle source
# File lib/rsyntaxtree/graph.rb, line 139
def get_children_width(id)
  calc_children_width(id)[1] - get_children_indent(id)
end
get_txt_only(text) click to toggle source
# File lib/rsyntaxtree/graph.rb, line 287
def get_txt_only(text)
  text = text.strip
  if /\A([\+\-\=\*]+).+/ =~ text
    prefix = $1
    prefix_l = Regexp.escape(prefix)
    prefix_r = Regexp.escape(prefix.reverse)
    if /\A#{prefix_l}(.+)#{prefix_r}\z/ =~ text
      return $1
    end
  end
  return text
end
img_get_txt_height(text, font, font_size, multiline = false) click to toggle source
# File lib/rsyntaxtree/graph.rb, line 300
def img_get_txt_height(text, font, font_size, multiline = false)
  metrics = img_get_txt_metrics(text, font, font_size, multiline)
  y = metrics.height
  return y
end
img_get_txt_metrics(text, font, font_size, multiline) click to toggle source
# File lib/rsyntaxtree/graph.rb, line 59
def img_get_txt_metrics(text, font, font_size, multiline)

  background = Image.new(500, 250)

  gc = Draw.new
  gc.annotate(background, 0, 0, 0, 0, text) do |gc|
    gc.font = font
    gc.pointsize = font_size
    gc.gravity = CenterGravity
    gc.stroke = 'none'
  end

  if multiline
    metrics = gc.get_multiline_type_metrics(background, text)
  else
    metrics = gc.get_type_metrics(background, text)
  end

  return metrics
end
parse_list() click to toggle source

Parse the elements in the list top to bottom and

draw the elements into the image.
As we it iterate through the levels, the element
indentation is calculated.
# File lib/rsyntaxtree/graph.rb, line 147
def parse_list

  # Calc element list recursively....
  e_arr = @e_list.get_elements

  h = @e_list.get_level_height
  h.times do |i|
    x = 0
    e_arr.each do |j|

      if (j.level == i)
        cw = @e_list.get_element_width(j.id)
        parent_indent = @e_list.get_indent(j.parent)
        if (x <  parent_indent)
          x = parent_indent
        end
        @e_list.set_indent(j.id, x)

        if !@symmetrize
          draw_element(x, i, cw, j.content, j.type)
          if(j.parent != 0 )
            words = j.content.split(" ")
            unless @leafstyle == "nothing" && ETYPE_LEAF == j.type
              if (@leafstyle == "triangle" && ETYPE_LEAF == j.type && x == parent_indent && words.length > 0)
                txt_width = img_get_txt_width(j.content, @font, @font_size)
                triangle_to_parent(x, i, cw, txt_width, @symmetrize)
              elsif (@leafstyle == "auto" && ETYPE_LEAF == j.type && x == parent_indent)
                 if words.length > 1 || j.triangle
                   txt_width = img_get_txt_width(j.content, @font, @font_size)
                   triangle_to_parent(x, i, cw, txt_width, @symmetrize)
                 else
                   line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
                 end
              else
                line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
              end
            end
          end
        end

        x += cw
      end
    end
  end
  return true if !@symmetrize
  h.times do |i|
    curlevel = h - i - 1
    indent = 0
    e_arr.each_with_index do |j, idx|
      if (j.level == curlevel)
        # Draw a line to the parent element
        children = @e_list.get_children(j.id)

        tw = img_get_txt_width(j.content, @font, @font_size)
        if children.length > 1
          left, right = -1, -1
          children.each do |child|          
            k = @e_list.get_id(child)
            kw = img_get_txt_width(k.content, @font, @font_size)              
            left = k.indent + kw / 2 if k.indent + kw / 2 < left or left == -1
            right = k.indent + kw / 2 if k.indent + kw / 2 > right
          end
          draw_element(left, curlevel, right - left, j.content, j.type)
          @e_list.set_indent(j.id, left + (right - left) / 2 -  tw / 2)

          children.each do |child|
            k = @e_list.get_id(child)
            words = k.content.split(" ")
            dw = img_get_txt_width(k.content, @font, @font_size)
            unless @leafstyle == "nothing" && ETYPE_LEAF == k.type
              if (@leafstyle == "triangle" && ETYPE_LEAF == k.type && k.indent == j.indent && words.length > 0)
                txt_width = img_get_txt_width(k.content, @font, @font_size)
                triangle_to_parent(k.indent, curlevel + 1, dw, txt_width)
              elsif (@leafstyle == "auto" && ETYPE_LEAF == k.type && k.indent == j.indent)
                if words.length > 1 || k.triangle
                  txt_width = img_get_txt_width(k.content, @font, @font_size)
                  triangle_to_parent(k.indent, curlevel + 1, dw, txt_width)
                else
                  line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
                end
              else
                line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
              end
            end
          end

        else
          unless children.empty?
            k = @e_list.get_id(children[0])
            kw = img_get_txt_width(k.content, @font, @font_size)              
            left = k.indent
            right = k.indent + kw
            draw_element(left, curlevel, right - left, j.content, j.type)
            @e_list.set_indent(j.id, left + (right - left) / 2 -  tw / 2)
          else
           parent = @e_list.get_id(j.parent)
           pw = img_get_txt_width(parent.content, @font, @font_size)
           pleft = parent.indent
           pright = pleft + pw
           left = j.indent
           right = left + tw
           if pw > tw
             left = pleft
             right = pright
           end
           draw_element(left, curlevel, right - left, j.content, j.type) 
           @e_list.set_indent(j.id, left + (right - left) / 2 -  tw / 2)             
          end

          unless children.empty?
            k = @e_list.get_id(children[0])
            words = k.content.split(" ")
            dw = img_get_txt_width(k.content, @font, @font_size)
            unless @leafstyle == "nothing" && ETYPE_LEAF == k.type
              if (@leafstyle == "triangle" && ETYPE_LEAF == k.type && words.length > 0)
                txt_width = img_get_txt_width(k.content, @font, @font_size)
                triangle_to_parent(k.indent, curlevel + 1, dw, txt_width)
              elsif (@leafstyle == "auto" && ETYPE_LEAF == k.type)
                if words.length > 1 || k.triangle
                  txt_width = img_get_txt_width(k.content, @font, @font_size)
                  triangle_to_parent(k.indent, curlevel + 1, dw, txt_width)
                else
                  line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
                end
              else
                line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
              end
            end
          end
        end
      end
    end
  end
end
row2px(row) click to toggle source

Calculate top position from row (level)

# File lib/rsyntaxtree/graph.rb, line 283
def row2px(row)
 @m[:b_topbot] + @e_height * row + (@m[:v_space] + @font_size) * row
end