From: <md...@us...> - 2007-11-27 20:03:50
|
Revision: 4473 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4473&view=rev Author: mdboom Date: 2007-11-27 12:03:48 -0800 (Tue, 27 Nov 2007) Log Message: ----------- Improve speed of quad mesh drawing (by about 25%) Modified Paths: -------------- branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-11-27 18:34:38 UTC (rev 4472) +++ branches/transforms/src/_backend_agg.cpp 2007-11-27 20:03:48 UTC (rev 4473) @@ -348,10 +348,13 @@ template<class Path> bool should_snap(Path& path, const agg::trans_affine& trans) { - // If this is a straight horizontal or vertical line, quantize to nearest + // If this contains only straight horizontal or vertical lines, quantize to nearest // pixels double x0, y0, x1, y1; unsigned code; + if (path.total_vertices() > 5) + return false; + code = path.vertex(&x0, &y0); trans.transform(&x0, &y0); @@ -742,38 +745,20 @@ return Py::Object(); } -template<class PathIteratorType> -void RendererAgg::_draw_path(PathIteratorType& path, agg::trans_affine trans, - bool has_clippath, const facepair_t& face, - 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; - typedef agg::conv_dash<curve_t> dash_t; +template<class path_t> +void RendererAgg::_draw_path(path_t& path, bool has_clippath, + const facepair_t& face, const GCAgg& gc) { + typedef agg::conv_stroke<path_t> stroke_t; + typedef agg::conv_dash<path_t> dash_t; typedef agg::conv_stroke<dash_t> stroke_dash_t; typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; typedef agg::renderer_scanline_aa_solid<amask_ren_type> amask_aa_renderer_type; typedef agg::renderer_scanline_bin_solid<amask_ren_type> amask_bin_renderer_type; - trans *= agg::trans_affine_scaling(1.0, -1.0); - trans *= agg::trans_affine_translation(0.0, (double)height); - - // Build the transform stack - 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 - // treating paths as having curved segments. Doing so greatly - // simplifies the code - curve_t curve(quantized); - // Render face if (face.first) { - theRasterizer->add_path(curve); + theRasterizer->add_path(path); if (gc.isaa) { if (has_clippath) { @@ -803,22 +788,21 @@ // Render stroke if (gc.linewidth != 0.0) { double linewidth = gc.linewidth; - if (snap) + if (!gc.isaa) linewidth = round(linewidth); - if (gc.dashes.size() == 0) { - stroke_t stroke(curve); + stroke_t stroke(path); stroke.width(linewidth); stroke.line_cap(gc.cap); stroke.line_join(gc.join); theRasterizer->add_path(stroke); } else { - dash_t dash(curve); + dash_t dash(path); for (GCAgg::dash_t::const_iterator i = gc.dashes.begin(); i != gc.dashes.end(); ++i) { double val0 = i->first; double val1 = i->second; - if (snap) { + if (!gc.isaa) { val0 = (int)val0 + 0.5; val1 = (int)val1 + 0.5; } @@ -831,7 +815,7 @@ theRasterizer->add_path(stroke); } - if (gc.isaa && !(snap)) { + if (gc.isaa) { if (has_clippath) { pixfmt_amask_type pfa(*pixFmt, *alphaMask); amask_ren_type r(pfa); @@ -859,6 +843,10 @@ Py::Object RendererAgg::draw_path(const Py::Tuple& args) { + typedef agg::conv_transform<PathIterator> transformed_path_t; + typedef conv_quantize<transformed_path_t> quantize_t; + typedef agg::conv_curve<quantize_t> curve_t; + _VERBOSE("RendererAgg::draw_path"); args.verify_length(3, 4); @@ -878,15 +866,24 @@ set_clipbox(gc.cliprect, theRasterizer); bool has_clippath = render_clippath(gc.clippath, gc.clippath_trans); - _draw_path(path, trans, has_clippath, face, gc, true); + trans *= agg::trans_affine_scaling(1.0, -1.0); + trans *= agg::trans_affine_translation(0.0, (double)height); + bool snap = should_snap(path, trans); + transformed_path_t tpath(path, trans); + quantize_t quantized(tpath, snap); + curve_t curve(quantized); + if (snap) + gc.isaa = false; + _draw_path(curve, has_clippath, face, gc); + return Py::Object(); } -template<class PathGenerator> +template<class PathGenerator, int check_snap, int has_curves> Py::Object RendererAgg::_draw_path_collection_generic - (const agg::trans_affine& master_transform, + (agg::trans_affine master_transform, const Py::Object& cliprect, const Py::Object& clippath, const agg::trans_affine& clippath_trans, @@ -898,8 +895,12 @@ 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) { + const Py::SeqBase<Py::Int>& antialiaseds) { + typedef agg::conv_transform<typename PathGenerator::path_iterator> transformed_path_t; + typedef conv_quantize<transformed_path_t> quantize_t; + typedef agg::conv_curve<quantize_t> quantized_curve_t; + typedef agg::conv_curve<transformed_path_t> curve_t; + GCAgg gc(dpi); PyArrayObject* offsets = NULL; @@ -944,6 +945,9 @@ size_t i = 0; // Convert all of the transforms up front + master_transform *= agg::trans_affine_scaling(1.0, -1.0); + master_transform *= agg::trans_affine_translation(0.0, (double)height); + typedef std::vector<agg::trans_affine> transforms_t; transforms_t transforms; transforms.reserve(Ntransforms); @@ -975,6 +979,7 @@ facepair_t face; face.first = Nfacecolors != 0; agg::trans_affine trans; + bool snap = false; for (i = 0; i < N; ++i) { typename PathGenerator::path_iterator path = path_generator(i); @@ -1016,9 +1021,32 @@ } } - gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); + if (check_snap) { + snap = should_snap(path, trans); + if (snap) + gc.isaa = false; + else + gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); - _draw_path(path, trans, has_clippath, face, gc, check_snap); + transformed_path_t tpath(path, trans); + quantize_t quantized(tpath, snap); + if (has_curves) { + quantized_curve_t curve(quantized); + _draw_path(curve, has_clippath, face, gc); + } else { + _draw_path(quantized, has_clippath, face, gc); + } + } else { + gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); + + transformed_path_t tpath(path, trans); + if (has_curves) { + curve_t curve(tpath); + _draw_path(curve, has_clippath, face, gc); + } else { + _draw_path(tpath, has_clippath, face, gc); + } + } } } catch (...) { Py_XDECREF(offsets); @@ -1075,7 +1103,7 @@ PathListGenerator path_generator(paths); - _draw_path_collection_generic + _draw_path_collection_generic<PathListGenerator, 1, 1> (master_transform, cliprect, clippath, @@ -1088,8 +1116,7 @@ edgecolors_obj, linewidths, linestyles_obj, - antialiaseds, - true); + antialiaseds); return Py::Object(); } @@ -1108,19 +1135,18 @@ 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]; + size_t m = (idx & 0x2) ? (m_m + 1) : m_m; + size_t n = (idx+1 & 0x2) ? (m_n + 1) : m_n; double* pair = (double*)PyArray_GETPTR2(m_coordinates, m, n); *x = *pair++; *y = *pair; - return (idx == 0) ? agg::path_cmd_move_to : agg::path_cmd_line_to; + return (idx) ? agg::path_cmd_line_to : agg::path_cmd_move_to; } inline unsigned vertex(double* x, double* y) { - if (m_iterator >= total_vertices()) return agg::path_cmd_stop; + if (m_iterator >= total_vertices()) + return agg::path_cmd_stop; return vertex(m_iterator++, x, y); } @@ -1159,13 +1185,6 @@ } }; -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"); @@ -1208,7 +1227,7 @@ } } - _draw_path_collection_generic + _draw_path_collection_generic<QuadMeshGenerator, 0, 0> (master_transform, cliprect, clippath, @@ -1221,8 +1240,7 @@ edgecolors_obj, linewidths, linestyles_obj, - antialiaseds, - false); + antialiaseds); return Py::Object(); } Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-11-27 18:34:38 UTC (rev 4472) +++ branches/transforms/src/_backend_agg.h 2007-11-27 20:03:48 UTC (rev 4473) @@ -226,16 +226,16 @@ void set_clipbox(const Py::Object& cliprect, R rasterizer); bool render_clippath(const Py::Object& clippath, const agg::trans_affine& clippath_trans); 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> + void _draw_path(PathIteratorType& path, bool has_clippath, + const facepair_t& face, const GCAgg& gc); + template<class PathGenerator, int check_snap, int has_curves> Py::Object _draw_path_collection_generic - (const agg::trans_affine& master_transform, + (agg::trans_affine master_transform, const Py::Object& cliprect, const Py::Object& clippath, const agg::trans_affine& clippath_trans, - const PathGenerator& path_finder, + const PathGenerator& path_generator, const Py::SeqBase<Py::Object>& transforms_obj, const Py::Object& offsets_obj, const agg::trans_affine& offset_trans, @@ -243,8 +243,7 @@ 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); + const Py::SeqBase<Py::Int>& antialiaseds); private: Py::Object lastclippath; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |