Revision: 4305
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4305&view=rev
Author:   mdboom
Date:     2007-11-15 07:18:42 -0800 (Thu, 15 Nov 2007)

Log Message:
-----------
Speed improvements.

Modified Paths:
--------------
    branches/transforms/lib/matplotlib/path.py
    branches/transforms/lib/matplotlib/transforms.py
    branches/transforms/src/_backend_agg.cpp
    branches/transforms/src/_path.cpp

Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py  2007-11-15 15:15:21 UTC (rev 
4304)
+++ branches/transforms/lib/matplotlib/path.py  2007-11-15 15:18:42 UTC (rev 
4305)
@@ -160,31 +160,33 @@
     
     def iter_segments(self):
         """
-        Iterates over all of the endpoints in the path.  Unlike
-        iterating directly over the vertices array, curve control
-        points are skipped over.
+        Iterates over all of the curve segments in the path.
         """
-       i = 0
-       NUM_VERTICES = self.NUM_VERTICES
        vertices = self.vertices
         codes = self.codes
+        len_vertices = len(vertices)
 
+       NUM_VERTICES = self.NUM_VERTICES
+        MOVETO = self.MOVETO
+        LINETO = self.LINETO
+        CLOSEPOLY = self.CLOSEPOLY
+        STOP = self.STOP
+        
         if not len(vertices):
             return
         
         if codes is None:
-            code = self.MOVETO
-            yield vertices[0], self.MOVETO
-            i = 1
+            yield vertices[0], MOVETO
             for v in vertices[1:]:
-                yield v, self.LINETO
+                yield v, LINETO
         else:
-            while i < len(vertices):
+            i = 0
+            while i < len_vertices:
                 code = codes[i]
-                if code == self.CLOSEPOLY:
+                if code == CLOSEPOLY:
                     yield [], code
                     i += 1
-                elif code == self.STOP:
+                elif code == STOP:
                     return
                 else:
                     num_vertices = NUM_VERTICES[code]

Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py    2007-11-15 15:15:21 UTC 
(rev 4304)
+++ branches/transforms/lib/matplotlib/transforms.py    2007-11-15 15:18:42 UTC 
(rev 4305)
@@ -25,6 +25,7 @@
 
 import numpy as npy
 from matplotlib.numerix import npyma as ma
+from matplotlib._path import affine_transform
 from numpy.linalg import inv
 
 from weakref import WeakKeyDictionary
@@ -1206,10 +1207,13 @@
         mtx = self.get_matrix()
         if ma.isMaskedArray(points):
             points = ma.dot(mtx[0:2, 0:2], points.transpose()) + mtx[0:2, 2:]
-        else:
-            points = npy.dot(mtx[0:2, 0:2], points.transpose()) + mtx[0:2, 2:]
-        return points.transpose()
+            return points.transpose()
+        return affine_transform(points, mtx)
 
+    def transform_point(self, point):
+        mtx = self.get_matrix()
+        return affine_transform(point, mtx)
+    
     if DEBUG:
         _transform = transform
         def transform(self, points):
@@ -1251,7 +1255,7 @@
         Affine2DBase.__init__(self)
         if matrix is None:
             matrix = npy.identity(3)
-        else:
+        elif DEBUG:
            matrix = npy.asarray(matrix, npy.float_)
             assert matrix.shape == (3, 3)
         self._mtx = matrix
