From: <md...@us...> - 2010-06-11 14:30:38
|
Revision: 8414 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8414&view=rev Author: mdboom Date: 2010-06-11 14:30:32 +0000 (Fri, 11 Jun 2010) Log Message: ----------- Take stroke width into account when quantizing rectilinear paths. Discovered by Jason Grout in the mailing list thread "Plots shifted up or to the left a pixel or so" Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/artist.py trunk/matplotlib/lib/matplotlib/path.py trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_dates/date_axhline.png trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_dates/date_axvline.png trunk/matplotlib/src/_backend_agg.cpp trunk/matplotlib/src/_macosx.m trunk/matplotlib/src/_path.cpp trunk/matplotlib/src/path_cleanup.cpp trunk/matplotlib/src/path_converters.h Modified: trunk/matplotlib/lib/matplotlib/artist.py =================================================================== --- trunk/matplotlib/lib/matplotlib/artist.py 2010-06-11 08:34:24 UTC (rev 8413) +++ trunk/matplotlib/lib/matplotlib/artist.py 2010-06-11 14:30:32 UTC (rev 8414) @@ -412,7 +412,7 @@ * None: (auto) If the path contains only rectilinear line segments, round to the nearest pixel center - Only supported by the Agg backends. + Only supported by the Agg and MacOSX backends. """ return self._snap @@ -427,7 +427,7 @@ * None: (auto) If the path contains only rectilinear line segments, round to the nearest pixel center - Only supported by the Agg backends. + Only supported by the Agg and MacOSX backends. """ self._snap = snap Modified: trunk/matplotlib/lib/matplotlib/path.py =================================================================== --- trunk/matplotlib/lib/matplotlib/path.py 2010-06-11 08:34:24 UTC (rev 8413) +++ trunk/matplotlib/lib/matplotlib/path.py 2010-06-11 14:30:32 UTC (rev 8414) @@ -188,7 +188,8 @@ return len(self.vertices) def iter_segments(self, transform=None, remove_nans=True, clip=None, - quantize=False, simplify=None, curves=True): + quantize=False, stroke_width=1.0, simplify=None, + curves=True): """ Iterates over all of the curve segments in the path. Each iteration returns a 2-tuple (*vertices*, *code*), where @@ -210,6 +211,9 @@ *quantize*: if None, auto-quantize. If True, force quantize, and if False, don't quantize. + *stroke_width*: the width of the stroke being drawn. Needed + as a hint for the quantizer. + *simplify*: if True, perform simplification, to remove vertices that do not affect the appearance of the path. If False, perform no simplification. If None, use the @@ -232,7 +236,7 @@ STOP = self.STOP vertices, codes = cleanup_path(self, transform, remove_nans, clip, - quantize, simplify, curves) + quantize, stroke_width, simplify, curves) len_vertices = len(vertices) i = 0 Modified: trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_dates/date_axhline.png =================================================================== (Binary files differ) Modified: trunk/matplotlib/lib/matplotlib/tests/baseline_images/test_dates/date_axvline.png =================================================================== (Binary files differ) Modified: trunk/matplotlib/src/_backend_agg.cpp =================================================================== --- trunk/matplotlib/src/_backend_agg.cpp 2010-06-11 08:34:24 UTC (rev 8413) +++ trunk/matplotlib/src/_backend_agg.cpp 2010-06-11 14:30:32 UTC (rev 8414) @@ -535,14 +535,16 @@ transformed_path_t marker_path_transformed(marker_path, marker_trans); quantize_t marker_path_quantized(marker_path_transformed, gc.quantize_mode, - marker_path.total_vertices()); + marker_path.total_vertices(), + gc.linewidth); curve_t marker_path_curve(marker_path_quantized); PathIterator path(path_obj); transformed_path_t path_transformed(path, trans); quantize_t path_quantized(path_transformed, gc.quantize_mode, - path.total_vertices()); + path.total_vertices(), + 1.0); curve_t path_curve(path_quantized); path_curve.rewind(0); @@ -1106,7 +1108,7 @@ transformed_path_t tpath(path, trans); nan_removed_t nan_removed(tpath, true, path.has_curves()); clipped_t clipped(nan_removed, clip, width, height); - quantized_t quantized(clipped, gc.quantize_mode, path.total_vertices()); + quantized_t quantized(clipped, gc.quantize_mode, path.total_vertices(), gc.linewidth); simplify_t simplified(quantized, simplify, path.simplify_threshold()); curve_t curve(simplified); @@ -1273,7 +1275,8 @@ transformed_path_t tpath(path, trans); nan_removed_t nan_removed(tpath, true, has_curves); clipped_t clipped(nan_removed, do_clip, width, height); - quantized_t quantized(clipped, gc.quantize_mode, path.total_vertices()); + quantized_t quantized(clipped, gc.quantize_mode, + path.total_vertices(), gc.linewidth); if (has_curves) { quantized_curve_t curve(quantized); _draw_path(curve, has_clippath, face, gc); Modified: trunk/matplotlib/src/_macosx.m =================================================================== --- trunk/matplotlib/src/_macosx.m 2010-06-11 08:34:24 UTC (rev 8413) +++ trunk/matplotlib/src/_macosx.m 2010-06-11 14:30:32 UTC (rev 8414) @@ -289,6 +289,7 @@ 0, rect, QUANTIZE_FALSE, + 1.0, 0); Py_DECREF(transform); if (!iterator) @@ -662,6 +663,7 @@ 0, rect, QUANTIZE_AUTO, + 1.0, 0); Py_DECREF(transform); if (!iterator) @@ -889,6 +891,7 @@ 0, rect, QUANTIZE_AUTO, + CGContextGetLineWidth(self), rgbFace == NULL); if (!iterator) { @@ -966,6 +969,7 @@ 0, rect, QUANTIZE_AUTO, + CGContextGetLineWidth(self), 0); if (!iterator) { @@ -1042,6 +1046,7 @@ 0, rect, mode, + CGContextGetLineWidth(self), 0); if (!iterator) { @@ -1063,6 +1068,7 @@ 1, rect, QUANTIZE_TRUE, + 1.0, 0); if (!iterator) { @@ -1326,6 +1332,17 @@ 0, rect, mode, + 1.0, + /* Hardcoding stroke width to 1.0 + here, but for true + correctness, the paths would + need to be set up for each + different linewidth that may + be applied below. This + difference is very minute in + practice, so this hardcoding + is probably ok for now. -- + MGD */ 0); Py_DECREF(transform); Py_DECREF(path); @@ -1362,6 +1379,7 @@ 0, rect, QUANTIZE_AUTO, + 1.0, 0); if (!iterator) { @@ -1669,6 +1687,7 @@ 0, rect, QUANTIZE_AUTO, + 1.0, 0); if (iterator) { @@ -2654,6 +2673,7 @@ 0, rect, QUANTIZE_AUTO, + 1.0, 0); if (iterator) { Modified: trunk/matplotlib/src/_path.cpp =================================================================== --- trunk/matplotlib/src/_path.cpp 2010-06-11 08:34:24 UTC (rev 8413) +++ trunk/matplotlib/src/_path.cpp 2010-06-11 14:30:32 UTC (rev 8414) @@ -1228,8 +1228,9 @@ void _cleanup_path(PathIterator& path, const agg::trans_affine& trans, bool remove_nans, bool do_clip, const agg::rect_base<double>& rect, - e_quantize_mode quantize_mode, bool do_simplify, - bool return_curves, std::vector<double>& vertices, + e_quantize_mode quantize_mode, double stroke_width, + bool do_simplify, bool return_curves, + std::vector<double>& vertices, std::vector<npy_uint8>& codes) { typedef agg::conv_transform<PathIterator> transformed_path_t; typedef PathNanRemover<transformed_path_t> nan_removal_t; @@ -1241,7 +1242,7 @@ transformed_path_t tpath(path, trans); nan_removal_t nan_removed(tpath, remove_nans, path.has_curves()); clipped_t clipped(nan_removed, do_clip, rect); - quantized_t quantized(clipped, quantize_mode, path.total_vertices()); + quantized_t quantized(clipped, quantize_mode, path.total_vertices(), stroke_width); simplify_t simplified(quantized, do_simplify, path.simplify_threshold()); vertices.reserve(path.total_vertices() * 2); @@ -1260,7 +1261,7 @@ Py::Object _path_module::cleanup_path(const Py::Tuple& args) { - args.verify_length(7); + args.verify_length(8); PathIterator path(args[0]); agg::trans_affine trans = py_to_agg_transformation_matrix(args[1].ptr(), false); @@ -1300,8 +1301,10 @@ quantize_mode = QUANTIZE_FALSE; } + double stroke_width = Py::Float(args[5]); + bool simplify; - Py::Object simplify_obj = args[5]; + Py::Object simplify_obj = args[6]; if (simplify_obj.isNone()) { simplify = path.should_simplify(); @@ -1311,13 +1314,13 @@ simplify = simplify_obj.isTrue(); } - bool return_curves = args[6].isTrue(); + bool return_curves = args[7].isTrue(); std::vector<double> vertices; std::vector<npy_uint8> codes; _cleanup_path(path, trans, remove_nans, do_clip, clip_rect, quantize_mode, - simplify, return_curves, vertices, codes); + stroke_width, simplify, return_curves, vertices, codes); npy_intp length = codes.size(); npy_intp dims[] = { length, 2, 0 }; Modified: trunk/matplotlib/src/path_cleanup.cpp =================================================================== --- trunk/matplotlib/src/path_cleanup.cpp 2010-06-11 08:34:24 UTC (rev 8413) +++ trunk/matplotlib/src/path_cleanup.cpp 2010-06-11 14:30:32 UTC (rev 8414) @@ -28,14 +28,16 @@ PathCleanupIterator(PyObject* path, agg::trans_affine trans, bool remove_nans, bool do_clip, const agg::rect_base<double>& rect, - e_quantize_mode quantize_mode, bool do_simplify) : + e_quantize_mode quantize_mode, double stroke_width, + bool do_simplify) : m_path_obj(path, true), m_path_iter(m_path_obj), m_transform(trans), m_transformed(m_path_iter, m_transform), m_nan_removed(m_transformed, remove_nans, m_path_iter.has_curves()), m_clipped(m_nan_removed, do_clip, rect), - m_quantized(m_clipped, quantize_mode, m_path_iter.total_vertices()), + m_quantized(m_clipped, quantize_mode, m_path_iter.total_vertices(), + stroke_width), m_simplify(m_quantized, do_simplify && m_path_iter.should_simplify(), m_path_iter.simplify_threshold()) { @@ -53,14 +55,15 @@ void* get_path_iterator( PyObject* path, PyObject* trans, int remove_nans, int do_clip, - double rect[4], e_quantize_mode quantize_mode, int do_simplify) + double rect[4], e_quantize_mode quantize_mode, double stroke_width, + int do_simplify) { agg::trans_affine agg_trans = py_to_agg_transformation_matrix(trans, false); agg::rect_base<double> clip_rect(rect[0], rect[1], rect[2], rect[3]); PathCleanupIterator* pipeline = new PathCleanupIterator( path, agg_trans, remove_nans != 0, do_clip != 0, - clip_rect, quantize_mode, do_simplify != 0); + clip_rect, quantize_mode, stroke_width, do_simplify != 0); return (void*)pipeline; } Modified: trunk/matplotlib/src/path_converters.h =================================================================== --- trunk/matplotlib/src/path_converters.h 2010-06-11 08:34:24 UTC (rev 8413) +++ trunk/matplotlib/src/path_converters.h 2010-06-11 14:30:32 UTC (rev 8414) @@ -378,6 +378,7 @@ private: VertexSource* m_source; bool m_quantize; + double m_quantize_value; static bool should_quantize(VertexSource& path, e_quantize_mode quantize_mode, @@ -436,10 +437,17 @@ - QUANTIZE_FALSE: No quantization */ PathQuantizer(VertexSource& source, e_quantize_mode quantize_mode, - unsigned total_vertices=15) : + unsigned total_vertices=15, double stroke_width=0.0) : m_source(&source) { m_quantize = should_quantize(source, quantize_mode, total_vertices); + + if (m_quantize) + { + int odd_even = (int)mpl_round(stroke_width) % 2; + m_quantize_value = (odd_even) ? 0.5 : 0.0; + } + source.rewind(0); } @@ -454,8 +462,8 @@ code = m_source->vertex(x, y); if (m_quantize && agg::is_vertex(code)) { - *x = mpl_round(*x) + 0.5; - *y = mpl_round(*y) + 0.5; + *x = mpl_round(*x) + m_quantize_value; + *y = mpl_round(*y) + m_quantize_value; } return code; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |