Revision: 3939
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3939&view=rev
Author:   mdboom
Date:     2007-10-12 10:30:17 -0700 (Fri, 12 Oct 2007)

Log Message:
-----------
More progress on examples.

Modified Paths:
--------------
    branches/transforms/PASSED_DEMOS
    branches/transforms/examples/collections_demo.py
    branches/transforms/examples/simple_plot_fps.py
    branches/transforms/lib/matplotlib/axes.py
    branches/transforms/lib/matplotlib/axis.py
    branches/transforms/lib/matplotlib/colorbar.py
    branches/transforms/lib/matplotlib/contour.py
    branches/transforms/lib/matplotlib/text.py
    branches/transforms/lib/matplotlib/ticker.py
    branches/transforms/lib/matplotlib/transforms.py
    branches/transforms/src/_backend_agg.cpp

Modified: branches/transforms/PASSED_DEMOS
===================================================================
--- branches/transforms/PASSED_DEMOS    2007-10-12 14:29:57 UTC (rev 3938)
+++ branches/transforms/PASSED_DEMOS    2007-10-12 17:30:17 UTC (rev 3939)
@@ -16,10 +16,10 @@
 arctest.py             O
 arrow_demo.py          O
 axes_demo.py           O
-axes_props.py          [SOMETHING FUNNY ABOUT DASHED LINES]
+axes_props.py          O
 axhspan_demo.py                O
 axis_equal_demo.py      O
-backend_driver.py
+backend_driver.py      [N/A]
 barchart_demo.py        O
 barcode_demo.py         O
 barh_demo.py           [BROKEN IN TRUNK]
@@ -29,14 +29,14 @@
 broken_barh.py         O
 clippath_test.py       O
 clippedline.py         O
-collections_demo.py     -- [NEEDS ADDITIONAL WORK]
+collections_demo.py    O
 colorbar_only.py       O
 color_by_yvalue.py     O
 color_demo.py          O
 colours.py             [???]
-contour_demo.py                
-contourf_demo.py
-contour_image.py
+contour_demo.py                O
+contourf_demo.py       [FLOATING POINT EXCEPTION]
+contour_image.py       [FLOATING POINT EXCEPTION]
 coords_demo.py         O
 coords_report.py       O
 csd_demo.py            O

Modified: branches/transforms/examples/collections_demo.py
===================================================================
--- branches/transforms/examples/collections_demo.py    2007-10-12 14:29:57 UTC 
(rev 3938)
+++ branches/transforms/examples/collections_demo.py    2007-10-12 17:30:17 UTC 
(rev 3939)
@@ -87,7 +87,7 @@
 a = fig.add_subplot(2,2,3)
 
 col = collections.RegularPolyCollection(fig.dpi, 7,
-                                        sizes = N.fabs(xx) / 10.0, offsets=xyo,
+                                        sizes = N.fabs(xx)*10.0, offsets=xyo,
                                         transOffset=a.transData)
 trans = transforms.Affine2D().scale(fig.dpi/72.0)
 col.set_transform(trans)  # the points to pixels transform

Modified: branches/transforms/examples/simple_plot_fps.py
===================================================================
--- branches/transforms/examples/simple_plot_fps.py     2007-10-12 14:29:57 UTC 
(rev 3938)
+++ branches/transforms/examples/simple_plot_fps.py     2007-10-12 17:30:17 UTC 
(rev 3939)
@@ -21,11 +21,13 @@
 #savefig('simple_plot')
 
 import time
-
+from matplotlib import transforms
+    
 frames = 100.0
 t = time.clock()
 ion()
 for i in xrange(int(frames)):
+    transforms.CATCH = True
     part = i / frames
     axis([0.0, 1.0 - part, -1.0 + part, 1.0 - part])
     show()

Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py  2007-10-12 14:29:57 UTC (rev 
3938)
+++ branches/transforms/lib/matplotlib/axes.py  2007-10-12 17:30:17 UTC (rev 
3939)
@@ -1110,7 +1110,6 @@
         # and the data in xydata
         # MGDTODO: This isn't always the most efficient way to do this... in
         # some cases things should use update_datalim_bounds
-        
         if not ma.isMaskedArray(xys):
             xys = npy.asarray(xys)
         self.update_datalim_numerix(xys[:, 0], xys[:, 1])

Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py  2007-10-12 14:29:57 UTC (rev 
3938)
+++ branches/transforms/lib/matplotlib/axis.py  2007-10-12 17:30:17 UTC (rev 
3939)
@@ -91,16 +91,18 @@
         self._size = size
 
         self._padPixels = self.figure.dpi * self._pad * (1/72.0)
+        self._locTransform = Affine2D()
+        
+        self.tick1line = self._get_tick1line()
+        self.tick2line = self._get_tick2line()
+        self.gridline = self._get_gridline()
 
-
-        self.tick1line = self._get_tick1line(loc)
-        self.tick2line = self._get_tick2line(loc)
-        self.gridline = self._get_gridline(loc)
-
-        self.label1 = self._get_text1(loc)
+        self.label1 = self._get_text1()
         self.label = self.label1  # legacy name
-        self.label2 = self._get_text2(loc)
+        self.label2 = self._get_text2()
 
+        self.update_position(loc)
+        
         self.gridOn = gridOn
         self.tick1On = tick1On
         self.tick2On = tick2On
@@ -138,23 +140,23 @@
         'Get the value of the tick label pad in points'
         return self._pad.get()
 
-    def _get_text1(self, loc):
+    def _get_text1(self):
         'Get the default Text 1 instance'
         pass
 
-    def _get_text2(self, loc):
+    def _get_text2(self):
         'Get the default Text 2 instance'
         pass
 
-    def _get_tick1line(self, loc):
+    def _get_tick1line(self):
         'Get the default line2D instance for tick1'
         pass
 
-    def _get_tick2line(self, loc):
+    def _get_tick2line(self):
         'Get the default line2D instance for tick2'
         pass
 
-    def _get_gridline(self, loc):
+    def _get_gridline(self):
         'Get the default grid Line2d instance for this tick'
         pass
 
@@ -183,22 +185,6 @@
 
         renderer.close_group(self.__name__)
 
-    def set_xy(self, loc):
-        """
-        Set the location of tick in data coords with scalar loc
-
-        ACCEPTS: float
-        """
-        raise NotImplementedError('Derived must override')
-
-    def set_label(self, s):  # legacy name
-        """
-        Set the text of ticklabel
-
-        ACCEPTS: str
-        """
-        self.label1.set_text(s)
-
     def set_label1(self, s):
         """
         Set the text of ticklabel
@@ -206,7 +192,8 @@
         ACCEPTS: str
         """
         self.label1.set_text(s)
