class PSWriter

A debugging / demonstration utility class that generates postscript images

Public Class Methods

new(path) click to toggle source

@param path path of file to write (e.g. xxx.ps)

# File lib/geotree/pswriter.rb, line 50
def initialize(path)
  @path = path
  @line_width = -1
  @rgb = [-1,0,0]
  @phys_size = [612,792]
  @state = S_START_
  @stack = []
  @buffer_stack = []
  @dict = {}
  @dict_keys = []

  de("A","{arc} bind")
  de("CP","{closepath} bind")
  de('F','{fill} bind')
  de('I','{index} bind')
  de("L","{lineto} bind")
  de("M","{moveto} bind")
  de("NP","{newpath} bind")
  de('SRGB','{setrgbcolor} bind')
  de('SLW','{setlinewidth} bind')
  de('P','{pop} bind')
  de("R","{rmoveto} bind")
  de("S","{stroke} bind")
  de('SCL','{scale} bind')
  de('TR','{translate} bind')
  de("V","{rlineto} bind")
  de("DSH","{setdash} bind")

  set_logical_page_size(1000,1200)

  @line_type = 0
  @scale_ = 0
  @font_height = 0
  @scaled_font_height = 0

  @page_used = false
  @s = ''
end

Public Instance Methods

add_element(key,val) click to toggle source

Define an element by placing it in the dictionary

# File lib/geotree/pswriter.rb, line 390
def add_element(key,val)
  de(key,'{'+val+'}')
end
close() click to toggle source

Close document and write to disk

# File lib/geotree/pswriter.rb, line 104
def close
  if @state < S_CLOSED_
    if @stack.size != 0
      warn("state stack nonempty for #{@path}")
    end

    flush_page

    # Construct file by combining header, dictionary, and
    # the user text

    s = get_doc_header
    s << get_doc_dictionary
    s << @s
    set_state(S_CLOSED_)

    write_text_file(@path, s)
  end
end
draw_circle(cx, cy, radius) click to toggle source
# File lib/geotree/pswriter.rb, line 193
def draw_circle(cx, cy, radius)
  de("CH", "{NP 0 360 A CP S}")
  a("NP");
  a(cx);
  a(cy);
  a(radius);
  a("CH");
  cr
end
draw_disc(cx,cy,radius) click to toggle source
# File lib/geotree/pswriter.rb, line 184
def draw_disc(cx,cy,radius)
  de("CF", "{NP 0 360 A CP F}")
  a(cx);
  a(cy);
  a(radius);
  a("CF")
  cr
end
draw_element(key) click to toggle source
# File lib/geotree/pswriter.rb, line 394
def draw_element(key)
  val = @dict[key]
  raise ArgumentError if !@dict.member?(key)
  a(key)
end
draw_line(x1,y1,x2,y2) click to toggle source
# File lib/geotree/pswriter.rb, line 203
def draw_line(x1,y1,x2,y2)
  de("LN", "{NP 4 2 roll M L CP S}")

  #    a("NP");
  a(x1);
  a(y1);
  #    a("M");
  a(x2);
  a(y2);
  a("LN");
  cr
end
draw_polygon(polygon, x, y) click to toggle source

Draw a polygon @param polygon array of 2n coordinates, defining closed n-gon @param x translation to apply to coordinates @param y

# File lib/geotree/pswriter.rb, line 269
def draw_polygon(polygon, x, y)

  push(translate(x, y))
  a("NP")
  i = 0
  while i < polygon.size
    a(polygon[i])
    a((polygon[i + 1]))
    if (i == 0)
      a("M");
    else
      a("L");
    end
    i += 2
  end
  a("CP S")
  cr
  pop()
end
draw_rect(x,y,w,h,inset = 0) click to toggle source

Draw a rectangle @param inset distance to inset rectangle boundary (positive: shrink; negative:expand)

# File lib/geotree/pswriter.rb, line 137
def draw_rect(x,y,w,h,inset = 0)
  de("RC","{3 I 3 I M 1 I 0 V 0 1 I V 1 I neg 0 V P P P P CP S }")
  a(x + inset)
  a(y + inset)
  a(w - 2 * inset);
  a(h - 2 * inset);
  a("RC");
  cr
end
draw_string(string, x, y) click to toggle source
# File lib/geotree/pswriter.rb, line 164
def draw_string(string, x, y)
  if @font_height == 0
    set_font_size(28)
  end

  #    /TEXTL { currentpoint S M 0 0 R show } def
  #    % Right-justified text
  #    /TEXTR { currentpoint S M dup stringwidth pop neg 0 R show } def
  #    % Centered text
  de("TX", "{currentpoint S M dup stringwidth pop -2 div 0 R show }")

  a(x)
  a(y - @scaled_font_height / 2);
  a("M")
  work = make_eps_safe(string)
  a(work)
  a("TX")
  cr
end
new_page(page_title) click to toggle source

Start a new page @param page_title title of new page

# File lib/geotree/pswriter.rb, line 353
def new_page(page_title)
  set_state(S_OPEN_);
  flush_page

  print_page_header(page_title);
  @page_used = true;
end
page_size() click to toggle source
# File lib/geotree/pswriter.rb, line 131
def page_size
  return @document_size
end
pop(count = 1) click to toggle source
# File lib/geotree/pswriter.rb, line 368
def pop(count = 1)
  count.times do
    n = @stack.size   - 1
    op = @stack.pop
    case op.type
    when RGB_
      set_rgb(op.arg(0),op.arg(1),op.arg(2))
    when LINETYPE_
      set_line_type(op.arg(0))
    when LINEWIDTH_
      set_line_width(op.arg(0))
    when TRANS_
      translate(op.arg(0),op.arg(1))
    when FONTHEIGHT_
      set_font_size(op.arg(0))
    when SCALE_
      set_scale(op.arg(0))
    end
  end
end
push(obj) click to toggle source

Push previous state (returned by an operation) onto a stack to be restored later; call must be balanced by later call to pop() @param obj state object returned by operation such as setGray(), translate()

# File lib/geotree/pswriter.rb, line 364
def push(obj)
  @stack << obj
end
set_font_size(height) click to toggle source
# File lib/geotree/pswriter.rb, line 147
def set_font_size(height)
  raise IllegalStateException if @state != S_OPEN_

  ret = SOper.null

  if @font_height != height
    ret = SOper.new(FONTHEIGHT_, @font_height)
    @font_height = height;
    @scaled_font_height = height / @scale;
    a("/Monaco findfont ");
    a(@scaled_font_height);
    a("scalefont setfont\n");
    cr
  end
  ret
end
set_gray(f) click to toggle source
# File lib/geotree/pswriter.rb, line 333
def set_gray(f)
  set_rgb(f,f,f)
end
set_line_dashed() click to toggle source
# File lib/geotree/pswriter.rb, line 220
def set_line_dashed
  set_line_type(LT_DASHED_)
end
set_line_dotted() click to toggle source
# File lib/geotree/pswriter.rb, line 224
def set_line_dotted
  set_line_type(LT_DOTTED_)
end
set_line_solid() click to toggle source
# File lib/geotree/pswriter.rb, line 216
def set_line_solid
  set_line_type(LT_SOLID_)
end
set_line_type(type) click to toggle source
# File lib/geotree/pswriter.rb, line 239
def set_line_type(type)
  ret = SOper.null
  if  @line_type != type
    ret = SOper.new(LINETYPE_, @line_type)
    @line_type = type
    case type
    when LT_DASHED_
      n =    (@scale * 30).to_i
      a("[");
      a(n);
      a(n);
      a("] 0 DSH");
    when LT_DOTTED_
      int n =    (@scale * 30).to_i
      n2 = n / 4
      a("[");
      a(n2);
      a(n);
      a("] 0 DSH");
    else # LT_SOLID_
      a("[] 0 DSH");
    end
  end
  ret
end
set_line_width(w) click to toggle source
# File lib/geotree/pswriter.rb, line 307
def set_line_width(w)
  ret = SOper.null
  if @line_width != w

    ret = SOper.new(LINEWIDTH_, @line_width)
    @line_width = w
    a(LINEWIDTH_FACTOR_ * @scale   * @line_width)
    a("SLW");
  end
  ret
end
set_logical_page_size( width, height) click to toggle source

Set logical page size. Subsequent drawing operations will be scaled appropriately. Default logical page size is 1000 x 1200 units.

# File lib/geotree/pswriter.rb, line 126
def set_logical_page_size( width,  height)
  raise IllegalStateException if @state != S_START_
  @document_size = [width,height]
