From: <md...@us...> - 2008-12-29 14:08:16
|
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. |