Revision: 6080
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6080&view=rev
Author:   mdboom
Date:     2008-09-10 18:46:10 +0000 (Wed, 10 Sep 2008)

Log Message:
-----------
[ 2089958 ] Path simplification for vector output backends

Modified Paths:
--------------
    trunk/matplotlib/CHANGELOG
    trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
    trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
    trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
    trunk/matplotlib/lib/matplotlib/config/mplconfig.py
    trunk/matplotlib/lib/matplotlib/config/rcsetup.py
    trunk/matplotlib/lib/matplotlib/path.py
    trunk/matplotlib/lib/matplotlib/rcsetup.py
    trunk/matplotlib/matplotlibrc.template

Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG  2008-09-10 15:28:55 UTC (rev 6079)
+++ trunk/matplotlib/CHANGELOG  2008-09-10 18:46:10 UTC (rev 6080)
@@ -1,3 +1,10 @@
+2008-09-10 [ 2089958 ] Path simplification for vector output backends
+           Leverage the simplification code exposed through
+           path_to_polygons to simplify certain well-behaved paths in
+           the vector backends (PDF, PS and SVG).  "path.simplify"
+           must be set to True in matplotlibrc for this to work.  -
+           MGD
+
 2008-09-10 Add "filled" kwarg to Path.intersects_path and
            Path.intersects_bbox. - MGD
 

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py     2008-09-10 
15:28:55 UTC (rev 6079)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py     2008-09-10 
18:46:10 UTC (rev 6080)
@@ -331,6 +331,10 @@
     def __init__(self, width, height, dpi, filename):
         self.width, self.height = width, height
         self.dpi = dpi
+        if rcParams['path.simplify']:
+            self.simplify = (width * dpi, height * dpi)
+        else:
+            self.simplify = None
         self.nextObject = 1     # next free object id
         self.xrefTable = [ [0, 65535, 'the zero object'] ]
         self.passed_in_file_object = False
@@ -1092,12 +1096,12 @@
             self.endStream()
 
     [EMAIL PROTECTED]
-    def pathOperations(path, transform):
+    def pathOperations(path, transform, simplify=None):
         tpath = transform.transform_path(path)
 
         cmds = []
         last_points = None
-        for points, code in tpath.iter_segments():
+        for points, code in tpath.iter_segments(simplify):
             if code == Path.MOVETO:
                 cmds.extend(points)
                 cmds.append(Op.moveto)
@@ -1118,7 +1122,8 @@
     pathOperations = staticmethod(pathOperations)
 
     def writePath(self, path, transform):
-        cmds = self.pathOperations(path, transform)
+        cmds = self.pathOperations(
+            path, transform, self.simplify)
         self.output(*cmds)
 
     def reserveObject(self, name=''):

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py      2008-09-10 
15:28:55 UTC (rev 6079)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py      2008-09-10 
18:46:10 UTC (rev 6080)
@@ -145,6 +145,10 @@
             self.textcnt = 0
             self.psfrag = []
         self.imagedpi = imagedpi
+        if rcParams['path.simplify']:
+            self.simplify = (width * imagedpi, height * imagedpi)
+        else:
+            self.simplify = None
 
         # current renderer state (None=uninitialised)
         self.color = None
@@ -444,12 +448,12 @@
         # unflip
         im.flipud_out()
 
-    def _convert_path(self, path, transform):
+    def _convert_path(self, path, transform, simplify=None):
         path = transform.transform_path(path)
 
         ps = []
         last_points = None
-        for points, code in path.iter_segments():
+        for points, code in path.iter_segments(simplify):
             if code == Path.MOVETO:
                 ps.append("%g %g m" % tuple(points))
             elif code == Path.LINETO:
@@ -463,7 +467,7 @@
             elif code == Path.CLOSEPOLY:
                 ps.append("cl")
             last_points = points
-            
+
         ps = "\n".join(ps)
         return ps
 
@@ -482,7 +486,7 @@
         """
         Draws a Path instance using the given affine transform.
         """
-        ps = self._convert_path(path, transform)
+        ps = self._convert_path(path, transform, self.simplify)
         self._draw_ps(ps, gc, rgbFace)
 
     def draw_markers(self, gc, marker_path, marker_trans, path, trans, 
rgbFace=None):

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py     2008-09-10 
15:28:55 UTC (rev 6079)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py     2008-09-10 
18:46:10 UTC (rev 6080)
@@ -42,6 +42,10 @@
         self.width=width
         self.height=height
         self._svgwriter = svgwriter
+        if rcParams['path.simplify']:
+            self.simplify = (width, height)
+        else:
+            self.simplify = None
 
         self._groupd = {}
         if not rcParams['svg.image_inline']:
@@ -165,14 +169,14 @@
                 .scale(1.0, -1.0)
                 .translate(0.0, self.height))
 
-    def _convert_path(self, path, transform):
+    def _convert_path(self, path, transform, simplify=None):
         tpath = transform.transform_path(path)
 
         path_data = []
         appender = path_data.append
         path_commands = self._path_commands
         currpos = 0
-        for points, code in tpath.iter_segments():
+        for points, code in tpath.iter_segments(simplify):
             if code == Path.CLOSEPOLY:
                 segment = 'z'
             else:
