Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f96e11d

Browse files
committed
Add "draw_gouraud_triangles" (note the 's') backend method. Add initial support in Pdf backend (working in xpdf and evince, but not in acroread, strangely).
svn path=/trunk/matplotlib/; revision=7621
1 parent 670ec85 commit f96e11d

7 files changed

Lines changed: 182 additions & 42 deletions

File tree

lib/matplotlib/backend_bases.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,31 @@ def draw_gouraud_triangle(self, gc, points, colors, transform):
170170
"""
171171
Draw a Gouraud-shaded triangle.
172172
173-
EXPERIMENTAL
173+
*points* is a 3x2 array of (x, y) points for the triangle.
174+
175+
*colors* is a 3x4 array of RGBA colors for each point of the
176+
triangle.
177+
178+
*transform* is an affine transform to apply to the points.
174179
"""
175180
raise NotImplementedError
176181

182+
def draw_gouraud_triangles(self, gc, triangles_array, colors_array,
183+
transform):
184+
"""
185+
Draws a series of Gouraud triangles.
186+
187+
*points* is a Nx3x2 array of (x, y) points for the trianglex.
188+
189+
*colors* is a Nx3x4 array of RGBA colors for each point of the
190+
triangles.
191+
192+
*transform* is an affine transform to apply to the points.
193+
"""
194+
transform = transform.frozen()
195+
for tri, col in zip(triangles_array, colors_array):
196+
self.draw_gouraud_triangle(gc, tri, col, transform)
197+
177198
def _iter_collection_raw_paths(self, master_transform, paths,
178199
all_transforms):
179200
"""
@@ -410,7 +431,7 @@ def strip_math(self, s):
410431

411432
def start_rasterizing(self):
412433
"""
413-
Used in MixedModeRenderer. Switch to the raster renderer.
434+
Used in MixedModeRenderer. Switch to the raster renderer.
414435
"""
415436
pass
416437

@@ -425,7 +446,7 @@ def stop_rasterizing(self):
425446
def start_filter(self):
426447
"""
427448
Used in AggRenderer. Switch to a temporary renderer for image
428-
filtering effects.
449+
filtering effects.
429450
"""
430451
pass
431452

lib/matplotlib/backends/backend_agg.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ def _update_methods(self):
8080
self.draw_path_collection = self._renderer.draw_path_collection
8181
self.draw_quad_mesh = self._renderer.draw_quad_mesh
8282
self.draw_gouraud_triangle = self._renderer.draw_gouraud_triangle
83+
self.draw_gouraud_triangles = self._renderer.draw_gouraud_triangles
8384
self.draw_image = self._renderer.draw_image
8485
self.copy_from_bbox = self._renderer.copy_from_bbox
8586
self.tostring_rgba_minimized = self._renderer.tostring_rgba_minimized

lib/matplotlib/backends/backend_mixed.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ def __init__(self, figure, width, height, dpi, vector_renderer,
5858
finalize flipy get_canvas_width_height get_image_magnification
5959
get_texmanager get_text_width_height_descent new_gc open_group
6060
option_image_nocomposite points_to_pixels strip_math
61-
start_filter stop_filter
61+
start_filter stop_filter draw_gouraud_triangle
62+
draw_gouraud_triangles
6263
""".split()
6364
def _set_current_renderer(self, renderer):
6465
self._renderer = renderer

lib/matplotlib/backends/backend_pdf.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from cStringIO import StringIO
1818
from datetime import datetime
1919
from math import ceil, cos, floor, pi, sin
20+
import struct
2021
try:
2122
set
2223
except NameError:
@@ -268,7 +269,7 @@ def pdfRepr(self):
268269
gsave='q', grestore='Q',
269270
textpos='Td', selectfont='Tf', textmatrix='Tm',
270271
show='Tj', showkern='TJ',
271-
setlinewidth='w', clip='W')
272+
setlinewidth='w', clip='W', shading='sh')
272273

273274
Op = Bunch(**dict([(name, Operator(value))
274275
for name, value in _pdfops.items()]))
@@ -377,6 +378,7 @@ def __init__(self, filename):
377378
self.fontObject = self.reserveObject('fonts')
378379
self.alphaStateObject = self.reserveObject('extended graphics states')
379380
self.hatchObject = self.reserveObject('tiling patterns')
381+
self.gouraudObject = self.reserveObject('Gouraud triangles')
380382
self.XObjectObject = self.reserveObject('external objects')
381383
self.resourceObject = self.reserveObject('resources')
382384

@@ -403,6 +405,7 @@ def __init__(self, filename):
403405
self.nextAlphaState = 1
404406
self.hatchPatterns = {}
405407
self.nextHatch = 1
408+
self.gouraudTriangles = []
406409

