Logo Search packages:      
Sourcecode: mascyma version File versions  Download package

patches.py

from __future__ import division

from Numeric import array, arange, sin, cos, pi, Float
from artist import Artist
from cbook import True, False
from transforms import Bound1D, Bound2D, Transform, transform_bound2d, \
     inverse_transform_bound2d

00009 class Patch(Artist):
    """
    A patch is a 2D thingy with a face color and an edge color

    Public attributes:
    dpi    : a DPI instance
    bbox   : a Bound2D instance in display coords
    transx : a Transform instance
    transy : a Transform instance
    """
    
    def __init__(self, dpi, bbox, edgecolor='k', facecolor='b',                
                 fill=1,
                 transx=Transform(),
                 transy=Transform(),
                 ):
        Artist.__init__(self, dpi, bbox)

        self._edgecolor = edgecolor
        self._facecolor = facecolor
        self.fill = fill
        self._linewidth=1
        self.transx = transx
        self.transy = transy

    def copy_properties(self, other):
        self._edgecolor = other._edgecolor
        self._facecolor = other._facecolor
        self.fill = other.fill
        self._linewidth= other._linewidth
        
    def get_linewidth(self):
        return self._linewidth
  
    def set_edgecolor(self, color):
        self._edgecolor = color

    def set_facecolor(self, color):
        self._facecolor = color

    def set_linewidth(self, w):
        self._linewidth = w

    def set_fill(self, b):
        self.fill = b

    def _draw(self, drawable, *args, **kwargs):

        gc = drawable.new_gc()
        gc.set_foreground(self._edgecolor)
        gc.set_linewidth(self._linewidth)

        if self._clipOn:
            gc.set_clip_rectangle(self.bbox.get_bounds())

        self._derived_draw(drawable, gc)

    def _derived_draw(self, drawable, gc):
        raise NotImplementedError, 'Derived must override'


00070 class Rectangle(Patch):
    """
    Draw a rectangle with lower left at xy=(x,y) with specified
    width and height

    Public attributes:
    dpi     : a DPI instance
    bbox     : a Bound2D instance in display coords
    transx : a Transform instance for x data
    transy : a Transform instance for y data
    transw : a Transform instance for width data, default transx
    transh : a Transform instance for height data, default transy

    """

00085     def __init__(self, dpi, bbox, xy, width, height,
                 edgecolor='k', facecolor='b',                
                 fill=True,
                 transx=Transform(),
                 transy=Transform(),
                 transw=None,
                 transh=None,
                 ):
        """
        dpi  isa DPI instance
        bbox is the display Bound2D bounding boc
        xy is an x,y tuple; width and height are width and height of rectangle
        fill is a boolean indicating whether to fill the rectangle
        transy and transy are the transforms of the x and y data
        transw and hccords are the transforms of the width and height data
                if None, use transx and transy
        """
                     
        Patch.__init__(self, dpi, bbox, edgecolor, facecolor, fill,
                       transx, transy)

        if transw is None: self.transw = self.transx
        else: self.transw = transw
        if transh is None: self.transh = self.transy
        else: self.transh = transh

        self.xy  = array(xy, typecode=Float)
        self.width, self.height = width, height
        
    def _derived_draw(self, drawable, gc):

        # I'm not using get_window_extent here to save the function
        # calls since pcolor is slow enough
        l  = self.transx.positions(self.xy[0])
        b  = self.transy.positions(self.xy[1])
        w  = self.transw.scale(self.width)
        h  = self.transh.scale(self.height)
        
        if not self.fill:
            faceColor = None
        else:
            faceColor = self._facecolor
        drawable.draw_rectangle(gc, faceColor, l, b, w, h)

        
    def get_window_extent(self):
        l  = self.transx.positions(self.xy[0])
        b  = self.transy.positions(self.xy[1])
        w  = self.transw.scale(self.width)
        h  = self.transh.scale(self.height)
        return Bound2D(l,b,w,h)
            
    def get_x(self):
        "Return the left coord of the rectangle"
        return self.xy[0]

    def get_y(self):
        "Return the bottom coord of the rectangle"
        return self.xy[1]

    def get_width(self):
        "Return the width of the  rectangle"
        return self.width

    def get_height(self):
        "Return the height of the rectangle"
        return self.height

    def set_x(self, x):
        "Set the left coord of the rectangle"
        self.xy[0] = x

    def set_y(self, y):
        "Set the bottom coord of the rectangle"
        self.xy[1] = y

    def set_width(self, w):
        "Set the width rectangle"
        self.width = w

    def set_height(self, h):
        "Set the width rectangle"
        self.height = h

    def set_bounds(self, l, b, w, h):
        self.xy = array([l,b], typecode=Float)
        self.width = w
        self.height = h

00174 class RegularPolygon(Patch):
    """
    A regular polygon patch.  xy is a length 2 tuple (the center)
    numVertices is the number of vertices.  Radius is the distance
    from the center to each of the vertices.  Orientation is in
    radians and rotates the polygon.

    Public attributes:
    dpi     : a DPI instance
    bbox    : a Bound2D instance in display coords
    transx  : a Transform for the x data
    transy  : a Transform for the y data
    transw  : a Transform for the radius

    """
    def __init__(self, dpi, bbox, xy, numVertices, radius=5, orientation=0,
                 edgecolor='k', facecolor='b',                
                 fill=1,
                 transx=Transform(),
                 transy=Transform(),
                 transr=Transform(), 
                 ):

        Patch.__init__(self, dpi, bbox, edgecolor, facecolor, fill,
                       transx, transy)

        self.transr = transr
        self.xy = xy
        self.numVertices = numVertices
        self.radius = radius
        self.orientation = orientation
        self._compute_vertices()

    def _compute_vertices(self):

        theta = 2*pi/self.numVertices*arange(self.numVertices) + \
                self.orientation
        r = self.transr(self.radius)
        self.xs = self.xy[0] + r*cos(theta)
        self.ys = self.xy[1] + r*sin(theta)

    def _derived_draw(self, drawable, gc):

        xs  = self.transx.positions(self.xs)
        ys  = self.transy.positions(self.ys)
        vertices = zip(xs, ys)
        if not self.fill:
            faceColor = None
        else:
            faceColor = self._facecolor

        drawable.draw_polygon(gc, faceColor, points=vertices)


00228 class Circle(Patch):
    """
    A circle patch

    Public attributes:
      dpi     : a DPI instance
      bbox    : a Bound2D instance in display coords
      transx : a Bound1D instance giving the x coords
      transy : a Bound1D instance giving the y coords
      transrx : a Bound1D instance giving the radius coords in x direction
      transry : a Bound1D instance giving the radius coords in y direction
    """
00240     def __init__(self, dpi, bbox, xy, radius=5,
                 edgecolor='k', facecolor='b',                
                 fill=1,
                 transx=Transform(),
                 transy=Transform(),
                 transrx=None,                 
                 transry=None,
                 ):
        """
        if transrx is None, default to transx
        if transry is None, default to transy
        """
        Patch.__init__(self, dpi, bbox, edgecolor, facecolor, fill,
                       transx, transy)
        
        self.xy = xy
        self.radius = radius

        if transrx is None: self.transrx = transx
        else: self.transrx = transrx

        if transry is None: self.transry = transy
        else: self.transry = transry


    def _derived_draw(self, drawable, gc):

        x  = self.transx.positions(self.xy[0])
        y  = self.transy.positions(self.xy[1])
        w  = self.transrx.scale(self.radius)
        h  = self.transry.scale(self.radius)        
        if not self.fill:
            faceColor = None
        else:
            faceColor = self._facecolor

        drawable.draw_arc(gc, faceColor, x, y, 2*w, 2*h, 0, 360)
    
    def get_window_extent(self):
        x  = self.transx.positions(self.xy[0])
        y  = self.transy.positions(self.xy[1])
        w  = self.transrx.scale(self.radius)
        h  = self.transry.scale(self.radius)
        return Bound2D(x-w/2, y-h/2, 2*w, 2*h)




def bbox_artist(artist, drawable):
    """
    This is a debug function to draw a rectangle around the bounding
    box returned by get_window_extent of an artist, to test whether
    the artist is returning the correct bbox
    """

    #identity tranforms
    transx=Transform(artist.bbox.x, artist.bbox.x)
    transy=Transform(artist.bbox.y, artist.bbox.y)

    bbox = artist.get_window_extent()
    r = Rectangle(artist.dpi, bbox,
                  xy=(bbox.x.min(), bbox.y.min()),
                  width=bbox.x.interval(),
                  height=bbox.y.interval(),
                  fill=False,
                  transx=transx, transy=transy,
                  )
    r.set_clip_on( False )
    r.draw(drawable)


Generated by  Doxygen 1.6.0   Back to index