@@ -187,7 +191,7 @@
 
     def draw_path(self, gc, path, transform, rgbFace=None):
         trans_and_flip = self._make_flip_transform(transform)
-        path_data = self._convert_path(path, trans_and_flip)
+        path_data = self._convert_path(path, trans_and_flip, self.simplify)
         self._draw_svg_element('path', 'd="%s"' % path_data, gc, rgbFace)
 
     def draw_markers(self, gc, marker_path, marker_trans, path, trans, 
rgbFace=None):

Modified: trunk/matplotlib/lib/matplotlib/config/mplconfig.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2008-09-10 15:28:55 UTC 
(rev 6079)
+++ trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2008-09-10 18:46:10 UTC 
(rev 6080)
@@ -117,6 +117,9 @@
         markersize = T.Float(6)
         antialiased = T.true
 
+    class path(TConfig):
+        simplify = T.false
+
     class patch(TConfig):
         linewidth = T.Float(1.0)
         facecolor = T.Trait('blue', mplT.ColorHandler())
@@ -439,6 +442,8 @@
         'svg.image_noscale' : (self.tconfig.backend.svg, 'image_noscale'),
         'svg.embed_char_paths' : (self.tconfig.backend.svg, 
'embed_char_paths'),
 
+        # Path properties
+        'path.simplify' : (self.tconfig.path, 'simplify')
         }
 
     def __setitem__(self, key, val):

Modified: trunk/matplotlib/lib/matplotlib/config/rcsetup.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/config/rcsetup.py   2008-09-10 15:28:55 UTC 
(rev 6079)
+++ trunk/matplotlib/lib/matplotlib/config/rcsetup.py   2008-09-10 18:46:10 UTC 
(rev 6080)
@@ -476,6 +476,7 @@
     'svg.embed_char_paths' : [True, validate_bool],  # True to save all 
characters as paths in the SVG
     'plugins.directory' : ['.matplotlib_plugins', str], # where plugin 
directory is locate
 
+    'path.simplify' : [False, validate_bool]
 }
 
 if __name__ == '__main__':

Modified: trunk/matplotlib/lib/matplotlib/path.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/path.py     2008-09-10 15:28:55 UTC (rev 
6079)
+++ trunk/matplotlib/lib/matplotlib/path.py     2008-09-10 18:46:10 UTC (rev 
6080)
@@ -145,12 +145,24 @@
     def __len__(self):
         return len(self.vertices)
 
-    def iter_segments(self):
+    def iter_segments(self, simplify=None):
         """
         Iterates over all of the curve segments in the path.  Each
         iteration returns a 2-tuple (*vertices*, *code*), where
         *vertices* is a sequence of 1 - 3 coordinate pairs, and *code* is
         one of the :class:`Path` codes.
+
+        If *simplify* is provided, it must be a tuple (*width*,
+        *height*) defining the size of the figure, in native units
+        (e.g. pixels or points).  Simplification implies both removing
+        adjacent line segments that are very close to parallel, and
+        removing line segments outside of the figure.  The path will
+        be simplified *only* if :attr:`should_simplify` is True, which
+        is determined in the constructor by this criteria:
+
+           - No *codes* array
+           - No nonfinite values
+           - More than 128 vertices
         """
         vertices = self.vertices
         if not len(vertices):
@@ -166,7 +178,13 @@
         CLOSEPOLY    = self.CLOSEPOLY
         STOP         = self.STOP
 
-        if codes is None:
+        if simplify is not None and self.should_simplify:
+            polygons = self.to_polygons(None, *simplify)
+            for vertices in polygons:
+                yield vertices[0], MOVETO
+                for v in vertices[1:]:
+                    yield v, LINETO
+        elif codes is None:
             next_code = MOVETO
             for v in vertices:
                 if (~isfinite(v)).any():

Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/rcsetup.py  2008-09-10 15:28:55 UTC (rev 
6079)
+++ trunk/matplotlib/lib/matplotlib/rcsetup.py  2008-09-10 18:46:10 UTC (rev 
6080)
@@ -487,6 +487,7 @@
     'svg.embed_char_paths' : [True, validate_bool],  # True to save all 
characters as paths in the SVG
     'plugins.directory' : ['.matplotlib_plugins', str], # where plugin 
directory is locate
 
+    'path.simplify' : [False, validate_bool]
 }
 
 if __name__ == '__main__':

Modified: trunk/matplotlib/matplotlibrc.template
===================================================================
--- trunk/matplotlib/matplotlibrc.template      2008-09-10 15:28:55 UTC (rev 
6079)
+++ trunk/matplotlib/matplotlibrc.template      2008-09-10 18:46:10 UTC (rev 
6080)
@@ -270,6 +270,8 @@
 #contour.negative_linestyle :  dashed # dashed | solid
 
 ### SAVING FIGURES
+#path.simplify : False  # When True, simplify paths in vector backends, such 
as PDF, PS and SVG
+
 # the default savefig params can be different for the GUI backends.
 # Eg, you may want a higher resolution, or to make the figure
 # background white


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-checkins mailing list
Matplotlib-checkins@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to