407410
self.images = {}
408411
self.nextImage = 1
@@ -421,6 +424,7 @@ def __init__(self, filename):
421424
'XObject': self.XObjectObject,
422425
'ExtGState': self.alphaStateObject,
423426
'Pattern': self.hatchObject,
427+
'Shading': self.gouraudObject,
424428
'ProcSet': procsets }
425429
self.writeObject(self.resourceObject, resources)
426430

@@ -452,6 +456,7 @@ def close(self):
452456
dict([(val[0], val[1])
453457
for val in self.alphaStates.values()]))
454458
self.writeHatches()
459+
self.writeGouraudTriangles()
455460
xobjects = dict(self.images.values())
456461
for tup in self.markers.values():
457462
xobjects[tup[0]] = tup[1]
@@ -1050,6 +1055,44 @@ def writeHatches(self):
10501055
self.endStream()
10511056
self.writeObject(self.hatchObject, hatchDict)
10521057

1058+
def addGouraudTriangles(self, points, colors):
1059+
name = Name('GT%d' % len(self.gouraudTriangles))
1060+
self.gouraudTriangles.append((name, points, colors))
1061+
return name
1062+
1063+
def writeGouraudTriangles(self):
1064+
gouraudDict = dict()
1065+
for name, points, colors in self.gouraudTriangles:
1066+
ob = self.reserveObject('Gouraud triangle')
1067+
gouraudDict[name] = ob
1068+
shape = points.shape
1069+
flat_points = points.reshape((shape[0] * shape[1], 2))
1070+
points_min = npy.min(flat_points, axis=0) - (1 << 8)
1071+
points_max = npy.max(flat_points, axis=0) + (1 << 8)
1072+
factor = float(0xffffffff) / (points_max - points_min)
1073+
adjpoints = npy.array((points - points_min) * factor, dtype=npy.uint32)
1074+
adjcolors = npy.array(colors * 255.0, dtype=npy.uint8)
1075+
1076+
self.beginStream(
1077+
ob.id, None,
1078+
{ 'ShadingType': 4,
1079+
'BitsPerCoordinate': 32,
1080+
'BitsPerComponent': 8,
1081+
'BitsPerFlag': 8,
1082+
'ColorSpace': Name('DeviceRGB'),
1083+
'AntiAlias': 1,
1084+
'Decode': [points_min[0], points_max[0],
1085+
points_min[1], points_max[1],
1086+
0, 1, 0, 1, 0, 1]
1087+
})
1088+
1089+
for tpoints, tcolors in zip(adjpoints, adjcolors):
1090+
for p, c in zip(tpoints, tcolors):
1091+
values = [int(x) for x in [0] + list(p) + list(c[:3])]
1092+
self.write(struct.pack('>BLLBBB', *values))
1093+
self.endStream()
1094+
self.writeObject(self.gouraudObject, gouraudDict)
1095+
10531096
def imageObject(self, image):
10541097
"""Return name of an image XObject representing the given image."""
10551098

@@ -1326,6 +1369,18 @@ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None)
13261369
lastx, lasty = x, y
13271370
output(Op.grestore)
13281371

1372+
def draw_gouraud_triangle(self, gc, points, colors, trans):
1373+
self.draw_gouraud_triangles(gc, points.reshape((1, 3, 2)),
1374+
colors.reshape((1, 3, 4)), trans)
1375+
1376+
def draw_gouraud_triangles(self, gc, points, colors, trans):
1377+
shape = points.shape
1378+
points = points.reshape((shape[0] * shape[1], 2))
1379+
tpoints = trans.transform(points)
1380+
tpoints = tpoints.reshape(shape)
1381+
name = self.file.addGouraudTriangles(tpoints, colors)
1382+
self.file.output(name, Op.shading)
1383+
13291384
def _setup_textpos(self, x, y, descent, angle, oldx=0, oldy=0, olddescent=0, oldangle=0):
13301385
if angle == oldangle == 0:
13311386
self.file.output(x - oldx, (y + descent) - (oldy + olddescent), Op.textpos)

