Revision: 6708
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6708&view=rev
Author: mdboom
Date: 2008-12-29 14:08:13 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Merge branch 'hatching'
Modified Paths:
--------------
trunk/matplotlib/examples/pylab_examples/hatch_demo.py
trunk/matplotlib/lib/matplotlib/backend_bases.py
trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
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/path.py
trunk/matplotlib/src/_backend_agg.cpp
trunk/matplotlib/src/_backend_agg.h
Modified: trunk/matplotlib/examples/pylab_examples/hatch_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2008-12-29
13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/examples/pylab_examples/hatch_demo.py 2008-12-29
14:08:13 UTC (rev 6708)
@@ -12,7 +12,7 @@
xytext=(0, 5),
xycoords="axes fraction", textcoords="offset points", ha="center"
)
-ax1.bar(range(1,5), range(1,5), color='gray', ecolor='black', hatch="/")
+ax1.bar(range(1,5), range(1,5), color='gray', edgecolor='red', hatch="/")
ax2 = fig.add_subplot(122)
@@ -23,3 +23,5 @@
bar.set_hatch(pattern)
plt.show()
+plt.savefig("test.pdf")
+plt.savefig("test.ps")
Modified: trunk/matplotlib/lib/matplotlib/backend_bases.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backend_bases.py 2008-12-29 13:58:18 UTC
(rev 6707)
+++ trunk/matplotlib/lib/matplotlib/backend_bases.py 2008-12-29 14:08:13 UTC
(rev 6708)
@@ -30,6 +30,7 @@
import matplotlib.colors as colors
import matplotlib.transforms as transforms
import matplotlib.widgets as widgets
+import matplotlib.path as path
from matplotlib import rcParams
class RendererBase:
@@ -679,6 +680,14 @@
"""
return self._hatch
+ def get_hatch_path(self, density=6.0):
+ """
+ Returns a Path for the current hatch.
+ """
+ if self._hatch is None:
+ return None
+ return path.Path.hatch(self._hatch, density)
+
class Event:
"""
A matplotlib event. Attach additional attributes as defined in
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2008-12-29
13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2008-12-29
14:08:13 UTC (rev 6708)
@@ -73,9 +73,13 @@
'debug-annoying')
def draw_path(self, gc, path, transform, rgbFace=None):
+ """
+ Draw the path
+ """
nmax = rcParams['agg.path.chunksize'] # here at least for testing
npts = path.vertices.shape[0]
- if nmax > 100 and npts > nmax and path.should_simplify and rgbFace is
None:
+ if (nmax > 100 and npts > nmax and path.should_simplify and
+ rgbFace is None and gc.get_hatch() is None):
nch = npy.ceil(npts/float(nmax))
chsize = int(npy.ceil(npts/nch))
i0 = npy.arange(0, npts, chsize)
@@ -93,7 +97,6 @@
else:
self._renderer.draw_path(gc, path, transform, rgbFace)
-
def draw_mathtext(self, gc, x, y, s, prop, angle):
"""
Draw the math text using matplotlib.mathtext
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-29
13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-12-29
14:08:13 UTC (rev 6708)
@@ -953,21 +953,20 @@
'CA': alpha, 'ca': alpha })
return name
- def hatchPattern(self, lst):
- pattern = self.hatchPatterns.get(lst, None)
+ def hatchPattern(self, hatch_style):
+ pattern = self.hatchPatterns.get(hatch_style, None)
if pattern is not None:
return pattern
name = Name('H%d' % self.nextHatch)
self.nextHatch += 1
- self.hatchPatterns[lst] = name
+ self.hatchPatterns[hatch_style] = name
return name
def writeHatches(self):
hatchDict = dict()
- sidelen = 144.0
- density = 24.0
- for lst, name in self.hatchPatterns.items():
+ sidelen = 72.0
+ for hatch_style, name in self.hatchPatterns.items():
ob = self.reserveObject('hatch pattern')
hatchDict[name] = ob
res = { 'Procsets':
@@ -983,33 +982,21 @@
# lst is a tuple of stroke color, fill color,
# number of - lines, number of / lines,
# number of | lines, number of \ lines
- rgb = lst[0]
+ rgb = hatch_style[0]
self.output(rgb[0], rgb[1], rgb[2], Op.setrgb_stroke)
- if lst[1] is not None:
- rgb = lst[1]
+ if hatch_style[1] is not None:
+ rgb = hatch_style[1]
self.output(rgb[0], rgb[1], rgb[2], Op.setrgb_nonstroke,
0, 0, sidelen, sidelen, Op.rectangle,
Op.fill)
- if lst[2]: # -
- for j in npy.arange(0.0, sidelen, density/lst[2]):
- self.output(0, j, Op.moveto,
- sidelen, j, Op.lineto)
- if lst[3]: # /
- for j in npy.arange(0.0, sidelen, density/lst[3]):
- self.output(0, j, Op.moveto,
- sidelen-j, sidelen, Op.lineto,
- sidelen-j, 0, Op.moveto,
- sidelen, j, Op.lineto)
- if lst[4]: # |
- for j in npy.arange(0.0, sidelen, density/lst[4]):
- self.output(j, 0, Op.moveto,
- j, sidelen, Op.lineto)
- if lst[5]: # \
- for j in npy.arange(sidelen, 0.0, -density/lst[5]):
- self.output(sidelen, j, Op.moveto,
- j, sidelen, Op.lineto,
- j, 0, Op.moveto,
- 0, j, Op.lineto)
+
+ self.output(0.1, Op.setlinewidth)
+
+ # TODO: We could make this dpi-dependent, but that would be
+ # an API change
+ self.output(*self.pathOperations(
+ Path.hatch(hatch_style[2]),
+ Affine2D().scale(sidelen)))
self.output(Op.stroke)
self.endStream()
@@ -1735,13 +1722,8 @@
return [Name('DeviceRGB'), Op.setcolorspace_nonstroke]
else:
hatch = hatch.lower()
- lst = ( self._rgb,
- self._fillcolor,
- hatch.count('-') + hatch.count('+'),
- hatch.count('/') + hatch.count('x'),
- hatch.count('|') + hatch.count('+'),
- hatch.count('\\') + hatch.count('x') )
- name = self.file.hatchPattern(lst)
+ hatch_style = (self._rgb, self._fillcolor, hatch)
+ name = self.file.hatchPattern(hatch_style)
return [Name('Pattern'), Op.setcolorspace_nonstroke,
name, Op.setcolor_nonstroke]
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2008-12-29
13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2008-12-29
14:08:13 UTC (rev 6708)
@@ -31,7 +31,7 @@
from matplotlib._mathtext_data import uni2type1
from matplotlib.text import Text
from matplotlib.path import Path
-from matplotlib.transforms import IdentityTransform
+from matplotlib.transforms import Affine2D
import numpy as npy
import binascii
@@ -163,7 +163,7 @@
self.linedash = None
self.fontname = None
self.fontsize = None
- self.hatch = None
+ self._hatches = {}
self.image_magnification = imagedpi/72.0
self._clip_paths = {}
self._path_collection_id = 0
@@ -231,58 +231,36 @@
if store: self.fontname = fontname
if store: self.fontsize = fontsize
- def set_hatch(self, hatch):
- """
- hatch can be one of:
- / - diagonal hatching
- \ - back diagonal
- | - vertical
- - - horizontal
- + - crossed
- X - crossed diagonal
+ def create_hatch(self, hatch):
+ sidelen = 72
+ if self._hatches.has_key(hatch):
+ return self._hatches[hatch]
+ name = 'H%d' % len(self._hatches)
+ self._pswriter.write("""\
+ << /PatternType 1
+ /PaintType 2
+ /TilingType 2
+ /BBox[0 0 %(sidelen)d %(sidelen)d]
+ /XStep %(sidelen)d
+ /YStep %(sidelen)d
- letters can be combined, in which case all the specified
- hatchings are done
+ /PaintProc {
+ pop
+ 0 setlinewidth
+""" % locals())
+ self._pswriter.write(
+ self._convert_path(Path.hatch(hatch), Affine2D().scale(72.0)))
+ self._pswriter.write("""\
+ stroke
+ } bind
+ >>
+ matrix
+ makepattern
+ /%(name)s exch def
+""" % locals())
+ self._hatches[hatch] = name
+ return name
- if same letter repeats, it increases the density of hatching
- in that direction
- """
- hatches = {'horiz':0, 'vert':0, 'diag1':0, 'diag2':0}
-
- for letter in hatch:
- if (letter == '/'): hatches['diag2'] += 1
- elif (letter == '\\'): hatches['diag1'] += 1
- elif (letter == '|'): hatches['vert'] += 1
- elif (letter == '-'): hatches['horiz'] += 1
- elif (letter == '+'):
- hatches['horiz'] += 1
- hatches['vert'] += 1
- elif (letter.lower() == 'x'):
- hatches['diag1'] += 1
- hatches['diag2'] += 1
-
- def do_hatch(angle, density):
- if (density == 0): return ""
- return """\
- gsave
- eoclip %s rotate 0.0 0.0 0.0 0.0 setrgbcolor 0 setlinewidth
- /hatchgap %d def
- pathbbox /hatchb exch def /hatchr exch def /hatcht exch def /hatchl exch def
- hatchl cvi hatchgap idiv hatchgap mul
- hatchgap
- hatchr cvi hatchgap idiv hatchgap mul
- {hatcht m 0 hatchb hatcht sub r }
- for
- stroke
- grestore
- """ % (angle, 12/density)
- self._pswriter.write("gsave\n")
- self._pswriter.write(do_hatch(90, hatches['horiz']))
- self._pswriter.write(do_hatch(0, hatches['vert']))
- self._pswriter.write(do_hatch(45, hatches['diag1']))
- self._pswriter.write(do_hatch(-45, hatches['diag2']))
- self._pswriter.write("grestore\n")
-
def get_canvas_width_height(self):
'return the canvas width and height in display coords'
return self.width, self.height
@@ -816,15 +794,17 @@
if fill:
if stroke:
write("gsave\n")
- self.set_color(store=0, *rgbFace[:3])
- write("fill\ngrestore\n")
- else:
- self.set_color(store=0, *rgbFace[:3])
- write("fill\n")
+ self.set_color(store=0, *rgbFace[:3])
+ write("fill\n")
+ if stroke:
+ write("grestore\n")
hatch = gc.get_hatch()
if hatch:
- self.set_hatch(hatch)
+ hatch_name = self.create_hatch(hatch)
+ write("gsave\n")
+ write("[/Pattern [/DeviceRGB]] setcolorspace %f %f %f " %
gc.get_rgb()[:3])
+ write("%s setcolor fill grestore\n" % hatch_name)
if stroke:
write("stroke\n")
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2008-12-29
13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2008-12-29
14:08:13 UTC (rev 6708)
@@ -57,6 +57,7 @@
self._markers = {}
self._path_collection_id = 0
self._imaged = {}
+ self._hatchd = {}
self.mathtext_parser = MathTextParser('SVG')
svgwriter.write(svgProlog%(width,height,width,height))
@@ -90,15 +91,38 @@
font.set_size(size, 72.0)
return font
+ def _get_hatch(self, gc, rgbFace):
+ """
+ Create a new hatch pattern
+ """
+ HATCH_SIZE = 144
+ dictkey = (gc.get_hatch().lower(), rgbFace, gc.get_rgb())
+ id = self._hatchd.get(dictkey)
+ if id is None:
+ id = 'h%s' % md5(str(dictkey)).hexdigest()
+ self._svgwriter.write('<defs>\n <pattern id="%s" ' % id)
+ self._svgwriter.write('patternUnits="userSpaceOnUse" x="0" y="0" ')
+ self._svgwriter.write(' width="%d" height="%d" >\n' % (HATCH_SIZE,
HATCH_SIZE))
+ path_data = self._convert_path(gc.get_hatch_path(),
Affine2D().scale(144))
+ path = '<path d="%s" fill="%s" stroke="%s" stroke-width="1.0"/>' %
(
+ path_data, rgb2hex(rgbFace[:3]), rgb2hex(gc.get_rgb()[:3]))
+ self._svgwriter.write(path)
+ self._svgwriter.write('\n </pattern>\n</defs>')
+ self._hatchd[dictkey] = id
+ return id
+
def _get_style(self, gc, rgbFace):
"""
return the style string.
style is generated from the GraphicsContext, rgbFace and clippath
"""
- if rgbFace is None:
- fill = 'none'
+ if gc.get_hatch() is not None:
+ fill = "url(#%s)" % self._get_hatch(gc, rgbFace)
else:
- fill = rgb2hex(rgbFace[:3])
+ if rgbFace is None:
+ fill = 'none'
+ else:
+ fill = rgb2hex(rgbFace[:3])
offset, seq = gc.get_dashes()
if seq is None:
@@ -150,7 +174,7 @@
def open_group(self, s, gid=None):
"""
Open a grouping element with label *s*. If *gid* is given, use
- *gid* as the id of the group.
+ *gid* as the id of the group.
"""
if gid:
self._svgwriter.write('<g id="%s">\n' % (gid))
Modified: trunk/matplotlib/lib/matplotlib/path.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/path.py 2008-12-29 13:58:18 UTC (rev
6707)
+++ trunk/matplotlib/lib/matplotlib/path.py 2008-12-29 14:08:13 UTC (rev
6708)
@@ -11,7 +11,7 @@
from matplotlib._path import point_in_path, get_path_extents, \
point_in_path_collection, get_path_collection_extents, \
path_in_path, path_intersects_path, convert_path_to_polygons
-from matplotlib.cbook import simple_linear_interpolation
+from matplotlib.cbook import simple_linear_interpolation, maxdict
class Path(object):
"""
@@ -115,8 +115,8 @@
self.codes = codes
self.vertices = vertices
- #...@staticmethod
- def make_compound_path(*args):
+ #...@classmethod
+ def make_compound_path(cls, *args):
"""
(staticmethod) Make a compound path from a list of Path
objects. Only polygons (not curves) are supported.
@@ -130,14 +130,14 @@
vertices = np.vstack([x.vertices for x in args])
vertices.reshape((total_length, 2))
- codes = Path.LINETO * np.ones(total_length)
+ codes = cls.LINETO * np.ones(total_length)
i = 0
for length in lengths:
- codes[i] = Path.MOVETO
+ codes[i] = cls.MOVETO
i += length
- return Path(vertices, codes)
- make_compound_path = staticmethod(make_compound_path)
+ return cls(vertices, codes)
+ make_compound_path = classmethod(make_compound_path)
def __repr__(self):
return "Path(%s, %s)" % (self.vertices, self.codes)
@@ -343,7 +343,7 @@
"""
if cls._unit_rectangle is None:
cls._unit_rectangle = \
- Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0,
0.0]])
+ cls([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0,
0.0]])
return cls._unit_rectangle
unit_rectangle = classmethod(unit_rectangle)
@@ -366,7 +366,7 @@
# "points-up"
theta += np.pi / 2.0
verts = np.concatenate((np.cos(theta), np.sin(theta)), 1)
- path = Path(verts)
+ path = cls(verts)
cls._unit_regular_polygons[numVertices] = path
return path
unit_regular_polygon = classmethod(unit_regular_polygon)
@@ -392,7 +392,7 @@
r = np.ones(ns2 + 1)
r[1::2] = innerCircle
verts = np.vstack((r*np.cos(theta), r*np.sin(theta))).transpose()
- path = Path(verts)
+ path = cls(verts)
cls._unit_regular_polygons[(numVertices, innerCircle)] = path
return path
unit_regular_star = classmethod(unit_regular_star)
@@ -466,7 +466,7 @@
codes[0] = cls.MOVETO
codes[-1] = cls.CLOSEPOLY
- cls._unit_circle = Path(vertices, codes)
+ cls._unit_circle = cls(vertices, codes)
return cls._unit_circle
unit_circle = classmethod(unit_circle)
@@ -523,19 +523,19 @@
if is_wedge:
length = n * 3 + 4
- vertices = np.zeros((length, 2), np.float_)
- codes = Path.CURVE4 * np.ones((length, ), Path.code_type)
+ vertices = np.empty((length, 2), np.float_)
+ codes = cls.CURVE4 * np.ones((length, ), cls.code_type)
vertices[1] = [xA[0], yA[0]]
- codes[0:2] = [Path.MOVETO, Path.LINETO]
- codes[-2:] = [Path.LINETO, Path.CLOSEPOLY]
+ codes[0:2] = [cls.MOVETO, cls.LINETO]
+ codes[-2:] = [cls.LINETO, cls.CLOSEPOLY]
vertex_offset = 2
end = length - 2
else:
length = n * 3 + 1
- vertices = np.zeros((length, 2), np.float_)
- codes = Path.CURVE4 * np.ones((length, ), Path.code_type)
+ vertices = np.empty((length, 2), np.float_)
+ codes = cls.CURVE4 * np.ones((length, ), cls.code_type)
vertices[0] = [xA[0], yA[0]]
- codes[0] = Path.MOVETO
+ codes[0] = cls.MOVETO
vertex_offset = 1
end = length
@@ -546,7 +546,7 @@
vertices[vertex_offset+2:end:3, 0] = xB
vertices[vertex_offset+2:end:3, 1] = yB
- return Path(vertices, codes)
+ return cls(vertices, codes)
arc = classmethod(arc)
#...@classmethod
@@ -562,6 +562,94 @@
return cls.arc(theta1, theta2, n, True)
wedge = classmethod(wedge)
+ _hatch_dict = maxdict(8)
+ #...@classmethod
+ def hatch(cls, hatchpattern, density=6):
+ """
+ Given a hatch specifier, *hatchpattern*, generates a Path that
+ can be used in a repeated hatching pattern. *density* is the
+ number of lines per unit square.
+ """
+ if hatchpattern is None:
+ return None
+
+ hatch = hatchpattern.lower()
+ hatch_path = cls._hatch_dict.get((hatch, density))
+ if hatch_path is not None:
+ return hatch_path
+
+ size = 1.0
+ density = int(density)
+ counts = [
+ hatch.count('-') + hatch.count('+'),
+ hatch.count('/') + hatch.count('x'),
+ hatch.count('|') + hatch.count('+'),
+ hatch.count('\\') + hatch.count('x')
+ ]
+
+ if sum(counts) == 0:
+ return cls([])
+
+ counts = [x * density for x in counts]
+
+ num_vertices = (counts[0] * 2 + counts[1] * 4 +
+ counts[2] * 2 + counts[3] * 4)
+ vertices = np.empty((num_vertices, 2))
+ codes = np.empty((num_vertices,), cls.code_type)
+ codes[0::2] = cls.MOVETO
+ codes[1::2] = cls.LINETO
+
+ cursor = 0
+
+ if counts[0]:
+ vertices_chunk = vertices[cursor:cursor + counts[0] * 2]
+ cursor += counts[0] * 2
+ steps = np.linspace(0.0, 1.0, counts[0], False)
+ vertices_chunk[0::2, 0] = 0.0
+ vertices_chunk[0::2, 1] = steps
+ vertices_chunk[1::2, 0] = size
+ vertices_chunk[1::2, 1] = steps
+
+ if counts[1]:
+ vertices_chunk = vertices[cursor:cursor + counts[1] * 4]
+ cursor += counts[1] * 4
+ steps = np.linspace(0.0, 1.0, counts[1], False)
+ vertices_chunk[0::4, 0] = 0.0
+ vertices_chunk[0::4, 1] = steps
+ vertices_chunk[1::4, 0] = size - steps
+ vertices_chunk[1::4, 1] = size
+ vertices_chunk[2::4, 0] = size - steps
+ vertices_chunk[2::4, 1] = 0.0
+ vertices_chunk[3::4, 0] = size
+ vertices_chunk[3::4, 1] = steps
+
+ if counts[2]:
+ vertices_chunk = vertices[cursor:cursor + counts[2] * 2]
+ cursor += counts[2] * 2
+ steps = np.linspace(0.0, 1.0, counts[2], False)
+ vertices_chunk[0::2, 0] = steps
+ vertices_chunk[0::2, 1] = 0.0
+ vertices_chunk[1::2, 0] = steps
+ vertices_chunk[1::2, 1] = size
+
+ if counts[3]:
+ vertices_chunk = vertices[cursor:cursor + counts[3] * 4]
+ cursor += counts[3] * 4
+ steps = np.linspace(0.0, 1.0, counts[3], False)
+ vertices_chunk[0::4, 0] = size
+ vertices_chunk[0::4, 1] = steps
+ vertices_chunk[1::4, 0] = steps
+ vertices_chunk[1::4, 1] = size
+ vertices_chunk[2::4, 0] = steps
+ vertices_chunk[2::4, 1] = 0.0
+ vertices_chunk[3::4, 0] = 0.0
+ vertices_chunk[3::4, 1] = steps
+
+ hatch_path = cls(vertices, codes)
+ cls._hatch_dict[(hatch, density)] = hatch_path
+ return hatch_path
+ hatch = classmethod(hatch)
+
_get_path_collection_extents = get_path_collection_extents
def get_path_collection_extents(*args):
"""
Modified: trunk/matplotlib/src/_backend_agg.cpp
===================================================================
--- trunk/matplotlib/src/_backend_agg.cpp 2008-12-29 13:58:18 UTC (rev
6707)
+++ trunk/matplotlib/src/_backend_agg.cpp 2008-12-29 14:08:13 UTC (rev
6708)
@@ -30,6 +30,7 @@
#include "agg_span_image_filter_gray.h"
#include "agg_span_image_filter_rgba.h"
#include "agg_span_interpolator_linear.h"
+#include "agg_span_pattern_rgba.h"
#include "agg_conv_shorten_path.h"
#include "util/agg_color_conv_rgb8.h"
@@ -149,6 +150,7 @@
_set_clip_rectangle(gc);
_set_clip_path(gc);
_set_snap(gc);
+ _set_hatch_path(gc);
}
GCAgg::GCAgg(double dpi) :
@@ -273,6 +275,15 @@
}
}
+void
+GCAgg::_set_hatch_path( const Py::Object& gc) {
+ _VERBOSE("GCAgg::_set_hatch_path");
+
+ Py::Object method_obj = gc.getAttr("get_hatch_path");
+ Py::Callable method(method_obj);
+ hatchpath = method.apply(Py::Tuple());
+}
+
const size_t
RendererAgg::PIXELS_PER_INCH(96);
@@ -310,6 +321,7 @@
rendererBase.clear(agg::rgba(1, 1, 1, 0));
rendererAA.attach(rendererBase);
rendererBin.attach(rendererBase);
+ hatchRenderingBuffer.attach(hatchBuffer, HATCH_SIZE, HATCH_SIZE,
HATCH_SIZE*4);
}
void RendererAgg::create_alpha_buffers() {
@@ -879,6 +891,55 @@
}
}
+ // Render hatch
+ if (!gc.hatchpath.isNone()) {
+ // Reset any clipping that may be in effect, since we'll be
+ // drawing the hatch in a scratch buffer at origin (0, 0)
+ theRasterizer.reset_clipping();
+ rendererBase.reset_clipping(true);
+
+ // Create and transform the path
+ typedef agg::conv_transform<PathIterator> hatch_path_trans_t;
+ typedef SimplifyPath<hatch_path_trans_t> hatch_path_simplify_t;
+ typedef agg::conv_stroke<hatch_path_simplify_t> hatch_path_stroke_t;
+
+ PathIterator hatch_path(gc.hatchpath);
+ agg::trans_affine hatch_trans;
+ hatch_trans *= agg::trans_affine_scaling(HATCH_SIZE, HATCH_SIZE);
+ hatch_path_trans_t hatch_path_trans(hatch_path, hatch_trans);
+ hatch_path_simplify_t hatch_path_simplify
+ (hatch_path_trans, true, false, HATCH_SIZE, HATCH_SIZE);
+ hatch_path_stroke_t hatch_path_stroke(hatch_path_simplify);
+ hatch_path_stroke.width(1.0);
+ hatch_path_stroke.line_cap(agg::square_cap);
+ theRasterizer.add_path(hatch_path_stroke);
+
+ // Render the path into the hatch buffer
+ pixfmt hatch_img_pixf(hatchRenderingBuffer);
+ renderer_base rb(hatch_img_pixf);
+ renderer_aa rs(rb);
+ rb.clear(agg::rgba(0.0, 0.0, 0.0, 0.0));
+ rs.color(gc.color);
+ agg::render_scanlines(theRasterizer, slineP8, rs);
+
+ // Put clipping back on, if originally set on entry to this
+ // function
+ set_clipbox(gc.cliprect, theRasterizer);
+ if (has_clippath)
+ render_clippath(gc.clippath, gc.clippath_trans);
+
+ // Transfer the hatch to the main image buffer
+ typedef agg::image_accessor_wrap<pixfmt,
+ agg::wrap_mode_repeat_auto_pow2,
+ agg::wrap_mode_repeat_auto_pow2> img_source_type;
+ typedef agg::span_pattern_rgba<img_source_type> span_gen_type;
+ agg::span_allocator<agg::rgba8> sa;
+ img_source_type img_src(hatch_img_pixf);
+ span_gen_type sg(img_src, 0, 0);
+ theRasterizer.add_path(path);
+ agg::render_scanlines_aa(theRasterizer, slineP8, rendererBase, sa, sg);
+ }
+
// Render stroke
if (gc.linewidth != 0.0) {
double linewidth = gc.linewidth;
Modified: trunk/matplotlib/src/_backend_agg.h
===================================================================
--- trunk/matplotlib/src/_backend_agg.h 2008-12-29 13:58:18 UTC (rev 6707)
+++ trunk/matplotlib/src/_backend_agg.h 2008-12-29 14:08:13 UTC (rev 6708)
@@ -60,7 +60,6 @@
typedef agg::scanline_bin scanline_bin;
typedef agg::amask_no_clip_gray8 alpha_mask_type;
-
typedef agg::renderer_base<agg::pixfmt_gray8> renderer_base_alpha_mask_type;
typedef agg::renderer_scanline_aa_solid<renderer_base_alpha_mask_type>
renderer_alpha_mask_type;
@@ -129,6 +128,8 @@
SNAP_TRUE
} snap;
+ Py::Object hatchpath;
+
protected:
agg::rgba get_color(const Py::Object& gc);
double points_to_pixels( const Py::Object& points);
@@ -139,6 +140,7 @@
void _set_clip_path( const Py::Object& gc);
void _set_antialiased( const Py::Object& gc);
void _set_snap( const Py::Object& gc);
+ void _set_hatch_path( const Py::Object& gc);
};
@@ -206,6 +208,12 @@
Py::Object lastclippath;
agg::trans_affine lastclippath_transform;
+ // HATCH_SIZE should be a power of 2, to take advantage of Agg's
+ // fast pattern rendering
+ static const size_t HATCH_SIZE = 128;
+ agg::int8u hatchBuffer[HATCH_SIZE * HATCH_SIZE * 4];
+ agg::rendering_buffer hatchRenderingBuffer;
+
const int debug;
protected:
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins