|
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.
|