-
+    set_label = set_label1
+        
     def set_label2(self, s):
         """
         Set the text of ticklabel2
@@ -233,7 +220,7 @@
     the label text and the grid line
     """
     __name__ = 'xtick'
-    def _get_text1(self, loc):
+    def _get_text1(self):
         'Get the default Text instance'
         # the y loc is 3 points below the min of y axis
         # get the affine as an a,b,c,d,tx,ty list
@@ -242,7 +229,7 @@
         trans, vert, horiz = 
self.axes.get_xaxis_text1_transform(self._padPixels)
         
         t =  TextWithDash(
-            x=loc, y=0,
+            x=0, y=0,
             fontproperties=FontProperties(size=rcParams['xtick.labelsize']),
             color=rcParams['xtick.color'],
             verticalalignment=vert,
@@ -256,15 +243,15 @@
         return t
 
 
-    def _get_text2(self, loc):
+    def _get_text2(self):
 
         'Get the default Text 2 instance'
         # x in data coords, y in axes coords
         #t =  Text(
         trans, vert, horiz = 
self.axes.get_xaxis_text2_transform(self._padPixels)
 
-        t =  TextWithDash(
-            x=loc, y=1,
+        t = TextWithDash(
+            x=0, y=1,
             fontproperties=FontProperties(size=rcParams['xtick.labelsize']),
             color=rcParams['xtick.color'],
             verticalalignment=vert,
@@ -272,60 +259,55 @@
             xaxis=True,
             horizontalalignment=horiz,
             )
-
         t.set_transform(trans)
         self._set_artist_props(t)
         return t
 
-    def _get_tick1line(self, loc):
+    def _get_tick1line(self):
         'Get the default line2D instance'
         # x in data coords, y in axes coords
-        l = Line2D( xdata=(loc,), ydata=(0,),
-                    color='k',
-                    linestyle = 'None',
-                    marker = self._xtickmarkers[0],
-                    markersize=self._size,
-                    )
+        l = Line2D(xdata=(0,), ydata=(0,),
+                   color='k',
+                   linestyle = 'None',
+                   marker = self._xtickmarkers[0],
+                   markersize=self._size,
+                   )
         l.set_transform(self.axes.get_xaxis_transform())
         self._set_artist_props(l)
         return l
 
-    def _get_tick2line(self, loc):
+    def _get_tick2line(self):
         'Get the default line2D instance'
         # x in data coords, y in axes coords
-        l = Line2D( xdata=(loc,), ydata=(1,),
+        l = Line2D( xdata=(0,), ydata=(1,),
                        color='k',
                        linestyle = 'None',
                        marker = self._xtickmarkers[1],
                        markersize=self._size,
                        )
 
-        l.set_transform(self.axes.get_xaxis_transform())
+        l.set_transform(self._locTransform + self.axes.get_xaxis_transform())
         self._set_artist_props(l)
         return l
 
-    def _get_gridline(self, loc):
+    def _get_gridline(self):
         'Get the default line2D instance'
         # x in data coords, y in axes coords
-        l = Line2D(xdata=(loc, loc), ydata=(0, 1.0),
+        l = Line2D(xdata=(0.0, 0.0), ydata=(0, 1.0),
                    color=rcParams['grid.color'],
                    linestyle=rcParams['grid.linestyle'],
                    linewidth=rcParams['grid.linewidth'],
                    )
-        l.set_transform(self.axes.get_xaxis_transform())
+        l.set_transform(self._locTransform + self.axes.get_xaxis_transform())
         self._set_artist_props(l)
 
         return l
 
     def update_position(self, loc):
         'Set the location of tick in data coords with scalar loc'
-        x = loc
-
-        self.tick1line.set_xdata((x,))
-        self.tick2line.set_xdata((x,))
-        self.gridline.set_xdata((x, ))
-        self.label1.set_x(x)
-        self.label2.set_x(x)
+        self._locTransform.clear().translate(loc, 0.0)
+        self.label1.set_x(loc)
+        self.label2.set_x(loc)
         self._loc = loc
 
     def get_view_interval(self):
@@ -355,14 +337,14 @@
     __name__ = 'ytick'
 
     # how far from the y axis line the right of the ticklabel are
-    def _get_text1(self, loc):
+    def _get_text1(self):
         'Get the default Text instance'
         # x in axes coords, y in data coords
         #t =  Text(
         trans, vert, horiz = 
self.axes.get_yaxis_text1_transform(self._padPixels)
 
         t = TextWithDash(
-            x=0, y=loc,
+            x=0, y=0,
             fontproperties=FontProperties(size=rcParams['ytick.labelsize']),
             color=rcParams['ytick.color'],
             verticalalignment=vert,
@@ -375,14 +357,14 @@
         self._set_artist_props(t)
         return t
 
-    def _get_text2(self, loc):
+    def _get_text2(self):
         'Get the default Text instance'
         # x in axes coords, y in data coords
         #t =  Text(
         trans, vert, horiz = 
self.axes.get_yaxis_text2_transform(self._padPixels)
 
-        t =  TextWithDash(
-            x=1, y=loc,
+        t = TextWithDash(
+            x=1, y=0,
             fontproperties=FontProperties(size=rcParams['ytick.labelsize']),
             color=rcParams['ytick.color'],
             verticalalignment=vert,
@@ -394,20 +376,20 @@
         self._set_artist_props(t)
         return t
 
-    def _get_tick1line(self, loc):
+    def _get_tick1line(self):
         'Get the default line2D instance'
         # x in axes coords, y in data coords
 
-        l = Line2D( (0,), (loc,), color='k',
+        l = Line2D( (0,), (0,), color='k',
                     marker = self._ytickmarkers[0],
                     linestyle = 'None',
                     markersize=self._size,
                        )
-        l.set_transform(self.axes.get_yaxis_transform())
+        l.set_transform(self._locTransform + self.axes.get_yaxis_transform())
         self._set_artist_props(l)
         return l
 
-    def _get_tick2line(self, loc):
+    def _get_tick2line(self):
         'Get the default line2D instance'
         # x in axes coords, y in data coords
         l = Line2D( (1,), (0,), color='k',
@@ -416,34 +398,29 @@
                     markersize=self._size,
                     )
 
-        l.set_transform(self.axes.get_yaxis_transform())
+        l.set_transform(self._locTransform + self.axes.get_yaxis_transform())
         self._set_artist_props(l)
         return l
 
-    def _get_gridline(self, loc):
+    def _get_gridline(self):
         'Get the default line2D instance'
         # x in axes coords, y in data coords
-        l = Line2D( xdata=(0,1), ydata=(loc,loc),
+        l = Line2D( xdata=(0,1), ydata=(0, 0),
                     color=rcParams['grid.color'],
                     linestyle=rcParams['grid.linestyle'],
                     linewidth=rcParams['grid.linewidth'],
                     )
 
-        l.set_transform(self.axes.get_yaxis_transform())
+        l.set_transform(self._locTransform + self.axes.get_yaxis_transform())
         self._set_artist_props(l)
         return l
 
 
     def update_position(self, loc):
         'Set the location of tick in data coords with scalar loc'
-        y = loc
-        self.tick1line.set_ydata((y,))
-        self.tick2line.set_ydata((y,))
-        self.gridline.set_ydata((y, ))
-
-        self.label1.set_y( y )
-        self.label2.set_y( y )
-
+        self._locTransform.clear().translate(0.0, loc)
+        self.label1.set_y(loc)
+        self.label2.set_y(loc)
         self._loc = loc
 
 
@@ -558,9 +535,11 @@
         popall(self.majorTicks)
         popall(self.minorTicks)
 
-        self.majorTicks.extend([self._get_tick(major=True)  for i in range(1)])
-        self.minorTicks.extend([self._get_tick(major=False) for i in range(1)])
-
+        self.majorTicks.extend([self._get_tick(major=True)])
+        self.minorTicks.extend([self._get_tick(major=False)])
+        self._lastNumMajorTicks = 1
+        self._lastNumMinorTicks = 1
+        
         self.converter = None
         self.units = None
         self.set_units(None)
@@ -744,16 +723,21 @@
         'get the tick instances; grow as necessary'
         if numticks is None:
             numticks = len(self.get_major_locator()())
-        
-        if len(self.majorTicks)<numticks:
+
+        if len(self.majorTicks) < numticks:
             # update the new tick label properties from the old
-            protoTick = self.majorTicks[0]
-            for i in range(numticks-len(self.majorTicks)):
+            for i in range(numticks - len(self.majorTicks)):
                 tick = self._get_tick(major=True)
-                #tick = protoTick
+                self.majorTicks.append(tick)
+            
+        if self._lastNumMajorTicks < numticks:
+            protoTick = self.majorTicks[0]
+            for i in range(self._lastNumMajorTicks, len(self.majorTicks)):
+                tick = self.majorTicks[i]
                 if self._gridOnMajor: tick.gridOn = True
                 self._copy_tick_props(protoTick, tick)
-                self.majorTicks.append(tick)
+
+        self._lastNumMajorTicks = numticks
         ticks = self.majorTicks[:numticks]
 
         return ticks
@@ -764,13 +748,20 @@
         if numticks is None:
             numticks = len(self.get_minor_locator()())
 
-        if len(self.minorTicks)<numticks:
+        if len(self.minorTicks) < numticks:
+            # update the new tick label properties from the old
+            for i in range(numticks - len(self.minorTicks)):
+                tick = self._get_tick(minor=True)
+                self.minorTicks.append(tick)
+            
+        if self._lastNumMinorTicks < numticks:
             protoTick = self.minorTicks[0]
-            for i in range(numticks-len(self.minorTicks)):
-                tick = self._get_tick(major=False)
+            for i in range(self._lastNumMinorTicks, len(self.minorTicks)):
+                tick = self.minorTicks[i]
                 if self._gridOnMinor: tick.gridOn = True
                 self._copy_tick_props(protoTick, tick)
-                self.minorTicks.append(tick)
+
+        self._lastNumMinorTicks = numticks
         ticks = self.minorTicks[:numticks]
 
         return ticks
@@ -946,7 +937,6 @@
 
         self.set_major_formatter( FixedFormatter(ticklabels) )
 
-
         ret = []
         for i, tick in enumerate(self.get_major_ticks()):
             if i<len(ticklabels):

Modified: branches/transforms/lib/matplotlib/colorbar.py
===================================================================
--- branches/transforms/lib/matplotlib/colorbar.py      2007-10-12 14:29:57 UTC 
(rev 3938)
+++ branches/transforms/lib/matplotlib/colorbar.py      2007-10-12 17:30:17 UTC 
(rev 3939)
@@ -314,8 +314,7 @@
                 b = self._boundaries[self._inside]
                 locator = ticker.FixedLocator(b, nbins=10)
         if isinstance(self.norm, colors.NoNorm):
-            intv = transforms.Interval(transforms.Value(self._values[0]),
-                                       transforms.Value(self._values[-1]))
+            intv = self._values[0], self._values[-1]
         else:
             intv = self.vmin, self.vmax
         locator.create_dummy_axis()

Modified: branches/transforms/lib/matplotlib/contour.py
===================================================================
--- branches/transforms/lib/matplotlib/contour.py       2007-10-12 14:29:57 UTC 
(rev 3938)
+++ branches/transforms/lib/matplotlib/contour.py       2007-10-12 17:30:17 UTC 
(rev 3939)
@@ -8,6 +8,7 @@
 import numpy as npy
 import matplotlib.numerix.npyma as ma
 import matplotlib._cntr as _cntr
+import matplotlib.path as path
 import matplotlib.ticker as ticker
 import matplotlib.transforms as transforms
 import matplotlib.cm as cm
@@ -210,7 +211,7 @@
 
         trans = self.ax.transData
 
-        slc = trans.seq_xy_tups(linecontour)
+        slc = trans.transform(linecontour)
         x,y = slc[ind]
         xx= npy.asarray(slc)[:,0].copy()
         yy=npy.asarray(slc)[:,1].copy()
@@ -247,8 +248,9 @@
             new_x1, new_y1 = x-xlabel, y-ylabel
             new_x2, new_y2 = x+xlabel, y+ylabel
 
-        new_x1d, new_y1d = trans.inverse_xy_tup((new_x1, new_y1))
-        new_x2d, new_y2d = trans.inverse_xy_tup((new_x2, new_y2))
+        inverse = trans.inverted()
+        new_x1d, new_y1d = inverse.transform_point((new_x1, new_y1))
+        new_x2d, new_y2d = inverse.transform_point((new_x2, new_y2))
         new_xy1 = npy.array(((new_x1d, new_y1d),))
         new_xy2 = npy.array(((new_x2d, new_y2d),))
 
@@ -333,20 +335,22 @@
             con = self.collections[icon]
             lw = self.get_label_width(lev, fmt, fsize)
             additions = []
-            for segNum, linecontour in enumerate(con._segments):
+            paths = con.get_paths()
+            for segNum, linepath in enumerate(paths):
+                linecontour = linepath.vertices
                 # for closed contours add one more point to
                 # avoid division by zero
                 if npy.all(linecontour[0] == linecontour[-1]):
                     linecontour = npy.concatenate((linecontour,
-                                               linecontour[1][npy.newaxis,:]))
+                                                   
linecontour[1][npy.newaxis,:]))
                     #linecontour.append(linecontour[1])
                 # transfer all data points to screen coordinates
-                slc = trans.seq_xy_tups(linecontour)
+                slc = trans.transform(linecontour)
                 if self.print_label(slc,lw):
                     x,y, rotation, ind  = self.locate_label(slc, lw)
                     # transfer the location of the label back to
                     # data coordinates
-                    dx,dy = trans.inverse_xy_tup((x,y))
+                    dx,dy = trans.inverted().transform_point((x,y))
                     t = text.Text(dx, dy, rotation = rotation,
                              horizontalalignment='center',
                              verticalalignment='center')
@@ -355,12 +359,14 @@
                     self.cl.append(t)
                     self.cl_cvalues.append(cvalue)
                     if inline:
-                        new = self.break_linecontour(linecontour, rotation,
-                                                       lw, ind)
-                        con._segments[segNum] = new[0]
-                        additions.append(new[1])
-            con._segments.extend(additions)
+                        new = self.break_linecontour(linecontour, rotation, 
lw, ind)
+                        if len(new[0]):
+                            paths[segNum] = path.Path(new[0], closed=False)
+                        if len(new[1]):
+                            additions.append(path.Path(new[1], closed=False))
+            paths.extend(additions)
 
+            
 class ContourSet(cm.ScalarMappable, ContourLabeler):
     """
     Create and store a set of contour lines or filled regions.
@@ -494,6 +500,7 @@
         '''
         if self.locator is None:
             self.locator = ticker.MaxNLocator(N+1)
+            self.locator.create_dummy_axis()
         locator = self.locator
         zmax = self.zmax
         zmin = self.zmin

Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py  2007-10-12 14:29:57 UTC (rev 
3938)
+++ branches/transforms/lib/matplotlib/text.py  2007-10-12 17:30:17 UTC (rev 
3939)
@@ -172,7 +172,6 @@
         self._linespacing = other._linespacing
 
     def _get_layout(self, renderer):
-
         # layout the xylocs in display coords as if angle = zero and
         # then rotate them around self._x, self._y
         #return _unit_box
@@ -327,11 +326,10 @@
                                   self._fontproperties, angle)
             return
 
+        canvasw, canvash = renderer.get_canvas_width_height()
         for line, wh, x, y in info:
             x, y = trans.transform_point((x, y))
-            
             if renderer.flipy():
-                canvasw, canvash = renderer.get_canvas_width_height()
                 y = canvash-y
                 
             renderer.draw_text(gc, x, y, line,

Modified: branches/transforms/lib/matplotlib/ticker.py
===================================================================
--- branches/transforms/lib/matplotlib/ticker.py        2007-10-12 14:29:57 UTC 
(rev 3938)
+++ branches/transforms/lib/matplotlib/ticker.py        2007-10-12 17:30:17 UTC 
(rev 3939)
@@ -145,6 +145,11 @@
 
     def set_data_interval(self, vmin, vmax):
         self.axis.set_data_interval(vmin, vmax)
+
+    def set_bounds(self, vmin, vmax):
+        self.set_view_interval(vmin, vmax)
+        self.set_data_interval(vmin, vmax)
+
         
 class Formatter(TickHelper):
     """

Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py    2007-10-12 14:29:57 UTC 
(rev 3938)
+++ branches/transforms/lib/matplotlib/transforms.py    2007-10-12 17:30:17 UTC 
(rev 3939)
@@ -32,8 +32,10 @@
 import cbook
 from path import Path
 
-DEBUG = True
+DEBUG = False
 
+# MGDTODO: Cache get_affine???
+
 class TransformNode(object):
     """
     TransformNode is the base class for anything that participates in
@@ -81,7 +83,7 @@
         # A list of the children is kept around for debugging purposes
         # only.
         self._children = []
-
+        
     def __copy__(self, *args):
         raise NotImplementedError(
             "TransformNode instances can not be copied. " +
@@ -402,13 +404,13 @@
                      self._points[0] + (W, H)])
 
     def splitx(self, *args):
-        '''
+        """
         e.g., bbox.splitx(f1, f2, ...)
 
         Returns a list of new BBoxes formed by
         splitting the original one with vertical lines
         at fractional positions f1, f2, ...
-        '''
+        """
         boxes = []
         xf = [0] + list(args) + [1]
         l, b, r, t = self.lbrt
@@ -418,13 +420,13 @@
         return boxes
 
     def splity(self, *args):
-        '''
+        """
         e.g., bbox.splitx(f1, f2, ...)
 
         Returns a list of new PBoxes formed by
         splitting the original one with horizontal lines
         at fractional positions f1, f2, ...
-        '''
+        """
         boxes = []
         yf = [0] + list(args) + [1]
         l, b, r, t = self.lbrt
@@ -434,6 +436,11 @@
         return boxes
 
     def count_contains(self, vertices):
+        """
+        Count the number of vertices contained in the Bbox.
+
+        vertices is a Nx2 numpy array.
+        """
         if len(vertices) == 0:
             return 0
         vertices = npy.asarray(vertices)
@@ -446,6 +453,11 @@
         return N.sum(inside)
 
     def count_overlaps(self, bboxes):
+        """
+        Count the number of bounding boxes that overlap this one.
+
+        bboxes is a sequence of Bbox objects
+        """
         ax1, ay1, ax2, ay2 = self._get_lbrt()
         if ax2 < ax1:
             ax2, ax1 = ax1, ax2
@@ -454,7 +466,9 @@
 
         count = 0
         for bbox in bboxes:
-            bx1, by1, bx2, by2 = bbox._get_lbrt()
+            # bx1, by1, bx2, by2 = bbox._get_lbrt()
+            # The above, inlined...
+            bx1, by1, bx2, by2 = bbox.get_points().flatten()
             if bx2 < bx1:
                 bx2, bx1 = bx1, bx2
             if by2 < by1:
@@ -464,7 +478,53 @@
                            (bx1 >= ax2) or
                            (by1 >= ay2)))
         return count
-            
+
+    def expanded(self, sw, sh):
+        """
+        Return a new Bbox which is this Bbox expanded around its
+        center by the given factors sw and sh.
+        """
+        width = self.width
+        height = self.height
+        deltaw = (sw * width - width) / 2.0
+        deltah = (sh * height - height) / 2.0
+        a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
+        return Bbox(self._points + a)
+
+    def translated(self, tx, ty):
+        """
+        Return a copy of the Bbox, translated by tx and ty.
+        """
+        return Bbox(self._points + (tx, ty))
+
+    [EMAIL PROTECTED]
+    def union(bboxes):
+        """
+        Return a Bbox that contains all of the given bboxes.
+        """
+        assert(len(bboxes))
+
+        if len(bboxes) == 1:
+            return bboxes[0]
+
+        xmin = npy.inf
+        ymin = npy.inf
+        xmax = -npy.inf
+        ymax = -npy.inf
+
+        for bbox in bboxes:
+            points = bbox.get_points()
+            xs = points[:, 0]
+            ys = points[:, 1]
+            xmin = min(xmin, npy.min(xs))
+            ymin = min(ymin, npy.min(ys))
+            xmax = max(xmax, npy.max(xs))
+            ymax = max(ymax, npy.max(ys))
+
+        return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
+    union = staticmethod(union)
+    
+    
 class Bbox(BboxBase):
     def __init__(self, points):
         """
@@ -535,7 +595,6 @@
            when None, use the last value passed to Bbox.ignore().
         """
         # MGDTODO: It may be more efficient for some callers to use 
update_from_data_xy instead
-
         if ignore is None:
             ignore = self._ignore
 
@@ -569,7 +628,6 @@
                   max(y.max(), self.ymax)]],
                 npy.float_)
             self._minpos = npy.minimum(minpos, self._minpos)
-
         self.invalidate()
 
     def update_from_data_xy(self, xy, ignore=None):
@@ -665,52 +723,7 @@
         """
         self._points = other.get_points()
         self.invalidate()
-        
-    def expanded(self, sw, sh):
-        """
-        Return a new Bbox which is this Bbox expanded around its
-        center by the given factors sw and sh.
-        """
-        width = self.width
-        height = self.height
-        deltaw = (sw * width - width) / 2.0
-        deltah = (sh * height - height) / 2.0
-        a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
-        return Bbox(self._points + a)
 
-    def translated(self, tx, ty):
-        """
-        Return a copy of the Bbox, translated by tx and ty.
-        """
-        return Bbox(self._points + (tx, ty))
-
-    [EMAIL PROTECTED]
-    def union(bboxes):
-        """
-        Return a Bbox that contains all of the given bboxes.
-        """
-        assert(len(bboxes))
-
-        if len(bboxes) == 1:
-            return bboxes[0]
-
-        xmin = npy.inf
-        ymin = npy.inf
-        xmax = -npy.inf
-        ymax = -npy.inf
-
-        for bbox in bboxes:
-            points = bbox.get_points()
-            xs = points[:, 0]
-            ys = points[:, 1]
-            xmin = min(xmin, npy.min(xs))
-            ymin = min(ymin, npy.min(ys))
-            xmax = max(xmax, npy.max(xs))
-            ymax = max(ymax, npy.max(ys))
-
-        return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
-    union = staticmethod(union)
-
     
 class TransformedBbox(BboxBase):
     """
@@ -1633,15 +1646,39 @@
         else:
             return npy.concatenate((x_points, y_points), 1)
     transform.__doc__ = Transform.transform.__doc__
-    
-    transform_non_affine = transform
+
+    def transform_affine(self, points):
+        if self._x.is_affine and self._y.is_affine:
+            return self.transform(points)
+        return points
+    transform_affine.__doc__ = Transform.transform_affine.__doc__
+
+    def transform_non_affine(self, points):
+        if self._x.is_affine and self._y.is_affine:
+            return points
+        return self.transform(points)
     transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__
 
     def inverted(self):
         return BlendedGenericTransform(self._x.inverted(), self._y.inverted())
     inverted.__doc__ = Transform.inverted.__doc__
-    
 
+    def get_affine(self):
+        if self._x.is_affine and self._y.is_affine:
+            if self._x == self._y:
+                return self._x.get_affine()
+            else:
+                x_mtx = self._x.get_affine().get_matrix()
+                y_mtx = self._y.get_affine().get_matrix()
+                # This works because we already know the transforms are
+                # separable, though normally one would want to set b and
+                # c to zero.
+                mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
+                return Affine2D(mtx)
+        return IdentityTransform()
+    get_affine.__doc__ = Transform.get_affine.__doc__
+
+
 class BlendedAffine1D(Affine2DBase):
     """
     A "blended" transform uses one transform for the x-direction, and
@@ -1807,7 +1844,7 @@
     is_affine = property(_get_is_affine)
         
     def _get_is_separable(self):
-        return self._a.is_separable() and self._b.is_separable()
+        return self._a.is_separable and self._b.is_separable
     is_separable = property(_get_is_separable)
         
     def __repr__(self):
@@ -1838,7 +1875,7 @@
     
     def transform_path_affine(self, path):
         return self._b.transform_path_affine(
-            self._a.transform(path))
+            self._a.transform_path(path))
     transform_path_affine.__doc__ = Transform.transform_path_affine.__doc__
 
     def transform_path_non_affine(self, path):
@@ -1850,7 +1887,8 @@
     
     def get_affine(self):
         if self._a.is_affine and self._b.is_affine:
-            return CompositeAffine2D(self._a.get_affine(), 
self._b.get_affine())
+            return Affine2D(npy.dot(self._b.get_affine().get_matrix(),
+                                    self._a.get_affine().get_matrix()))
         return self._b.get_affine()
     get_affine.__doc__ = Transform.get_affine.__doc__
     

Modified: branches/transforms/src/_backend_agg.cpp
===================================================================
--- branches/transforms/src/_backend_agg.cpp    2007-10-12 14:29:57 UTC (rev 
3938)
+++ branches/transforms/src/_backend_agg.cpp    2007-10-12 17:30:17 UTC (rev 
3939)
@@ -82,7 +82,10 @@
       return agg::trans_affine(a, b, c, d, e, f);
     }
   } catch (...) {
-    
+    if (errors) {
+      Py_XDECREF(matrix);
+      throw;
+    }
   }
 
   Py_XDECREF(matrix);
@@ -333,8 +336,10 @@
 
 bool
 RendererAgg::bbox_to_rect(const Py::Object& bbox_obj, double* l, double* b, 
double* r, double* t) {
+  PyArrayObject* bbox = NULL;
+
   if (bbox_obj.ptr() != Py_None) {
-    PyArrayObject* bbox = (PyArrayObject*) PyArray_FromObject(bbox_obj.ptr(), 
PyArray_DOUBLE, 2, 2);   
+    bbox = (PyArrayObject*) PyArray_FromObject(bbox_obj.ptr(), PyArray_DOUBLE, 
2, 2);   
 
     if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || 
bbox->dimensions[1] != 2) {
       Py_XDECREF(bbox);
@@ -559,9 +564,9 @@
 
   PathIterator path(path_obj);
   transformed_path_t path_transformed(path, trans);
-  bool snap = should_snap(path, trans);
-  GCAgg gc = GCAgg(gc_obj, dpi, snap);
-  quantize_t path_quantized(path_transformed, snap);
+  // bool snap = should_snap(path, trans);
+  GCAgg gc = GCAgg(gc_obj, dpi, true);
+  quantize_t path_quantized(path_transformed, true);
   path_quantized.rewind(0);
 
   facepair_t face = _get_rgba_face(face_obj, gc.alpha);
@@ -638,6 +643,7 @@
   } catch(...) {
     delete[] fillCache;
     delete[] strokeCache;
+    throw;
   }
   
   delete [] fillCache;
@@ -879,7 +885,7 @@
       theRasterizer->add_path(stroke);
     }
     
-    if (gc.isaa && !(snap && gc.dashes.size())) {
+    if (gc.isaa && !(snap && gc.linewidth < 1.5)) {
       if (has_clippath) {
        pixfmt_amask_type pfa(*pixFmt, *alphaMask);
        amask_ren_type r(pfa);
@@ -954,99 +960,110 @@
   
   GCAgg gc(dpi, false);
 
-  PyArrayObject* offsets = 
(PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2);
-  if (!offsets || offsets->dimensions[1] != 2)
-    throw Py::ValueError("Offsets array must be Nx2");
+  PyArrayObject* offsets    = NULL;
+  PyArrayObject* facecolors = NULL;
+  PyArrayObject* edgecolors = NULL;
 
-  PyArrayObject* facecolors = 
(PyArrayObject*)PyArray_FromObject(facecolors_obj.ptr(), PyArray_DOUBLE, 1, 2);
-  if (!facecolors || 
-      (facecolors->nd == 1 && facecolors->dimensions[0] != 0) || 
-      (facecolors->nd == 2 && facecolors->dimensions[1] != 4))
-    throw Py::ValueError("Facecolors must be a Nx4 numpy array or empty");
+  try {
+    offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), 
PyArray_DOUBLE, 2, 2);
+    if (!offsets || offsets->dimensions[1] != 2)
+      throw Py::ValueError("Offsets array must be Nx2");
 
-  PyArrayObject* edgecolors = 
(PyArrayObject*)PyArray_FromObject(edgecolors_obj.ptr(), PyArray_DOUBLE, 1, 2);
-  if (!edgecolors || 
-      (edgecolors->nd == 1 && edgecolors->dimensions[0] != 0) || 
-      (edgecolors->nd == 2 && edgecolors->dimensions[1] != 4))
-    throw Py::ValueError("Edgecolors must be a Nx4 numpy array");
+    PyArrayObject* facecolors = 
(PyArrayObject*)PyArray_FromObject(facecolors_obj.ptr(), PyArray_DOUBLE, 1, 2);
+    if (!facecolors || 
+       (facecolors->nd == 1 && facecolors->dimensions[0] != 0) || 
+       (facecolors->nd == 2 && facecolors->dimensions[1] != 4))
+      throw Py::ValueError("Facecolors must be a Nx4 numpy array or empty");
 
-  size_t Npaths             = paths.length();
-  size_t Noffsets    = offsets->dimensions[0];
-  size_t N          = std::max(Npaths, Noffsets);
-  size_t Ntransforms = std::min(transforms_obj.length(), N);
-  size_t Nfacecolors = facecolors->dimensions[0];
-  size_t Nedgecolors = edgecolors->dimensions[0];
-  size_t Nlinewidths = linewidths.length();
-  size_t Nlinestyles = std::min(linestyles_obj.length(), N);
-  size_t Naa        = antialiaseds.length();
+    PyArrayObject* edgecolors = 
(PyArrayObject*)PyArray_FromObject(edgecolors_obj.ptr(), PyArray_DOUBLE, 1, 2);
+    if (!edgecolors || 
+       (edgecolors->nd == 1 && edgecolors->dimensions[0] != 0) || 
+       (edgecolors->nd == 2 && edgecolors->dimensions[1] != 4))
+      throw Py::ValueError("Edgecolors must be a Nx4 numpy array");
+    
+    size_t Npaths      = paths.length();
+    size_t Noffsets    = offsets->dimensions[0];
+    size_t N          = std::max(Npaths, Noffsets);
+    size_t Ntransforms = std::min(transforms_obj.length(), N);
+    size_t Nfacecolors = facecolors->dimensions[0];
+    size_t Nedgecolors = edgecolors->dimensions[0];
+    size_t Nlinewidths = linewidths.length();
+    size_t Nlinestyles = std::min(linestyles_obj.length(), N);
+    size_t Naa        = antialiaseds.length();
 
-  if ((Nfacecolors == 0 && Nedgecolors == 0) || N == 0)
-    return Py::Object();
-
-  size_t i        = 0;
-
-  // Convert all of the transforms up front
-  typedef std::vector<agg::trans_affine> transforms_t;
-  transforms_t transforms;
-  transforms.reserve(Ntransforms);
-  for (i = 0; i < Ntransforms; ++i) {
-    agg::trans_affine trans = py_to_agg_transformation_matrix
-      (transforms_obj[i], false);
-    trans *= master_transform;
-    transforms.push_back(trans);
-  }
-
-  // Convert all the dashes up front
-  typedef std::vector<std::pair<double, GCAgg::dash_t> > dashes_t;
-  dashes_t dashes;
-  dashes.resize(Nlinestyles);
-  i = 0;
-  for (dashes_t::iterator d = dashes.begin(); 
-       d != dashes.end(); ++d, ++i) {
-    convert_dashes(Py::Tuple(linestyles_obj[i]), false, dpi, d->second, 
d->first);
-  }
-
-  // Handle any clipping globally
-  theRasterizer->reset_clipping();
-  rendererBase->reset_clipping(true);
-  set_clipbox(cliprect, theRasterizer);
-  bool has_clippath = render_clippath(clippath, clippath_trans);
-
-  // Set some defaults, assuming no face or edge
-  gc.linewidth = 0.0;
-  facepair_t face;
-  face.first = Nfacecolors != 0;
-
-  for (i = 0; i < N; ++i) {
-    PathIterator path(paths[i % Npaths]);
-    bool snap = (path.total_vertices() == 2);
-    double xo                = *(double*)PyArray_GETPTR2(offsets, i % 
Noffsets, 0);
-    double yo                = *(double*)PyArray_GETPTR2(offsets, i % 
Noffsets, 1);
-    offset_trans.transform(&xo, &yo);
-    agg::trans_affine_translation transOffset(xo, yo);
-    agg::trans_affine& trans = transforms[i % Ntransforms];
-
-    if (Nfacecolors) {
-      size_t fi = i % Nfacecolors;
-      face.second            = agg::rgba(*(double*)PyArray_GETPTR2(facecolors, 
fi, 0),
-                                        *(double*)PyArray_GETPTR2(facecolors, 
fi, 1),
-                                        *(double*)PyArray_GETPTR2(facecolors, 
fi, 2),
-                                        *(double*)PyArray_GETPTR2(facecolors, 
fi, 3));
+    if ((Nfacecolors == 0 && Nedgecolors == 0) || N == 0)
+      return Py::Object();
+    
+    size_t i        = 0;
+    
+    // Convert all of the transforms up front
+    typedef std::vector<agg::trans_affine> transforms_t;
+    transforms_t transforms;
+    transforms.reserve(Ntransforms);
+    for (i = 0; i < Ntransforms; ++i) {
+      agg::trans_affine trans = py_to_agg_transformation_matrix
+       (transforms_obj[i], false);
+      trans *= master_transform;
+      transforms.push_back(trans);
     }
-
-    if (Nedgecolors) {
-      size_t ei = i % Nedgecolors;
-      gc.color               = agg::rgba(*(double*)PyArray_GETPTR2(edgecolors, 
ei, 0),
-                                        *(double*)PyArray_GETPTR2(edgecolors, 
ei, 1),
-                                        *(double*)PyArray_GETPTR2(edgecolors, 
ei, 2),
-                                        *(double*)PyArray_GETPTR2(edgecolors, 
ei, 3));
-      gc.linewidth          = double(Py::Float(linewidths[i % Nlinewidths])) * 
dpi/72.0;
-      gc.dashes                     = dashes[i % Nlinestyles].second;
-      gc.dashOffset         = dashes[i % Nlinestyles].first;
+    
+    // Convert all the dashes up front
+    typedef std::vector<std::pair<double, GCAgg::dash_t> > dashes_t;
+    dashes_t dashes;
+    dashes.resize(Nlinestyles);
+    i = 0;
+    for (dashes_t::iterator d = dashes.begin(); 
+        d != dashes.end(); ++d, ++i) {
+      convert_dashes(Py::Tuple(linestyles_obj[i]), false, dpi, d->second, 
d->first);
     }
-
-    gc.isaa                 = bool(Py::Int(antialiaseds[i % Naa]));
-    _draw_path(path, trans * transOffset, snap, has_clippath, face, gc);
+    
+    // Handle any clipping globally
+    theRasterizer->reset_clipping();
+    rendererBase->reset_clipping(true);
+    set_clipbox(cliprect, theRasterizer);
+    bool has_clippath = render_clippath(clippath, clippath_trans);
+    
+    // Set some defaults, assuming no face or edge
+    gc.linewidth = 0.0;
+    facepair_t face;
+    face.first = Nfacecolors != 0;
+    
+    for (i = 0; i < N; ++i) {
+      PathIterator path(paths[i % Npaths]);
+      bool snap = (path.total_vertices() == 2);
+      double xo                = *(double*)PyArray_GETPTR2(offsets, i % 
Noffsets, 0);
+      double yo                = *(double*)PyArray_GETPTR2(offsets, i % 
Noffsets, 1);
+      offset_trans.transform(&xo, &yo);
+      agg::trans_affine_translation transOffset(xo, yo);
+      agg::trans_affine& trans = transforms[i % Ntransforms];
+      
+      if (Nfacecolors) {
+       size_t fi = i % Nfacecolors;
+       face.second            = 
agg::rgba(*(double*)PyArray_GETPTR2(facecolors, fi, 0),
+                                          
*(double*)PyArray_GETPTR2(facecolors, fi, 1),
+                                          
*(double*)PyArray_GETPTR2(facecolors, fi, 2),
+                                          
*(double*)PyArray_GETPTR2(facecolors, fi, 3));
+      }
+      
+      if (Nedgecolors) {
+       size_t ei = i % Nedgecolors;
+       gc.color               = 
agg::rgba(*(double*)PyArray_GETPTR2(edgecolors, ei, 0),
+                                          
*(double*)PyArray_GETPTR2(edgecolors, ei, 1),
+                                          
*(double*)PyArray_GETPTR2(edgecolors, ei, 2),
+                                          
*(double*)PyArray_GETPTR2(edgecolors, ei, 3));
+       gc.linewidth           = double(Py::Float(linewidths[i % Nlinewidths])) 
* dpi/72.0;
+       gc.dashes                    = dashes[i % Nlinestyles].second;
+       gc.dashOffset          = dashes[i % Nlinestyles].first;
+      }
+      
+      gc.isaa                 = bool(Py::Int(antialiaseds[i % Naa]));
+      _draw_path(path, trans * transOffset, snap, has_clippath, face, gc);
+    }
+  } catch (...) {
+    Py_XDECREF(offsets);
+    Py_XDECREF(facecolors);
+    Py_XDECREF(edgecolors);
+    throw;
   }
 
   Py_XDECREF(offsets);
@@ -1518,18 +1535,15 @@
 
 void get_path_extents(PathIterator& path, agg::trans_affine& trans, 
                      double* x0, double* y0, double* x1, double* y1) {
-  typedef agg::conv_curve<PathIterator> curve_t;
-  
-  curve_t curved_path(path);
+  typedef agg::conv_transform<PathIterator> transformed_path_t;
+  typedef agg::conv_curve<transformed_path_t> curve_t;
   double x, y;
-  curved_path.rewind(0);
+  unsigned code;
 
-  unsigned code = curved_path.vertex(&x, &y);
+  transformed_path_t tpath(path, trans);
+  curve_t curved_path(tpath);
 
-  *x0 = x;
-  *y0 = y;
-  *x1 = x;
-  *y1 = y;
+  curved_path.rewind(0);
 
   while ((code = curved_path.vertex(&x, &y)) != agg::path_cmd_stop) {
     if (code & agg::path_cmd_end_poly == agg::path_cmd_end_poly)
@@ -1539,9 +1553,6 @@
     if (x > *x1) *x1 = x;
     if (y > *y1) *y1 = y;
   }
-
-  trans.transform(x0, y0);
-  trans.transform(x1, y1);
 }
 
 Py::Object _backend_agg_module::get_path_extents(const Py::Tuple& args) {
@@ -1550,7 +1561,11 @@
   PathIterator path(args[0]);
   agg::trans_affine trans = py_to_agg_transformation_matrix(args[1]);
 
-  double x0, y0, x1, y1;
+  double x0 = std::numeric_limits<double>::infinity();
+  double y0 = std::numeric_limits<double>::infinity();
+  double x1 = -std::numeric_limits<double>::infinity();
+  double y1 = -std::numeric_limits<double>::infinity();
+
   ::get_path_extents(path, trans, &x0, &y0, &x1, &y1);
 
   Py::Tuple result(4);
@@ -1561,10 +1576,6 @@
   return result;
 }
 
-struct PathCollectionExtents {
-  double x0, y0, x1, y1;
-};
-
 Py::Object _backend_agg_module::get_path_collection_extents(const Py::Tuple& 
args) {
   args.verify_length(5);
 
@@ -1572,57 +1583,58 @@
   agg::trans_affine      master_transform = 
py_to_agg_transformation_matrix(args[0]);
   Py::SeqBase<Py::Object> paths                   = args[1];
   Py::SeqBase<Py::Object> transforms_obj   = args[2];
-  Py::SeqBase<Py::Object> offsets          = args[3];
+  Py::Object              offsets_obj      = args[3];
   agg::trans_affine       offset_trans     = 
py_to_agg_transformation_matrix(args[4], false);
 
-  size_t Npaths             = paths.length();
-  size_t Noffsets    = offsets.length();
-  size_t N          = std::max(Npaths, Noffsets);
-  size_t Ntransforms = std::min(transforms_obj.length(), N);
-  size_t i;
+  PyArrayObject* offsets = NULL;
+  double x0, y0, x1, y1;
 
-  // Convert all of the transforms up front
-  typedef std::vector<agg::trans_affine> transforms_t;
-  transforms_t transforms;
-  transforms.reserve(Ntransforms);
-  for (i = 0; i < Ntransforms; ++i) {
-    agg::trans_affine trans = py_to_agg_transformation_matrix
-      (transforms_obj[i], false);
-    trans *= master_transform;
-    transforms.push_back(trans);
-  }
-  
-  typedef std::vector<PathCollectionExtents> path_extents_t;
-  path_extents_t path_extents;
-  path_extents.resize(Npaths);
+  try {
+    offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), 
PyArray_DOUBLE, 2, 2);
+    if (!offsets || offsets->dimensions[1] != 2)
+      throw Py::ValueError("Offsets array must be Nx2");
 
-  // Get each of the path extents first
-  i = 0;
-  for (path_extents_t::iterator p = path_extents.begin();
-       p != path_extents.end(); ++p, ++i) {
-    PathIterator path(paths[i]);
-    agg::trans_affine& trans = transforms[i % Ntransforms];
-    ::get_path_extents(path, trans, &p->x0, &p->y0, &p->x1, &p->y1);
-  }
+    size_t Npaths      = paths.length();
+    size_t Noffsets    = offsets->dimensions[0];
+    size_t N          = std::max(Npaths, Noffsets);
+    size_t Ntransforms = std::min(transforms_obj.length(), N);
+    size_t i;
 
-  // The offset each of those and collect the mins/maxs
-  double x0 = std::numeric_limits<double>::infinity();
-  double y0 = std::numeric_limits<double>::infinity();
-  double x1 = -std::numeric_limits<double>::infinity();
-  double y1 = -std::numeric_limits<double>::infinity();
-  for (i = 0; i < N; ++i) {
-    Py::SeqBase<Py::Float> offset = Py::SeqBase<Py::Float>(offsets[i % 
Noffsets]);
-    double xo                = Py::Float(offset[0]);
-    double yo                = Py::Float(offset[1]);
-    offset_trans.transform(&xo, &yo);
-    PathCollectionExtents& ext = path_extents[i % Npaths];
+    // Convert all of the transforms up front
+    typedef std::vector<agg::trans_affine> transforms_t;
+    transforms_t transforms;
+    transforms.reserve(Ntransforms);
+    for (i = 0; i < Ntransforms; ++i) {
+      agg::trans_affine trans = py_to_agg_transformation_matrix
+       (transforms_obj[i], false);
+      trans *= master_transform;
+      transforms.push_back(trans);
+    }
+    
+    // The offset each of those and collect the mins/maxs
+    x0 = std::numeric_limits<double>::infinity();
+    y0 = std::numeric_limits<double>::infinity();
+    x1 = -std::numeric_limits<double>::infinity();
+    y1 = -std::numeric_limits<double>::infinity();
+    for (i = 0; i < N; ++i) {
+      PathIterator path(paths[i % Npaths]);
+      
+      double xo                = *(double*)PyArray_GETPTR2(offsets, i % 
Noffsets, 0);
+      double yo                = *(double*)PyArray_GETPTR2(offsets, i % 
Noffsets, 1);
+      offset_trans.transform(&xo, &yo);
+      agg::trans_affine_translation transOffset(xo, yo);
+      agg::trans_affine trans = transforms[i % Ntransforms];
+      trans *= transOffset;
 
-    x0 = std::min(x0, ext.x0 + xo);
-    y0 = std::min(y0, ext.y0 + yo);
-    x1 = std::max(x1, ext.x1 + xo);
-    y1 = std::max(y1, ext.y1 + yo);
+      ::get_path_extents(path, trans, &x0, &y0, &x1, &y1);
+    }
+  } catch (...) {
+    Py_XDECREF(offsets);
+    throw;
   }
 
+  Py_XDECREF(offsets);
+
   Py::Tuple result(4);
   result[0] = Py::Float(x0);
   result[1] = Py::Float(y0);


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to