From: <md...@us...> - 2007-11-07 20:13:38
|
Revision: 4152 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4152&view=rev Author: mdboom Date: 2007-11-07 12:13:35 -0800 (Wed, 07 Nov 2007) Log Message: ----------- Further speed improvements. Quadmesh extension code (still not as fast as the old version, for various reasons.) Fix bugs in quadmesh masking in PDF and PS backends. Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/lines.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h branches/transforms/src/agg_py_path_iterator.h Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/axes.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -4788,7 +4788,8 @@ vmax = kwargs.pop('vmax', None) shading = kwargs.pop('shading', 'flat') edgecolors = kwargs.pop('edgecolors', 'None') - + antialiased = kwargs.pop('antialiased', False) + X, Y, C = self._pcolorargs('pcolormesh', *args) Ny, Nx = X.shape @@ -4807,7 +4808,7 @@ showedges = 0 collection = mcoll.QuadMesh( - Nx - 1, Ny - 1, coords, showedges) # kwargs are not used + Nx - 1, Ny - 1, coords, showedges, antialiased=antialiased) # kwargs are not used collection.set_alpha(alpha) collection.set_array(C) if norm is not None: assert(isinstance(norm, mcolors.Normalize)) Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -9,6 +9,7 @@ import numpy as npy import matplotlib.cbook as cbook import matplotlib.colors as colors +import matplotlib.path as path import matplotlib.transforms as transforms import matplotlib.widgets as widgets from matplotlib import rcParams @@ -75,7 +76,31 @@ path, transform = path_id transform = transforms.Affine2D(transform.get_matrix()).translate(xo, yo) self.draw_path(gc, path, transform, rgbFace) + + def draw_quad_mesh(self, master_transform, cliprect, clippath, + clippath_trans, meshWidth, meshHeight, coordinates, + offsets, offsetTrans, facecolors, antialiased, + showedges): + """ + This provides a fallback implementation of draw_quad_mesh that + generates paths and then calls draw_path_collection. + """ + from matplotlib.collections import QuadMesh + paths = QuadMesh.convert_mesh_to_paths( + meshWidth, meshHeight, coordinates) + + if showedges: + edgecolors = npy.array([[0.0, 0.0, 0.0, 1.0]], npy.float_) + linewidths = npy.array([1.0], npy.float_) + else: + edgecolors = linewidths = npy.array([], npy.float_) + linewidths = npy.array([0.0], npy.float_) + return self.draw_path_collection( + master_transform, cliprect, clippath, clippath_trans, + paths, [], offsets, offsetTrans, facecolors, edgecolors, + linewidths, [], [antialiased]) + def _iter_collection_raw_paths(self, master_transform, paths, all_transforms): """ This is a helper method (along with _iter_collection) to make @@ -158,6 +183,9 @@ if Nfacecolors == 0: rgbFace = None + if Nedgecolors == 0: + gc.set_linewidth(0.0) + xo, yo = 0, 0 for i in xrange(N): path_id = path_ids[i % Npaths] Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -66,6 +66,7 @@ self.draw_path = self._renderer.draw_path self.draw_markers = self._renderer.draw_markers self.draw_path_collection = self._renderer.draw_path_collection + self.draw_quad_mesh = self._renderer.draw_quad_mesh self.draw_image = self._renderer.draw_image self.copy_from_bbox = self._renderer.copy_from_bbox self.restore_region = self._renderer.restore_region Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -993,7 +993,7 @@ rgba = npy.fromstring(s, npy.uint8) rgba.shape = (h, w, 4) - rgb = rgba[:,:,:3] + rgb = rgba[:,:,:4] return h, w, rgb.tostring() def _gray(self, im, rc=0.3, gc=0.59, bc=0.11): @@ -1601,10 +1601,12 @@ return `d` def _strokep(self): - return self._linewidth > 0 and self._alpha > 0 + return (self._linewidth > 0 and self._alpha > 0 and + (len(self._rgb) <= 3 or self._rgb[3] != 0.0)) def _fillp(self): - return self._fillcolor is not None or self._hatch + return ((self._fillcolor is not None or self._hatch) and + (len(self._fillcolor) <= 3 or self._fillcolor[3] != 0.0)) def close_and_paint(self): if self._strokep(): Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -745,14 +745,20 @@ if debugPS and command: write("% "+command+"\n") - self.set_linewidth(gc.get_linewidth()) - jint = gc.get_joinstyle() - self.set_linejoin(jint) - cint = gc.get_capstyle() - self.set_linecap(cint) - self.set_linedash(*gc.get_dashes()) - if self.linewidth > 0 and stroke: - self.set_color(*gc.get_rgb()[:3]) + stroke = (stroke and gc.get_linewidth() > 0.0 and + (len(gc.get_rgb()) <= 3 or gc.get_rgb()[3] != 0.0)) + fill = (fill and rgbFace is not None and + (len(rgbFace) <= 3 or rgbFace[3] != 0.0)) + + if stroke: + self.set_linewidth(gc.get_linewidth()) + jint = gc.get_joinstyle() + self.set_linejoin(jint) + cint = gc.get_capstyle() + self.set_linecap(cint) + self.set_linedash(*gc.get_dashes()) + if self.linewidth > 0 and stroke: + self.set_color(*gc.get_rgb()[:3]) cliprect = gc.get_clip_rectangle() if cliprect: @@ -767,7 +773,7 @@ write(ps.strip()) write("\n") - if rgbFace is not None and fill: + if fill: #print 'rgbface', rgbFace write("gsave\n") self.set_color(store=0, *rgbFace[:3]) Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/collections.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -376,53 +376,89 @@ at mesh coordinates (0, 0), then the one at (0, 1), then at (0, 2) .. (0, meshWidth), (1, 0), (1, 1), and so on. """ - def __init__(self, meshWidth, meshHeight, coordinates, showedges): - Path = mpath.Path - + def __init__(self, meshWidth, meshHeight, coordinates, showedges, antialiased=True): Collection.__init__(self) self._meshWidth = meshWidth self._meshHeight = meshHeight self._coordinates = coordinates self._showedges = showedges + self._antialiased = antialiased + self._paths = None + + self._bbox = transforms.Bbox.unit() + self._bbox.update_from_data_xy(coordinates.reshape( + ((meshWidth + 1) * (meshHeight + 1), 2))) + + def get_paths(self, dataTrans=None): + import pdb + pdb.set_trace() + if self._paths is None: + self._paths = self.convert_mesh_to_paths( + self._meshWidth, self._meshHeight, self._coordinates) + return self._paths + + #@staticmethod + def convert_mesh_to_paths(meshWidth, meshHeight, coordinates): + Path = mpath.Path + c = coordinates.reshape((meshHeight + 1, meshWidth + 1, 2)) # We could let the Path constructor generate the codes for us, # but this is faster, since we know they'll always be the same codes = npy.array( [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY], Path.code_type) - + points = npy.concatenate(( - c[0:-1, 0:-1], - c[0:-1, 1: ], - c[1: , 1: ], - c[1: , 0:-1], - c[0:-1, 0:-1] - ), axis=2) + c[0:-1, 0:-1], + c[0:-1, 1: ], + c[1: , 1: ], + c[1: , 0:-1], + c[0:-1, 0:-1] + ), axis=2) points = points.reshape((meshWidth * meshHeight, 5, 2)) - self._paths = [Path(x, codes) for x in points] - - self._bbox = transforms.Bbox.unit() - self._bbox.update_from_data_xy(c.reshape( - ((meshWidth + 1) * (meshHeight + 1), 2))) - - def get_paths(self, dataTrans=None): - return self._paths - + return [Path(x, codes) for x in points] + convert_mesh_to_paths = staticmethod(convert_mesh_to_paths) + def get_datalim(self, transData): return self._bbox def draw(self, renderer): - self.update_scalarmappable() + if not self.get_visible(): return + renderer.open_group(self.__class__.__name__) + transform = self.get_transform() + transOffset = self._transOffset + offsets = self._offsets - self._linewidths = (1,) - if self._showedges: - self._edgecolors = npy.array([[0.0, 0.0, 0.0, 1.0]], npy.float_) + if self.have_units(): + if len(self._offsets): + xs = self.convert_xunits(self._offsets[:0]) + ys = self.convert_yunits(self._offsets[:1]) + offsets = zip(xs, ys) + + if len(offsets) == 0: + offsets = npy.array([], npy.float_) else: - self._edgecolors = self._facecolors + offsets = npy.asarray(offsets, npy.float_) - Collection.draw(self, renderer) + self.update_scalarmappable() + clippath, clippath_trans = self.get_transformed_clip_path_and_affine() + if clippath_trans is not None: + clippath_trans = clippath_trans.frozen() + + assert transform.is_affine + if not transOffset.is_affine: + offsets = transOffset.transform_non_affine(offsets) + transOffset = transOffset.get_affine() + + renderer.draw_quad_mesh( + transform.frozen(), self.clipbox, clippath, clippath_trans, + self._meshWidth, self._meshHeight, self._coordinates, + offsets, transOffset, self._facecolors, self._antialiased, + self._showedges) + renderer.close_group(self.__class__.__name__) + class PolyCollection(Collection): def __init__(self, verts, **kwargs): """ Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/lib/matplotlib/lines.py 2007-11-07 20:13:35 UTC (rev 4152) @@ -388,8 +388,10 @@ not_masked += 1 if (not_masked < 2 or - ((x.shape != self._xorig.shape or npy.any(x != self._xorig)) or - (y.shape != self._yorig.shape or npy.any(y != self._yorig)))): + (x is not self._xorig and + (x.shape != self._xorig.shape or npy.any(x != self._xorig))) or + (y is not self._yorig and + (y.shape != self._yorig.shape or npy.any(y != self._yorig)))): self._xorig = x self._yorig = y self.recache() Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/src/_backend_agg.cpp 2007-11-07 20:13:35 UTC (rev 4152) @@ -302,7 +302,7 @@ template<class R> void -RendererAgg::set_clipbox(Py::Object& cliprect, R rasterizer) { +RendererAgg::set_clipbox(const Py::Object& cliprect, R rasterizer) { //set the clip rectangle from the gc _VERBOSE("RendererAgg::set_clipbox"); @@ -775,10 +775,11 @@ return Py::Object(); } -void RendererAgg::_draw_path(PathIterator& path, agg::trans_affine trans, +template<class PathIteratorType> +void RendererAgg::_draw_path(PathIteratorType& path, agg::trans_affine trans, bool has_clippath, const facepair_t& face, - const GCAgg& gc) { - typedef agg::conv_transform<PathIterator> transformed_path_t; + const GCAgg& gc, bool check_snap) { + typedef agg::conv_transform<PathIteratorType> transformed_path_t; typedef conv_quantize<transformed_path_t> quantize_t; typedef agg::conv_curve<quantize_t> curve_t; typedef agg::conv_stroke<curve_t> stroke_t; @@ -793,7 +794,9 @@ trans *= agg::trans_affine_translation(0.0, (double)height); // Build the transform stack - bool snap = should_snap(path, trans); + bool snap = false; + if (check_snap) + snap = should_snap(path, trans); transformed_path_t tpath(path, trans); quantize_t quantized(tpath, snap); // Benchmarking shows that there is no noticable slowdown to always @@ -908,31 +911,28 @@ set_clipbox(gc.cliprect, theRasterizer); bool has_clippath = render_clippath(gc.clippath, gc.clippath_trans); - _draw_path(path, trans, has_clippath, face, gc); + _draw_path(path, trans, has_clippath, face, gc, true); return Py::Object(); } +template<class PathGenerator> Py::Object -RendererAgg::draw_path_collection(const Py::Tuple& args) { - _VERBOSE("RendererAgg::draw_path_collection"); - args.verify_length(13); - - //segments, trans, clipbox, colors, linewidths, antialiaseds - agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); - Py::Object cliprect = args[1]; - Py::Object clippath = args[2]; - agg::trans_affine clippath_trans = py_to_agg_transformation_matrix(args[3], false); - Py::SeqBase<Py::Object> paths = args[4]; - Py::SeqBase<Py::Object> transforms_obj = args[5]; - Py::Object offsets_obj = args[6]; - agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7]); - Py::Object facecolors_obj = args[8]; - Py::Object edgecolors_obj = args[9]; - Py::SeqBase<Py::Float> linewidths = args[10]; - Py::SeqBase<Py::Object> linestyles_obj = args[11]; - Py::SeqBase<Py::Int> antialiaseds = args[12]; - +RendererAgg::_draw_path_collection_generic + (const agg::trans_affine& master_transform, + const Py::Object& cliprect, + const Py::Object& clippath, + const agg::trans_affine& clippath_trans, + const PathGenerator& path_generator, + const Py::SeqBase<Py::Object>& transforms_obj, + const Py::Object& offsets_obj, + const agg::trans_affine& offset_trans, + const Py::Object& facecolors_obj, + const Py::Object& edgecolors_obj, + const Py::SeqBase<Py::Float>& linewidths, + const Py::SeqBase<Py::Object>& linestyles_obj, + const Py::SeqBase<Py::Int>& antialiaseds, + bool check_snap) { GCAgg gc(dpi); PyArrayObject* offsets = NULL; @@ -961,7 +961,7 @@ (edgecolors->nd == 2 && edgecolors->dimensions[1] != 4)) throw Py::ValueError("Edgecolors must be a Nx4 numpy array"); - size_t Npaths = paths.length(); + size_t Npaths = path_generator.num_paths(); size_t Noffsets = offsets->dimensions[0]; size_t N = std::max(Npaths, Noffsets); size_t Ntransforms = std::min(transforms_obj.length(), N); @@ -1010,7 +1010,7 @@ agg::trans_affine trans; for (i = 0; i < N; ++i) { - PathIterator path(paths[i % Npaths]); + typename PathGenerator::path_iterator path = path_generator(i); if (Ntransforms) { trans = transforms[i % Ntransforms]; } else { @@ -1038,14 +1038,20 @@ *(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; + if (Nlinewidths) { + gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; + } else { + gc.linewidth = 1.0; + } + if (Nlinestyles) { + gc.dashes = dashes[i % Nlinestyles].second; + gc.dashOffset = dashes[i % Nlinestyles].first; + } } gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); - _draw_path(path, trans, has_clippath, face, gc); + _draw_path(path, trans, has_clippath, face, gc, check_snap); } } catch (...) { Py_XDECREF(offsets); @@ -1059,12 +1065,213 @@ } +class PathListGenerator { + const Py::SeqBase<Py::Object>& m_paths; + +public: + typedef PathIterator path_iterator; + + inline PathListGenerator(const Py::SeqBase<Py::Object>& paths) : + m_paths(paths) { + + } + + inline size_t num_paths() const { + return m_paths.size(); + } + + inline path_iterator operator()(size_t i) const { + return PathIterator(m_paths[i]); + } +}; + Py::Object +RendererAgg::draw_path_collection(const Py::Tuple& args) { + _VERBOSE("RendererAgg::draw_path_collection"); + args.verify_length(13); + + //segments, trans, clipbox, colors, linewidths, antialiaseds + agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); + Py::Object cliprect = args[1]; + Py::Object clippath = args[2]; + agg::trans_affine clippath_trans = py_to_agg_transformation_matrix(args[3], false); + Py::SeqBase<Py::Object> paths = args[4]; + Py::SeqBase<Py::Object> transforms_obj = args[5]; + Py::Object offsets_obj = args[6]; + agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7]); + Py::Object facecolors_obj = args[8]; + Py::Object edgecolors_obj = args[9]; + Py::SeqBase<Py::Float> linewidths = args[10]; + Py::SeqBase<Py::Object> linestyles_obj = args[11]; + Py::SeqBase<Py::Int> antialiaseds = args[12]; + + PathListGenerator path_generator(paths); + + _draw_path_collection_generic + (master_transform, + cliprect, + clippath, + clippath_trans, + path_generator, + transforms_obj, + offsets_obj, + offset_trans, + facecolors_obj, + edgecolors_obj, + linewidths, + linestyles_obj, + antialiaseds, + true); + + return Py::Object(); +} + +class QuadMeshGenerator { + size_t m_meshWidth; + size_t m_meshHeight; + PyArrayObject* m_coordinates; + + class QuadMeshPathIterator { + size_t m_iterator; + size_t m_m, m_n; + PyArrayObject* m_coordinates; + public: + QuadMeshPathIterator(size_t m, size_t n, PyArrayObject* coordinates) : + m_iterator(0), m_m(m), m_n(n), m_coordinates(coordinates) { + } + + static const size_t offsets[5][2]; + + inline unsigned vertex(unsigned idx, double* x, double* y) { + size_t m = m_m + offsets[idx][0]; + size_t n = m_n + offsets[idx][1]; + *x = *(double*)PyArray_GETPTR3(m_coordinates, m, n, 0); + *y = *(double*)PyArray_GETPTR3(m_coordinates, m, n, 1); + return (idx == 0) ? agg::path_cmd_move_to : agg::path_cmd_line_to; + } + + inline unsigned vertex(double* x, double* y) { + if (m_iterator >= total_vertices()) return agg::path_cmd_stop; + return vertex(m_iterator++, x, y); + } + + inline void rewind(unsigned path_id) { + m_iterator = path_id; + } + + inline unsigned total_vertices() { + return 5; + } + + inline bool has_curves() { + return false; + } + }; + +public: + typedef QuadMeshPathIterator path_iterator; + + inline QuadMeshGenerator(size_t meshWidth, size_t meshHeight, const Py::Object& coordinates) : + m_meshWidth(meshWidth), m_meshHeight(meshHeight), m_coordinates(NULL) { + PyArrayObject* coordinates_array = (PyArrayObject*)PyArray_FromObject(coordinates.ptr(), PyArray_DOUBLE, 1, 3); + if (!coordinates_array) { + throw Py::ValueError("Invalid coordinates array."); + } + + Py::Tuple shape(3); + shape[0] = Py::Int((int)meshHeight + 1); + shape[1] = Py::Int((int)meshWidth + 1); + shape[2] = Py::Int(2); + m_coordinates = (PyArrayObject*)PyArray_Reshape(coordinates_array, shape.ptr()); + } + + inline ~QuadMeshGenerator() { + Py_XDECREF(m_coordinates); + } + + inline size_t num_paths() const { + return m_meshWidth * m_meshHeight; + } + + inline path_iterator operator()(size_t i) const { + return QuadMeshPathIterator(i % m_meshHeight, i / m_meshHeight, m_coordinates); + } +}; + +const size_t QuadMeshGenerator::QuadMeshPathIterator::offsets[5][2] = { + { 0, 0 }, + { 0, 1 }, + { 1, 1 }, + { 1, 0 }, + { 0, 0 } }; + +Py::Object +RendererAgg::draw_quad_mesh(const Py::Tuple& args) { + _VERBOSE("RendererAgg::draw_quad_mesh"); + args.verify_length(12); + + //segments, trans, clipbox, colors, linewidths, antialiaseds + agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); + Py::Object cliprect = args[1]; + Py::Object clippath = args[2]; + agg::trans_affine clippath_trans = py_to_agg_transformation_matrix(args[3], false); + size_t mesh_width = Py::Int(args[4]); + size_t mesh_height = Py::Int(args[5]); + Py::Object coordinates = args[6]; + Py::Object offsets_obj = args[7]; + agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[8]); + Py::Object facecolors_obj = args[9]; + bool antialiased = (bool)Py::Int(args[10]); + bool showedges = (bool)Py::Int(args[11]); + + QuadMeshGenerator path_generator(mesh_width, mesh_height, coordinates); + + Py::SeqBase<Py::Object> transforms_obj; + Py::Object edgecolors_obj; + Py::Tuple linewidths(1); + linewidths[0] = Py::Float(1.0); + Py::SeqBase<Py::Object> linestyles_obj; + Py::Tuple antialiaseds(1); + antialiaseds[0] = Py::Int(antialiased ? 1 : 0); + + if (showedges) { + int dims[] = { 1, 4, 0 }; + double data[] = { 0, 0, 0, 1 }; + edgecolors_obj = PyArray_FromDimsAndData(2, dims, PyArray_DOUBLE, (char*)data); + } else { + if (antialiased) { + edgecolors_obj = facecolors_obj; + } else { + int dims[] = { 0, 0 }; + edgecolors_obj = PyArray_FromDims(1, dims, PyArray_DOUBLE); + } + } + + _draw_path_collection_generic + (master_transform, + cliprect, + clippath, + clippath_trans, + path_generator, + transforms_obj, + offsets_obj, + offset_trans, + facecolors_obj, + edgecolors_obj, + linewidths, + linestyles_obj, + antialiaseds, + false); + + return Py::Object(); +} + +Py::Object RendererAgg::write_rgba(const Py::Tuple& args) { _VERBOSE("RendererAgg::write_rgba"); args.verify_length(1); - std::string fname = Py::String( args[0]); + std::string fname = Py::String(args[0]); std::ofstream of2( fname.c_str(), std::ios::binary|std::ios::out); for (size_t i=0; i<NUMBYTES; i++) { @@ -1073,7 +1280,6 @@ return Py::Object(); } - // this code is heavily adapted from the paint license, which is in // the file paint.license (BSD compatible) included in this // distribution. TODO, add license file to MANIFEST.in and CVS @@ -1398,6 +1604,8 @@ "draw_path(gc, path, transform, rgbFace)\n"); add_varargs_method("draw_path_collection", &RendererAgg::draw_path_collection, "draw_path_collection(master_transform, cliprect, clippath, clippath_trans, paths, transforms, offsets, offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds)\n"); + add_varargs_method("draw_quad_mesh", &RendererAgg::draw_quad_mesh, + "draw_quad_mesh(master_transform, cliprect, clippath, clippath_trans, meshWidth, meshHeight, coordinates, offsets, offsetTrans, facecolors, antialiaseds, showedges)\n"); add_varargs_method("draw_markers", &RendererAgg::draw_markers, "draw_markers(gc, marker_path, marker_trans, path, rgbFace)\n"); add_varargs_method("draw_text_image", &RendererAgg::draw_text_image, Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/src/_backend_agg.h 2007-11-07 20:13:35 UTC (rev 4152) @@ -165,7 +165,9 @@ Py::Object draw_image(const Py::Tuple & args); Py::Object draw_path(const Py::Tuple & args); Py::Object draw_path_collection(const Py::Tuple & args); + Py::Object RendererAgg::draw_quad_mesh(const Py::Tuple& args); + Py::Object write_rgba(const Py::Tuple & args); Py::Object write_png(const Py::Tuple & args); Py::Object tostring_rgb(const Py::Tuple & args); @@ -215,10 +217,28 @@ facepair_t _get_rgba_face(const Py::Object& rgbFace, double alpha); bool bbox_to_rect(const Py::Object& bbox, double* l, double* b, double* r, double* t); template<class R> - void set_clipbox(Py::Object& cliprect, R rasterizer); + void set_clipbox(const Py::Object& cliprect, R rasterizer); bool render_clippath(const Py::Object& clippath, const agg::trans_affine& clippath_trans); - void _draw_path(PathIterator& path, agg::trans_affine trans, - bool has_clippath, const facepair_t& face, const GCAgg& gc); + template<class PathIteratorType> + void _draw_path(PathIteratorType& path, agg::trans_affine trans, + bool has_clippath, const facepair_t& face, const GCAgg& gc, bool check_snap); + template<class PathGenerator> + Py::Object + _draw_path_collection_generic + (const agg::trans_affine& master_transform, + const Py::Object& cliprect, + const Py::Object& clippath, + const agg::trans_affine& clippath_trans, + const PathGenerator& path_finder, + const Py::SeqBase<Py::Object>& transforms_obj, + const Py::Object& offsets_obj, + const agg::trans_affine& offset_trans, + const Py::Object& facecolors_obj, + const Py::Object& edgecolors_obj, + const Py::SeqBase<Py::Float>& linewidths, + const Py::SeqBase<Py::Object>& linestyles_obj, + const Py::SeqBase<Py::Int>& antialiaseds, + bool check_snap); private: Py::Object lastclippath; Modified: branches/transforms/src/agg_py_path_iterator.h =================================================================== --- branches/transforms/src/agg_py_path_iterator.h 2007-11-07 18:34:30 UTC (rev 4151) +++ branches/transforms/src/agg_py_path_iterator.h 2007-11-07 20:13:35 UTC (rev 4152) @@ -7,35 +7,35 @@ #include "agg_path_storage.h" class PathIterator { - PyArrayObject* vertices; - PyArrayObject* codes; + PyArrayObject* m_vertices; + PyArrayObject* m_codes; size_t m_iterator; size_t m_total_vertices; public: PathIterator(const Py::Object& path_obj) : - vertices(NULL), codes(NULL), m_iterator(0) { + m_vertices(NULL), m_codes(NULL), m_iterator(0) { Py::Object vertices_obj = path_obj.getAttr("vertices"); Py::Object codes_obj = path_obj.getAttr("codes"); - vertices = (PyArrayObject*)PyArray_FromObject + m_vertices = (PyArrayObject*)PyArray_FromObject (vertices_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2) + if (!m_vertices || m_vertices->nd != 2 || m_vertices->dimensions[1] != 2) throw Py::ValueError("Invalid vertices array."); if (codes_obj.ptr() != Py_None) { - codes = (PyArrayObject*)PyArray_FromObject + m_codes = (PyArrayObject*)PyArray_FromObject (codes_obj.ptr(), PyArray_UINT8, 1, 1); - if (!codes) + if (!m_codes) throw Py::ValueError("Invalid codes array."); } - m_total_vertices = vertices->dimensions[0]; + m_total_vertices = m_vertices->dimensions[0]; } ~PathIterator() { - Py_XDECREF(vertices); - Py_XDECREF(codes); + Py_XDECREF(m_vertices); + Py_XDECREF(m_codes); } static const char code_map[]; @@ -43,10 +43,10 @@ inline unsigned vertex(unsigned idx, double* x, double* y) { if (idx > m_total_vertices) throw Py::RuntimeError("Requested vertex past end"); - *x = *(double*)PyArray_GETPTR2(vertices, idx, 0); - *y = *(double*)PyArray_GETPTR2(vertices, idx, 1); - if (codes) { - return code_map[(int)*(char *)PyArray_GETPTR1(codes, idx)]; + *x = *(double*)PyArray_GETPTR2(m_vertices, idx, 0); + *y = *(double*)PyArray_GETPTR2(m_vertices, idx, 1); + if (m_codes) { + return code_map[(int)*(char *)PyArray_GETPTR1(m_codes, idx)]; } else { return idx == 0 ? agg::path_cmd_move_to : agg::path_cmd_line_to; } @@ -64,6 +64,10 @@ inline unsigned total_vertices() { return m_total_vertices; } + + inline bool has_curves() { + return m_codes; + } }; // Maps path codes on the Python side to agg path commands This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |