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.

------------------------------------------------------------------------------
ThinkGeek and WIRED's GeekDad team up for the Ultimate 
GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the 
lucky parental unit.  See the prize list and enter to win: 
http://p.sf.net/sfu/thinkgeek-promo
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to