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