[cairo] in_fill hit test and matrix transforms

Donn donn.ingle at gmail.com
Wed Nov 21 08:46:29 PST 2007


Hi again, been a while. I'm still hacking away on my wee project and have 
stumbled onto something that I'm not sure is expected behaviour. Sample code 
at end.

Some context:
1. Kubuntu Gutsy (7.10)
2. Standard python-gnome install, I have not built cairo or anything from 
source.
3. libcairo2 Version: 1.4.10-1ubuntu4
4. python-cairo Version: 1.4.0-2ubuntu1
5. Python 2.5

Okay, basically when stuff is drawn and not filled (in order to copy the path) 
under the influence of a transform, it seems to ignore the transform and draw 
at absolute coordinates.

 I want to test mouse x,y over a shape drawn by cairo and I have moved that 
shape to 50,50. I draw the shape at 0,0 but transform it to 50,50. After that 
I draw the same shape, under the same transform, but sans fill and copy the 
path so I can do a in_fill ( ) test but it "draws" the shape at 0,0.

 The sample code should run. If you click around the top-left corner you'll 
see True hits (printed on console). If you click where the red shape is, they 
are all False. 

So, I dunno if this is expected or (most likely) I am missing the point, but 
it's something I'll have to code around somehow.

Any ideas?

/d



import pygtk
import gtk, gobject, cairo
from gtk import gdk

class Screen(gtk.DrawingArea):
    __gsignals__ = { "expose-event": "override" }

    def __init__(self):
        super(Screen,self).__init__()
        self.connect("button_press_event", self.button_press)
        self.add_events(gdk.BUTTON_PRESS_MASK |
                        gdk.BUTTON_RELEASE_MASK |
                        gdk.POINTER_MOTION_MASK)
        
    def do_expose_event(self, event):
        cr = self.window.cairo_create()
        self.cr = cr
        self.draw(cr, *self.window.get_size())

def run(Widget):
    window = gtk.Window()
    window.connect("delete-event", gtk.main_quit)
    widget = Widget()
    widget.show()
    window.add(widget)
    window.present()
    gtk.main()

class Shapes(Screen):
    def matrixstart ( self, cr ):
        cr.save()
        matrix = cairo.Matrix(1,0,0,1, 150,150)
        cairo.Matrix.rotate( matrix, 3 )
        cr.transform ( matrix )   
    def matrixend ( self, cr ):
        cr.restore ( )
    def cairocommands ( self, cr ):
        x = y = 10
        sx = sy = 50
        cr.move_to(x,y)
        cr.line_to(x+sx,y)
        cr.line_to(x+sx,y+sy)
        cr.line_to(x+(sx/2),y+sy)
        cr.line_to(x+(sx/2),y+(sy/2))
        cr.line_to(x,y+(sy/2))
        cr.line_to(x,y+sy)
        cr.line_to(x-sx,y+sy)
        cr.close_path()
        cr.set_source_rgb(1,0,0)
    def draw(self, cr, width, height):
        #Use a matrix to change the shape's position and rotation.
        self.matrixstart ( cr )    
        self.cairocommands ( cr )
        cr.fill()
        self.matrixend ( cr )
    def button_press(self,widget,event):
        cr = self.cr
        #Exact same matrix, no effect
        self.matrixstart ( cr )    
        self.cairocommands ( cr )
        result = cr.in_fill( event.x, event.y )
        print result
        self.matrixend ( cr )
         
run(Shapes)


More information about the cairo mailing list