lib/matplotlib/collections.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,8 +1217,7 @@ def draw(self, renderer):
12171217
triangles, colors = self.convert_mesh_to_triangles(
12181218
self._meshWidth, self._meshHeight, coordinates)
12191219
check = {}
1220-
for tri, col in zip(triangles, colors):
1221-
renderer.draw_gouraud_triangle(gc, tri, col, transform.frozen())
1220+
renderer.draw_gouraud_triangles(gc, triangles, colors, transform.frozen())
12221221
else:
12231222
renderer.draw_quad_mesh(
12241223
gc, transform.frozen(), self._meshWidth, self._meshHeight,

src/_backend_agg.cpp

Lines changed: 92 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,28 +1455,58 @@ RendererAgg::draw_quad_mesh(const Py::Tuple& args) {
14551455
return Py::Object();
14561456
}
14571457

1458-
Py::Object
1459-
RendererAgg::draw_gouraud_triangle(const Py::Tuple& args) {
1460-
_VERBOSE("RendererAgg::draw_quad_mesh");
1461-
args.verify_length(4);
1458+
void
1459+
RendererAgg::_draw_gouraud_triangle(const GCAgg& gc,
1460+
const double* points, const double* colors, agg::trans_affine trans) {
14621461

14631462
typedef agg::rgba8 color_t;
14641463
typedef agg::span_gouraud_rgba<color_t> span_gen_t;
14651464
typedef agg::span_allocator<color_t> span_alloc_t;
14661465

1467-
//segments, trans, clipbox, colors, linewidths, antialiaseds
1468-
GCAgg gc(args[0], dpi);
1469-
Py::Object points_obj = args[1];
1470-
Py::Object colors_obj = args[2];
1471-
agg::trans_affine trans = py_to_agg_transformation_matrix(args[3].ptr());
1472-
14731466
theRasterizer.reset_clipping();
14741467
rendererBase.reset_clipping(true);
14751468
set_clipbox(gc.cliprect, theRasterizer);
14761469

14771470
trans *= agg::trans_affine_scaling(1.0, -1.0);
14781471
trans *= agg::trans_affine_translation(0.0, (double)height);
14791472

1473+
double tpoints[6];
1474+
1475+
for (int i = 0; i < 6; i += 2) {
1476+
tpoints[i] = points[i];
1477+
tpoints[i+1] = points[i+1];
1478+
trans.transform(&tpoints[i], &tpoints[i+1]);
1479+
}
1480+
1481+
span_alloc_t span_alloc;
1482+
span_gen_t span_gen;
1483+
1484+
span_gen.colors(
1485+
agg::rgba(colors[0], colors[1], colors[2], colors[3]),
1486+
agg::rgba(colors[4], colors[5], colors[6], colors[7]),
1487+
agg::rgba(colors[8], colors[9], colors[10], colors[11]));
1488+
span_gen.triangle(
1489+
tpoints[0], tpoints[1],
1490+
tpoints[2], tpoints[3],
1491+
tpoints[4], tpoints[5],
1492+
0.5);
1493+
1494+
theRasterizer.add_path(span_gen);
1495+
agg::render_scanlines_aa(
1496+
theRasterizer, slineP8, rendererBase, span_alloc, span_gen);
1497+
}
1498+
1499+
Py::Object
1500+
RendererAgg::draw_gouraud_triangle(const Py::Tuple& args) {
1501+
_VERBOSE("RendererAgg::draw_gouraud_triangle");
1502+
args.verify_length(4);
1503+
1504+
//segments, trans, clipbox, colors, linewidths, antialiaseds
1505+
GCAgg gc(args[0], dpi);
1506+
Py::Object points_obj = args[1];
1507+
Py::Object colors_obj = args[2];
1508+
agg::trans_affine trans = py_to_agg_transformation_matrix(args[3].ptr());
1509+
14801510
PyArrayObject* points = (PyArrayObject*)PyArray_ContiguousFromAny
14811511
(points_obj.ptr(), PyArray_DOUBLE, 2, 2);
14821512
if (!points ||
@@ -1490,32 +1520,57 @@ RendererAgg::draw_gouraud_triangle(const Py::Tuple& args) {
14901520
throw Py::ValueError("colors must be a 3x4 numpy array");
14911521

14921522
try {
1493-
double* opoints = (double*)PyArray_DATA(points);
1494-
double* c = (double*)PyArray_DATA(colors);
1495-
double tpoints[6];
1496-
1497-
for (int i = 0; i < 6; i += 2) {
1498-
tpoints[i] = opoints[i];
1499-
tpoints[i+1] = opoints[i+1];
1500-
trans.transform(&tpoints[i], &tpoints[i+1]);
1501-
}
1523+
_draw_gouraud_triangle(
1524+
gc, (double*)PyArray_DATA(points), (double*)PyArray_DATA(colors), trans);
1525+
} catch (...) {
1526+
Py_DECREF(points);
1527+
Py_DECREF(colors);
1528+
1529+
throw;
1530+
}
1531+
1532+
Py_DECREF(points);
1533+
Py_DECREF(colors);
1534+
1535+
return Py::Object();
1536+
}
15021537

1503-
span_alloc_t span_alloc;
1504-
span_gen_t span_gen;
1505-
1506-
span_gen.colors(
1507-
agg::rgba(c[0], c[1], c[2], c[3]),
1508-
agg::rgba(c[4], c[5], c[6], c[7]),
1509-
agg::rgba(c[8], c[9], c[10], c[11]));
1510-
span_gen.triangle(
1511-
tpoints[0], tpoints[1],
1512-
tpoints[2], tpoints[3],
1513-
tpoints[4], tpoints[5],
1514-
0.5);
1515-
1516-
theRasterizer.add_path(span_gen);
1517-
agg::render_scanlines_aa(
1518-
theRasterizer, slineP8, rendererBase, span_alloc, span_gen);
1538+
Py::Object
1539+
RendererAgg::draw_gouraud_triangles(const Py::Tuple& args) {
1540+
_VERBOSE("RendererAgg::draw_gouraud_triangles");
1541+
args.verify_length(4);
1542+
1543+
typedef agg::rgba8 color_t;
1544+
typedef agg::span_gouraud_rgba<color_t> span_gen_t;
1545+
typedef agg::span_allocator<color_t> span_alloc_t;
1546+
1547+
//segments, trans, clipbox, colors, linewidths, antialiaseds
1548+
GCAgg gc(args[0], dpi);
1549+
Py::Object points_obj = args[1];
1550+
Py::Object colors_obj = args[2];
1551+
agg::trans_affine trans = py_to_agg_transformation_matrix(args[3].ptr());
1552+
1553+
PyArrayObject* points = (PyArrayObject*)PyArray_ContiguousFromAny
1554+
(points_obj.ptr(), PyArray_DOUBLE, 3, 3);
1555+
if (!points ||
1556+
PyArray_DIM(points, 1) != 3 || PyArray_DIM(points, 2) != 2)
1557+
throw Py::ValueError("points must be a Nx3x2 numpy array");
1558+
1559+
PyArrayObject* colors = (PyArrayObject*)PyArray_ContiguousFromAny
1560+
(colors_obj.ptr(), PyArray_DOUBLE, 3, 3);
1561+
if (!colors ||
1562+
PyArray_DIM(colors, 1) != 3 || PyArray_DIM(colors, 2) != 4)
1563+
throw Py::ValueError("colors must be a Nx3x4 numpy array");
1564+
1565+
if (PyArray_DIM(points, 0) != PyArray_DIM(colors, 0)) {
1566+
throw Py::ValueError("points and colors arrays must be the same length");
1567+
}
1568+
1569+
try {
1570+
for (int i = 0; i < PyArray_DIM(points, 0); ++i) {
1571+
_draw_gouraud_triangle(
1572+
gc, (double*)PyArray_GETPTR1(points, i), (double*)PyArray_GETPTR1(colors, i), trans);
1573+
}
15191574
} catch (...) {
15201575
Py_DECREF(points);
15211576
Py_DECREF(colors);
@@ -1870,6 +1925,8 @@ void RendererAgg::init_type()
18701925
"draw_quad_mesh(gc, master_transform, meshWidth, meshHeight, coordinates, offsets, offsetTrans, facecolors, antialiaseds, showedges)\n");
18711926
add_varargs_method("draw_gouraud_triangle", &RendererAgg::draw_gouraud_triangle,
18721927
"draw_gouraud_triangle(gc, points, colors, master_transform)\n");
1928+
add_varargs_method("draw_gouraud_triangles", &RendererAgg::draw_gouraud_triangles,
1929+
"draw_gouraud_triangles(gc, points, colors, master_transform)\n");
18731930
add_varargs_method("draw_markers", &RendererAgg::draw_markers,
18741931
"draw_markers(gc, marker_path, marker_trans, path, rgbFace)\n");
18751932
add_varargs_method("draw_text_image", &RendererAgg::draw_text_image,

src/_backend_agg.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ class RendererAgg: public Py::PythonExtension<RendererAgg> {
165165
Py::Object draw_path_collection(const Py::Tuple & args);
166166
Py::Object draw_quad_mesh(const Py::Tuple& args);
167167
Py::Object draw_gouraud_triangle(const Py::Tuple& args);
168+
Py::Object draw_gouraud_triangles(const Py::Tuple& args);
168169

169170
Py::Object write_rgba(const Py::Tuple & args);
170171
Py::Object tostring_rgb(const Py::Tuple & args);
@@ -241,6 +242,11 @@ class RendererAgg: public Py::PythonExtension<RendererAgg> {
241242
const Py::SeqBase<Py::Object>& linestyles_obj,
242243
const Py::SeqBase<Py::Int>& antialiaseds);
243244

245+
void
246+
_draw_gouraud_triangle(
247+
const GCAgg& gc,
248+
const double* points, const double* colors, agg::trans_affine trans);
249+
244250
private:
245251
void create_alpha_buffers();
246252
};

0 commit comments

Comments
 (0)