end
set_rgb(r,g,b) click to toggle source
# File lib/geotree/pswriter.rb, line 319
def set_rgb(r,g,b)
  ret = SOper.null
  if (r != @rgb[0] || g != @rgb[1] || b != @rgb[2])

    ret = SOper.new(RGB_, @rgb[0], @rgb[1], @rgb[2])
    a(r)
    a(g)
    a(b)
    @rgb = [r,g,b]
    a("SRGB");
  end
  ret
end
set_scale(f) click to toggle source
# File lib/geotree/pswriter.rb, line 228
def set_scale(f)
  ret = SOper.null
  if   f != 1
    ret = SOper.new(SCALE_, 1.0 / f)
    a(f);
    a(f);
    a("SCL");
  end
  ret
end
set_state( s) click to toggle source
# File lib/geotree/pswriter.rb, line 337
def set_state(  s)
  if (@state != s)
    case s
    when S_OPEN_
      raise IllegalStateException if @state != S_START_
      @state = s
      #        print_document_header
    when S_START_
      raise IllegalStateException
    end
    @state = s
  end
end
start_buffer() click to toggle source
# File lib/geotree/pswriter.rb, line 89
def start_buffer
  raise IllegalStateException if !@buffer_stack.empty?
  @buffer_stack << @s
  @s = ''
end
stop_buffer() click to toggle source
# File lib/geotree/pswriter.rb, line 95
def stop_buffer
  raise IllegalStateException if @buffer_stack.empty?
  ret = @s
  @s = @buffer_stack.pop
  ret
end
translate(tx,ty,neg=false) click to toggle source

Translate subsequent drawing operations

# File lib/geotree/pswriter.rb, line 290
def translate(tx,ty,neg=false)

  ret = SOper.null
  if (neg)
    tx = -tx;
    ty = -ty;
  end
  if (tx != 0 || ty != 0)
    ret = SOper.new(TRANS_, -tx, -ty)

    a(tx);
    a(ty);
    a("TR");
  end
  ret
end

Private Instance Methods

a(obj) click to toggle source
# File lib/geotree/pswriter.rb, line 414
def a(obj)
  if @sp_req
    @s << ' '
  end
  if obj.is_a? Numeric
    if obj.is_a? Float
      w = sprintf("%.2f",obj)
      # Trim extraneous leading/trailing zeros

      if w[0,2] == '0.'
        w = w[1.. -1]
      elsif w[0,3] == '-0.'
        w[1,1] = ''
      end

      j = w.index('.')
      if j
        while w[-1] == '0'
          w = w[0..-2]
        end
        if w[-1] == '.'
          w = w[0..-2]
        end
      end
      @s <<    w
    else
      @s << obj.to_s
    end
  else
    @s <<   obj
  end
  @sp_req = true
end
cr() click to toggle source
# File lib/geotree/pswriter.rb, line 402
def cr
  if true
    if @sp_req
      @s << ' '
      @sp_req = false
    end
  else
    @sp_req = false
    @s << "\n"
  end
end
de(key,val) click to toggle source
# File lib/geotree/pswriter.rb, line 496
def de(key,val)
  if !@dict.member? key
    @dict_keys << key
    @dict[key] = val
  else
    vexist = @dict[key]
    if vexist != val
      raise ArgumentError,"Attempt to change value for key #{key} to #{val}, was #{vexist}"
    end

  end
end
flush_page() click to toggle source
# File lib/geotree/pswriter.rb, line 510
def flush_page
  if @page_used
    a("showpage")
    @page_used = false
  end
end
get_doc_dictionary() click to toggle source
# File lib/geotree/pswriter.rb, line 483
def get_doc_dictionary
  s = ''
  @dict_keys.each do |k|
    v = @dict[k]
    if v.size
      s << '/' << k << ' ' << v << " def\n"
    else
      s2 << '/' << k << "\n"
    end
  end
  s
end
get_doc_header() click to toggle source
# File lib/geotree/pswriter.rb, line 479
def get_doc_header
  h = "%!PS\n"
end
make_eps_safe(str) click to toggle source
# File lib/geotree/pswriter.rb, line 517
def make_eps_safe(str)
  w = '('
  str.length.times do |i|
    c = str[i]
    esc = false
    if c.ord < 32
      c = '_'
    end
    case c
    when '(',')'
      esc = true
    end

    w << '\\' if esc
    w << c
  end
  w << ')'
  w
end
print_page_header(page_title) click to toggle source