@@ -1276,7 +1280,9 @@
           b d f
           0 0 1
         """
-        return Affine2D(Affine2D.matrix_from_values(a, b, c, d, e, f))
+        return Affine2D(
+            npy.array([a, c, e, b, d, f, 0.0, 0.0, 1.0], npy.float_)
+            .reshape((3,3)))
     from_values = staticmethod(from_values)
 
     def get_matrix(self):

Modified: branches/transforms/src/_backend_agg.cpp
===================================================================
--- branches/transforms/src/_backend_agg.cpp    2007-11-15 15:15:21 UTC (rev 
4304)
+++ branches/transforms/src/_backend_agg.cpp    2007-11-15 15:18:42 UTC (rev 
4305)
@@ -282,8 +282,8 @@
 
   double l, b, r, t;
   if (py_convert_bbox(cliprect.ptr(), l, b, r, t)) {
-    rasterizer->clip_box(int(round(l)) + 1, height - int(round(b)) + 1, 
-                        int(round(r)) + 1, height - int(round(t)) + 1);
+    rasterizer->clip_box(int(round(l)) + 1, height - int(round(b)), 
+                        int(round(r)),     height - int(round(t)));
   }
 
   _VERBOSE("RendererAgg::set_clipbox done");
@@ -526,8 +526,6 @@
     strokeCache = new agg::int8u[strokeSize]; // or any container
     scanlines.serialize(strokeCache);
     
-    theRasterizer->reset_clipping();
-    rendererBase->reset_clipping(true);
     set_clipbox(gc.cliprect, rendererBase);
     bool has_clippath = render_clippath(gc.clippath, gc.clippath_trans);
     
@@ -536,34 +534,41 @@
     agg::serialized_scanlines_adaptor_aa8 sa;
     agg::serialized_scanlines_adaptor_aa8::embedded_scanline sl;
 
-    while (path_quantized.vertex(&x, &y) != agg::path_cmd_stop) {
-      //render the fill
-      if (face.first) {
-       if (has_clippath) {
-         pixfmt_amask_type pfa(*pixFmt, *alphaMask);
-         amask_ren_type r(pfa);
-         amask_aa_renderer_type ren(r);
+    if (face.first) {
+      // render the fill
+      if (has_clippath) {
+       pixfmt_amask_type pfa(*pixFmt, *alphaMask);
+       amask_ren_type r(pfa);
+       amask_aa_renderer_type ren(r);
+       ren.color(face.second);
+       while (path_quantized.vertex(&x, &y) != agg::path_cmd_stop) {
          sa.init(fillCache, fillSize, x, y);
-         ren.color(face.second);
          agg::render_scanlines(sa, sl, ren);
-       } else {
+       }
+      } else {
+       rendererAA->color(face.second);
+       while (path_quantized.vertex(&x, &y) != agg::path_cmd_stop) {
          sa.init(fillCache, fillSize, x, y);
-         rendererAA->color(face.second);
          agg::render_scanlines(sa, sl, *rendererAA);
        }
       }
-      
-      //render the stroke
-      if (has_clippath) {
-       pixfmt_amask_type pfa(*pixFmt, *alphaMask);
-       amask_ren_type r(pfa);
-       amask_aa_renderer_type ren(r);
+      path_quantized.rewind(0);
+    }
+
+    //render the stroke
+    if (has_clippath) {
+      pixfmt_amask_type pfa(*pixFmt, *alphaMask);
+      amask_ren_type r(pfa);
+      amask_aa_renderer_type ren(r);
+      ren.color(gc.color);
+      while (path_quantized.vertex(&x, &y) != agg::path_cmd_stop) {
        sa.init(strokeCache, strokeSize, x, y);
-       ren.color(gc.color);
        agg::render_scanlines(sa, sl, ren);
-      } else {
+      }
+    } else {
+      rendererAA->color(gc.color);
+      while (path_quantized.vertex(&x, &y) != agg::path_cmd_stop) {
        sa.init(strokeCache, strokeSize, x, y);
-       rendererAA->color(gc.color);
        agg::render_scanlines(sa, sl, *rendererAA);
       }
     }
@@ -880,8 +885,6 @@
   GCAgg gc = GCAgg(gc_obj, dpi);
   facepair_t face = _get_rgba_face(face_obj, gc.alpha);
   
-  theRasterizer->reset_clipping();
-  rendererBase->reset_clipping(true);
   set_clipbox(gc.cliprect, theRasterizer);
   bool has_clippath = render_clippath(gc.clippath, gc.clippath_trans);
 

Modified: branches/transforms/src/_path.cpp
===================================================================
--- branches/transforms/src/_path.cpp   2007-11-15 15:15:21 UTC (rev 4304)
+++ branches/transforms/src/_path.cpp   2007-11-15 15:18:42 UTC (rev 4305)
@@ -11,6 +11,13 @@
 
 // MGDTODO: Un-CXX-ify this module
 
+struct XY {
+  double x;
+  double y;
+
+  XY(double x_, double y_) : x(x_), y(y_) {}
+};
+
 // the extension module
 class _path_module : public Py::ExtensionModule<_path_module>
 {
@@ -32,7 +39,9 @@
                       "point_in_path_collection(a, atrans, b, btrans)");
     add_varargs_method("clip_path_to_rect", &_path_module::clip_path_to_rect,
                       "clip_path_to_rect(path, bbox, inside)");
-
+    add_varargs_method("affine_transform", &_path_module::affine_transform,
+                      "affine_transform(vertices, transform)");
+    
     initialize("Helper functions for paths");
   }
 
@@ -47,6 +56,7 @@
   Py::Object point_in_path_collection(const Py::Tuple& args);
   Py::Object path_in_path(const Py::Tuple& args);
   Py::Object clip_path_to_rect(const Py::Tuple& args);
+  Py::Object affine_transform(const Py::Tuple& args);
 };
 
 //
@@ -97,7 +107,7 @@
   inside_flag = 0;
 
   unsigned code = 0;
-  while (true) {
+  do {
     if (code != agg::path_cmd_move_to)
       code = path.vertex(&x, &y);
 
@@ -111,7 +121,7 @@
     vty1 = x;
 
     inside_flag = 0;
-    while (true) {
+    do {
       code = path.vertex(&x, &y);
 
       // The following cases denote the beginning on a new subpath
@@ -151,12 +161,9 @@
        
       vtx1 = x;
       vty1 = y;
+    } while (code != agg::path_cmd_stop && 
+            (code & agg::path_cmd_end_poly) != agg::path_cmd_end_poly);
 
-      if (code == agg::path_cmd_stop || 
-         (code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly)
-       break;
-    }
-
     yflag1 = (vty1 >= ty);
     if (yflag0 != yflag1) {
       if ( ((vty1-ty) * (vtx0-vtx1) >=
@@ -167,11 +174,8 @@
 
     if (inside_flag != 0)
       return true;
+  } while (code != agg::path_cmd_stop);
 
-    if (code == agg::path_cmd_stop)
-      break;
-  }
-
   return (inside_flag != 0);
 }
 
@@ -453,7 +457,7 @@
   http://en.wikipedia.org/wiki/Sutherland-Hodgman_clipping_algorithm
 */
 
-typedef std::vector<std::pair<double, double> > Polygon;
+typedef std::vector<XY> Polygon;
 
 namespace clip_to_rect_filters {
   /* There are four different passes needed to create/remove vertices
@@ -476,7 +480,7 @@
   struct xlt : public bisectx {
     xlt(double x) : bisectx(x) {}
 
-    bool operator()(double x, double y) const {
+    bool is_inside(double x, double y) const {
       return x <= m_x;
     }
   };
@@ -484,7 +488,7 @@
   struct xgt : public bisectx {
     xgt(double x) : bisectx(x) {}
     
-    bool operator()(double x, double y) const {
+    bool is_inside(double x, double y) const {
       return x >= m_x;
     }
   };
@@ -505,7 +509,7 @@
   struct ylt : public bisecty {
     ylt(double y) : bisecty(y) {}
 
-    bool operator()(double x, double y) const {
+    bool is_inside(double x, double y) const {
       return y <= m_y;
     }
   };
@@ -513,7 +517,7 @@
   struct ygt : public bisecty {
     ygt(double y) : bisecty(y) {}
 
-    bool operator()(double x, double y) const {
+    bool is_inside(double x, double y) const {
       return y >= m_y;
     }
   };
@@ -528,29 +532,23 @@
   if (polygon.size() == 0)
     return;
 
-  sx = polygon.back().first;
-  sy = polygon.back().second;
+  sx = polygon.back().x;
+  sy = polygon.back().y;
   for (Polygon::const_iterator i = polygon.begin(); i != polygon.end(); ++i) {
-    px = i->first;
-    py = i->second;
+    px = i->x;
+    py = i->y;
     
-    sinside = filter(sx, sy);
-    pinside = filter(px, py);
+    sinside = filter.is_inside(sx, sy);
+    pinside = filter.is_inside(px, py);
     
-    if (sinside) {
-      if (pinside) {
-       result.push_back(std::make_pair(px, py));
-      } else {
-       filter.bisect(sx, sy, px, py, &bx, &by);
-       result.push_back(std::make_pair(bx, by));
-      }
-    } else {
-      if (pinside) {
-       filter.bisect(sx, sy, px, py, &bx, &by);
-       result.push_back(std::make_pair(bx, by));
-       result.push_back(std::make_pair(px, py));
-      }
+    if (sinside ^ pinside) {
+      filter.bisect(sx, sy, px, py, &bx, &by);
+      result.push_back(XY(bx, by));
     }
+
+    if (pinside) {
+      result.push_back(XY(px, py));
+    }
     
     sx = px; sy = py;
   }
@@ -582,11 +580,12 @@
   unsigned code = 0;
   path.rewind(0);
 
-  while (true) {
+  do {
+    // Grab the next subpath and store it in polygon1
     polygon1.clear();
-    while (true) {
+    do {
       if (code == agg::path_cmd_move_to)
-       polygon1.push_back(std::make_pair(x, y));
+       polygon1.push_back(XY(x, y));
 
       code = path.vertex(&x, &y);
 
@@ -594,15 +593,9 @@
        break;
 
       if (code != agg::path_cmd_move_to)
-       polygon1.push_back(std::make_pair(x, y));
+       polygon1.push_back(XY(x, y));
+    } while ((code & agg::path_cmd_end_poly) != agg::path_cmd_end_poly);
 
-      if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
-       break;
-      } else if (code == agg::path_cmd_move_to) {
-       break;
-      }
-    }
-
     // The result of each step is fed into the next (note the
     // swapping of polygon1 and polygon2 at each step).
     clip_to_rect_one_step(polygon1, polygon2, clip_to_rect_filters::xlt(xmax));
@@ -610,12 +603,10 @@
     clip_to_rect_one_step(polygon1, polygon2, clip_to_rect_filters::ylt(ymax));
     clip_to_rect_one_step(polygon2, polygon1, clip_to_rect_filters::ygt(ymin));
 
+    // Empty polygons aren't very useful, so skip them
     if (polygon1.size())
       results.push_back(polygon1);
-
-    if (code == agg::path_cmd_stop)
-      break;
-  }
+  } while (code != agg::path_cmd_stop);
 }
 
 Py::Object _path_module::clip_path_to_rect(const Py::Tuple &args) {
@@ -633,30 +624,118 @@
 
   ::clip_to_rect(path, x0, y0, x1, y1, inside, results);
 
-  // MGDTODO: Not exception safe
   int dims[2];
   dims[1] = 2;
   PyObject* py_results = PyList_New(results.size());
-  for (std::vector<Polygon>::const_iterator p = results.begin(); p != 
results.end(); ++p) {
-    size_t size = p->size();
-    dims[0] = p->size();
-    PyArrayObject* pyarray = (PyArrayObject*)PyArray_FromDims(2, dims, 
PyArray_DOUBLE);
-    for (size_t i = 0; i < size; ++i) {
-      ((double *)pyarray->data)[2*i] = (*p)[i].first;
-      ((double *)pyarray->data)[2*i+1] = (*p)[i].second;
+  if (!py_results)
+    throw Py::RuntimeError("Error creating results list");
+  try {
+    for (std::vector<Polygon>::const_iterator p = results.begin(); p != 
results.end(); ++p) {
+      size_t size = p->size();
+      dims[0] = p->size();
+      PyArrayObject* pyarray = (PyArrayObject*)PyArray_FromDims(2, dims, 
PyArray_DOUBLE);
+      for (size_t i = 0; i < size; ++i) {
+       ((double *)pyarray->data)[2*i]   = (*p)[i].x;
+       ((double *)pyarray->data)[2*i+1] = (*p)[i].y;
+      }
+      if (PyList_SetItem(py_results, p - results.begin(), (PyObject *)pyarray) 
!= -1) {
+       throw Py::RuntimeError("Error creating results list");
+      }
     }
-    // MGDTODO: Error check
-    PyList_SetItem(py_results, p - results.begin(), (PyObject *)pyarray);
+  } catch (...) {
+    Py_XDECREF(py_results);
+    throw;
   }
 
   return Py::Object(py_results, true);
 }
 
-struct XY {
-  double x;
-  double y;
-};
+Py::Object _path_module::affine_transform(const Py::Tuple& args) {
+  args.verify_length(2);
+  
+  Py::Object vertices_obj = args[0];
+  Py::Object transform_obj = args[1];
 
+  PyArrayObject* vertices = NULL;
+  PyArrayObject* transform = NULL;
+  PyArrayObject* result = NULL;
+
+  try {
+    vertices = (PyArrayObject*)PyArray_FromObject
+      (vertices_obj.ptr(), PyArray_DOUBLE, 1, 2);
+    if (!vertices || 
+       (PyArray_NDIM(vertices) == 2 && PyArray_DIM(vertices, 1) != 2) ||
+       (PyArray_NDIM(vertices) == 1 && PyArray_DIM(vertices, 0) != 2))
+      throw Py::ValueError("Invalid vertices array.");
+
+    transform = (PyArrayObject*) PyArray_FromObject
+      (transform_obj.ptr(), PyArray_DOUBLE, 2, 2);
+    if (!transform || PyArray_NDIM(transform) != 2 || PyArray_DIM(transform, 
0) != 3 || PyArray_DIM(transform, 1) != 3)
+      throw Py::ValueError("Invalid transform.");
+    
+    double a, b, c, d, e, f;
+    {
+      size_t stride0 = PyArray_STRIDE(transform, 0);
+      size_t stride1 = PyArray_STRIDE(transform, 1);
+      char* row0 = PyArray_BYTES(transform);
+      char* row1 = row0 + stride0;
+      
+      a = *(double*)(row0);
+      row0 += stride1;
+      c = *(double*)(row0);
+      row0 += stride1;
+      e = *(double*)(row0);
+      
+      b = *(double*)(row1);
+      row1 += stride1;
+      d = *(double*)(row1);
+      row1 += stride1;
+      f = *(double*)(row1);
+    }
+
+    result = (PyArrayObject*)PyArray_FromDims
+      (PyArray_NDIM(vertices), PyArray_DIMS(vertices), PyArray_DOUBLE);
+    if (PyArray_NDIM(vertices) == 2) {
+      size_t n = PyArray_DIM(vertices, 0);
+      char* vertex_in = PyArray_BYTES(vertices);
+      double* vertex_out = (double*)PyArray_DATA(result);
+      size_t stride0 = PyArray_STRIDE(vertices, 0);
+      size_t stride1 = PyArray_STRIDE(vertices, 1);
+      double x;
+      double y;
+      
+      for (size_t i = 0; i < n; ++i) {
+       x = *(double*)(vertex_in);
+       y = *(double*)(vertex_in + stride1);
+       
+       *vertex_out++ = a*x + c*y + e;
+       *vertex_out++ = b*x + d*y + f;
+       
+       vertex_in += stride0;
+      }
+    } else {
+      char* vertex_in = PyArray_BYTES(vertices);
+      double* vertex_out = (double*)PyArray_DATA(result);
+      size_t stride0 = PyArray_STRIDE(vertices, 0);
+      double x;
+      double y;
+      x = *(double*)(vertex_in);
+      y = *(double*)(vertex_in + stride0);
+      *vertex_out++ = a*x + c*y + e;
+      *vertex_out++ = b*x + d*y + f;
+    }
+  } catch (...) {
+    Py_XDECREF(vertices);
+    Py_XDECREF(transform);
+    Py_XDECREF(result);
+  }
+
+  Py_XDECREF(vertices);
+  Py_XDECREF(transform);
+
+  return Py::Object((PyObject*)result, true);
+}
+
 extern "C"
 DL_EXPORT(void)
   init_path(void)


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