[cairo-commit] [cairo-www] src/animationrotation.mdwn
Carl Worth
cworth at freedesktop.org
Sun Nov 25 03:23:17 PST 2007
src/animationrotation.mdwn | 158 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
New commits:
commit 3049d8f74fc7e9066a154d7b32de47c8d5aac645
Author: Donn <donn.ingle at gmail.com>
Date: Sun Nov 25 03:23:12 2007 -0800
busy
diff --git a/src/animationrotation.mdwn b/src/animationrotation.mdwn
new file mode 100644
index 0000000..bc7abb4
--- /dev/null
+++ b/src/animationrotation.mdwn
@@ -0,0 +1,158 @@
+## A pyCairo/PyGTK animation framework showing (gasp) a square rotating around an arbitrary point
+
+This is two things. First it's a nice little framework that gives "life" to a function so that animation becomes possible. If you want stuff to be drawn again and again with little changes, this is a good start. (I'd love to see other solutions).
+ Secondly it shows how to rotate a "shape" (set of cairo commands) around any given ( x, y ) point.
+
+I tried to comment it thoroughly, so it will 'splain itself.
+
+
+ ## cairo demos Copyright (C) 2007 Donn.C.Ingle
+ ##
+ ## Contact: donn.ingle at gmail.com - I hope this email lasts.
+ ##
+ ## This program is free software; you can redistribute it and/or modify
+ ## it under the terms of the GNU General Public License as published by
+ ## the Free Software Foundation; either version 2 of the License, or
+ ## ( at your option ) any later version.
+ ##
+ ## This program is distributed in the hope that it will be useful,
+ ## but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ## GNU General Public License for more details.
+ ##
+ ## You should have received a copy of the GNU General Public License
+ ## along with this program; if not, write to the Free Software
+ ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ import pygtk
+ import gtk, gobject, cairo
+ from gtk import gdk
+
+ class Screen( gtk.DrawingArea ):
+ """ This class is a Drawing Area"""
+ def __init__(self):
+ super(Screen,self).__init__()
+ ## Old fashioned way to connect expose. I don't savvy the gobject stuff.
+ self.connect ( "expose_event", self.do_expose_event )
+ ## This is what gives the animation life!
+ gobject.timeout_add( 50, self.tick ) # Go call tick every 50 whatsits.
+
+ def tick ( self ):
+ ## This invalidates the screen, causing the expose event to fire.
+ self.alloc = self.get_allocation ( )
+ rect = gtk.gdk.Rectangle ( self.alloc.x, self.alloc.y, self.alloc.width, self.alloc.height )
+ self.window.invalidate_rect ( rect, True )
+ return True # Causes timeout to tick again.
+
+ ## When expose event fires, this is run
+ def do_expose_event( self, widget, event ):
+ self.cr = self.window.cairo_create( )
+ ## Call our draw function to do stuff.
+ self.draw( *self.window.get_size( ) )
+
+ class MyStuff ( Screen ):
+ """This class is also a Drawing Area, coming from Screen."""
+ def __init__ ( self ):
+ Screen.__init__( self )
+ ## x,y is where I'm at
+ self.x, self.y = 25, -25
+ ## rx,ry is point of rotation
+ self.rx, self.ry = -10, -25
+ ## rot is angle counter
+ self.rot = 0
+ ## sx,sy is to mess with scale
+ self.sx, self.sy = 1, 1
+
+ def draw( self, width, height ):
+ ## A shortcut
+ cr = self.cr
+
+ ## First, let's shift 0,0 to be in the center of page
+ ## This means:
+ ## -y | -y
+ ## -x | +x
+ ## ----0------
+ ## -x | +x
+ ## +y | +y
+
+ matrix = cairo.Matrix ( 1, 0, 0, 1, width/2, height/2 )
+ cr.transform ( matrix ) # Make it so...
+
+ ## Now save that situation so that we can mess with it.
+ ## This preserves the last context ( the one at 0,0)
+ ## and let's us do new stuff.
+ cr.save ( )
+
+ ## Now attempt to rotate something around a point
+ ## Use a matrix to change the shape's position and rotation.
+
+ ## First, make a matrix. Don't look at me, I only use this stuff :)
+ ThingMatrix = cairo.Matrix ( 1, 0, 0, 1, 0, 0 )
+
+ ## Next, move the drawing to it's x,y
+ cairo.Matrix.translate ( ThingMatrix, self.x, self.y )
+ cr.transform ( ThingMatrix ) # Changes the context to reflect that
+
+ ## Now, change the matrix again to:
+ cairo.Matrix.translate( ThingMatrix, self.rx, self.ry ) # move it all to point of rotation
+ cairo.Matrix.rotate( ThingMatrix, self.rot ) # Do the rotation
+ cairo.Matrix.translate( ThingMatrix, -self.rx, -self.ry ) # move it back again
+ cairo.Matrix.scale( ThingMatrix, self.sx, self.sy ) # Now scale it all
+ cr.transform ( ThingMatrix ) # and commit it to the context
+
+ ## Now, whatever is draw is "under the influence" of the
+ ## context and all that matrix magix we just did.
+ self.drawCairoStuff ( cr )
+
+ ## Let's inc the angle a little
+ self.rot += 0.1
+
+ ## Now mess with scale too
+ self.sx += 0 # Change to 0 to see if rotation is working...
+ if self.sx > 4: self.sx=0.5
+ self.sy = self.sx
+
+ ## We restore to a clean context, to undo all that hocus-pocus
+ cr.restore ( )
+
+ ## Let's draw a crosshair so we can identify 0,0
+ ## Drawn last to be above the red square.
+ self.drawcross ( cr )
+
+ ## And we're done
+ return True #keeps the timeout ticking
+
+ def drawCairoStuff ( self, cr ):
+ ## Thrillingly, we draw a red rectangle.
+ ## It's draw such that 0,0 is in it's center.
+ cr.rectangle( -25, -25, 50, 50 )
+ cr.set_source_rgb( 1, 0, 0)
+ cr.fill( )
+ ## Now a visual indicator of the point of rotation
+ ## I have no idea (yet) how to keep this as a
+ ## tiny dot when the entire thing scales.
+ cr.set_source_rgb( 1, 1, 1 )
+ cr.move_to( self.rx, self.ry )
+ cr.line_to ( self.rx+1, self.ry+1 )
+ cr.stroke( )
+
+ def drawcross ( self, ctx ):
+ ctx.set_source_rgb ( 0, 0, 0 )
+ ctx.move_to ( 0,10 )
+ ctx.line_to ( 0, -10 )
+ ctx.move_to ( -10, 0 )
+ ctx.line_to ( 10, 0 )
+ ctx.stroke ( )
+
+
+ def run( Widget ):
+ window = gtk.Window( )
+ window.connect( "delete-event", gtk.main_quit )
+ window.set_size_request ( 400, 400 )
+ widget = Widget( )
+ widget.show( )
+ window.add( widget )
+ window.present( )
+ gtk.main( )
+
+ run( MyStuff )
More information about the cairo-commit
mailing list