[cairo] ruby current_path

MenTaLguY mental at rydia.net
Wed Feb 9 21:43:01 PST 2005


On Wed, 2005-02-09 at 13:01, Øyvind Kolås wrote:
> On Wed,  9 Feb 2005 10:49:40 -0500, mental at rydia.net <mental at rydia.net> wrote:
> > (that is also why for current_path, I return an array from C and
> > iterate over it in Ruby)
> 
> Could you make a small sample of how this api is used? Having a sample
> would make it easier to see
> how it can be used.

This is from memory, so no promises this code will work as written, but
it should give you an idea...

 # generate an SVG path string from the current path
 path = ""
 context.current_path {|op, *coords|
   case op
   when :move_to
     path << "M"
   when :line_to
     path << "L"
   when :curve_to
     path << "C"
   when :close_path
     path << "z"
   end
   path << coords.join(",")
 }
 puts path

You can do SAX-like things with path events:

 class SVGPathBuilder
   def initialize(stream)
     @stream = stream
   end
   def move_to(x, y)
     @stream << "M#{x},#{y}"
   end
   def line_to(x, y)
     @stream << "L#{x},#{y}"
   end
   def curve_to(x1, y1, x2, y2, x3, y3)
     @stream << "C#{x1},#{y1},#{x2},#{y2},#{x3},#{y3}"
   end
   def close_path
     @stream << "z"
   end
 end

 path = ""
 handler = SVGPathBuilder.new(path)
 context.current_path {|event| handler.send(*event) }
 puts path

[ or even: context.current_path(&handler.method(:send)) ]

You can have stackable filters:

 # okay, cheap, but it's just an example
 class CurvesToLines
   def initialize(handler)
     @handler = handler
   end
   def move_to(x, y)
     @handler.move_to(x, y)
   end
   def line_to(x, y)
     @handler.line_to(x, y)
   end
   def curve_to(x1, y1, x2, y2, x3, y3)
     @handler.line_to(x3, y3) # throw away intermediate control points
   end
   def close_path
     @handler.close_path
   end
 end

And the observant will notice that Cairo::Context implements this "path
handler" protocol itself:

 # copy path from one context to another
 other_context.new_path
 context.current_path {|event| other_context.send(*event) }

You can also simply fetch an array of these events...

 events = context.current_path
 
...and do things with it:

 filter = CurvesToLines.new(context)
 context.new_path
 events.select {|event|
   event[0] != :close_path # skip all close_paths
 }.each {|event|
   filter.send(*event) # apply the filter
 }

These are all pretty contrived, but they should at least give you a
rough idea of what can be done with the API.

In retrospect, it might not hurt to add an (optional) single argument
for #current_path, so you could simply do:

 context.current_path(handler)

as shorthand for:

 context.current_path {|event| handler.send(*event) }

but really this is all icing.  I doubt current_path will ever get used
that much.

-mental
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : http://lists.freedesktop.org/archives/cairo/attachments/20050210/ffa69e1a/attachment.pgp


More information about the cairo mailing list