|
From: <md...@us...> - 2007-09-18 16:21:40
|
Revision: 3855
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3855&view=rev
Author: mdboom
Date: 2007-09-18 09:21:37 -0700 (Tue, 18 Sep 2007)
Log Message:
-----------
More code using new transformation framework. Lots of dead code
removed from backend_agg.cpp/h
Modified Paths:
--------------
branches/transforms/lib/matplotlib/backend_bases.py
branches/transforms/lib/matplotlib/backends/backend_agg.py
branches/transforms/lib/matplotlib/lines.py
branches/transforms/lib/matplotlib/path.py
branches/transforms/lib/matplotlib/transforms.py
branches/transforms/lib/matplotlib/type1font.py
branches/transforms/src/_backend_agg.cpp
branches/transforms/src/_backend_agg.h
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-17 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-18 16:21:37 UTC (rev 3855)
@@ -39,8 +39,7 @@
def _get_cached_native_path(self, path):
native_path = self._native_paths.get(path)
if native_path is None:
- import matplotlib.patches
- print "CACHE MISS", path
+ # print "CACHE MISS", path
native_path = self.convert_to_native_path(path)
self._native_paths[path] = native_path
return native_path
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-17 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-18 16:21:37 UTC (rev 3855)
@@ -121,13 +121,9 @@
debug=False)
if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done',
'debug-annoying')
- # self.draw_polygon = self._renderer.draw_polygon
- self.draw_rectangle = self._renderer.draw_rectangle
- # MGDTODO -- remove these lines
- # self.draw_lines = self._renderer.draw_lines
- # self.draw_markers = self._renderer.draw_markers
- self.draw_image = self._renderer.draw_image
+ self.convert_to_native_path = self._renderer.convert_to_native_path
+ self.draw_image = self._renderer.draw_image
self.copy_from_bbox = self._renderer.copy_from_bbox
self.restore_region = self._renderer.restore_region
self.mathtext_parser = MathTextParser('Agg')
@@ -137,12 +133,9 @@
if __debug__: verbose.report('RendererAgg.__init__ done',
'debug-annoying')
- def convert_to_native_path(self, path):
- return self._renderer.convert_to_native_path(path.vertices, path.codes)
-
- def _draw_native_path(self, gc, native_path, transform, rgbFace):
- return self._renderer.draw_path(gc, native_path, transform.to_values(), rgbFace)
-
+ def _draw_native_path(self, gc, path, transform, rgbFace):
+ return self._renderer.draw_path(gc, path, transform.get_matrix(), rgbFace)
+
def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation):
"""
Draw an arc centered at x,y with width and height and angles
@@ -175,8 +168,8 @@
def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None):
return self._renderer.draw_markers(
gc,
- native_marker_path, marker_trans.to_values(),
- path.vertices, path.codes, trans.to_values(),
+ native_marker_path, marker_trans.get_matrix(),
+ path.vertices, path.codes, trans.get_matrix(),
rgbFace)
def draw_polygon(self, *args):
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py 2007-09-17 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/lines.py 2007-09-18 16:21:37 UTC (rev 3855)
@@ -712,6 +712,7 @@
def _draw_nothing(self, renderer, gc, path):
pass
+
def _draw_steps(self, renderer, gc, xt, yt):
# MGDTODO: This is a quirky one. The step-plotting part
# should probably be moved to where the path is generated
@@ -729,6 +730,7 @@
else:
renderer.draw_lines(gc, xt2, yt2)
+
def _draw_solid(self, renderer, gc, path):
gc.set_linestyle('solid')
renderer.draw_path(gc, path, self.get_transform())
@@ -753,8 +755,15 @@
def _draw_point(self, renderer, gc, path):
- self._draw_circle(renderer, gc, path, point = True)
+ w = renderer.points_to_pixels(self._markersize) * \
+ self._point_size_reduction * 0.5
+ rgbFace = self._get_rgb_face()
+ transform = Affine2D().scale(w)
+ renderer.draw_markers(
+ gc, Path.unit_circle(), transform, path, self.get_transform(),
+ rgbFace)
+
def _draw_pixel(self, renderer, gc, path):
rgbFace = self._get_rgb_face()
transform = Affine2D().translate(-0.5, -0.5)
@@ -762,12 +771,8 @@
path, self.get_transform(), rgbFace)
- def _draw_circle(self, renderer, gc, path, point=False):
- w = renderer.points_to_pixels(self._markersize)
- if point:
- w *= self._point_size_reduction
- w *= 0.5
-
+ def _draw_circle(self, renderer, gc, path):
+ w = renderer.points_to_pixels(self._markersize) * 0.5
rgbFace = self._get_rgb_face()
transform = Affine2D().scale(w, w)
renderer.draw_markers(
@@ -826,7 +831,8 @@
def _draw_thin_diamond(self, renderer, gc, path):
offset = renderer.points_to_pixels(self._markersize)
- transform = Affine2D().translate(0.5, 0.5).rotate_deg(45).scale(offset * 0.8, offset)
+ transform = Affine2D().translate(0.5, 0.5) \
+ .rotate_deg(45).scale(offset * 0.8, offset)
rgbFace = self._get_rgb_face()
renderer.draw_markers(gc, Path.unit_rectangle(), transform,
path, self.get_transform(), rgbFace)
@@ -840,7 +846,7 @@
path, self.get_transform(), rgbFace)
- def _draw_hexagon1(self, renderer, gc, path, point=False):
+ def _draw_hexagon1(self, renderer, gc, path):
offset = 0.5 * renderer.points_to_pixels(self._markersize)
transform = Affine2D().scale(offset)
rgbFace = self._get_rgb_face()
@@ -848,50 +854,44 @@
path, self.get_transform(), rgbFace)
- def _draw_hexagon2(self, renderer, gc, xt, yt):
+ def _draw_hexagon2(self, renderer, gc, path):
offset = 0.5 * renderer.points_to_pixels(self._markersize)
transform = Affine2D().scale(offset).rotate_deg(30)
rgbFace = self._get_rgb_face()
renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform,
path, self.get_transform(), rgbFace)
-
- def _draw_vline(self, renderer, gc, xt, yt):
+
+ _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]], closed=False)
+ def _draw_vline(self, renderer, gc, path):
offset = 0.5*renderer.points_to_pixels(self._markersize)
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, -offset)
- path.line_to(0, offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y-offset, x, y+offset)
+ transform = Affine2D().scale(offset)
+ renderer.draw_markers(gc, self._line_marker_path, transform,
+ path, self.get_transform())
- def _draw_hline(self, renderer, gc, xt, yt):
+ def _draw_hline(self, renderer, gc, path):
offset = 0.5*renderer.points_to_pixels(self._markersize)
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset, 0)
- path.line_to(offset, 0)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y, x+offset, y)
+ transform = Affine2D().scale(offset).rotate_deg(90)
+ renderer.draw_markers(gc, self._line_marker_path, transform,
+ path, self.get_transform())
+
_tickhoriz_path = Path([[0.0, 0.5], [1.0, 0.5]])
def _draw_tickleft(self, renderer, gc, path):
offset = renderer.points_to_pixels(self._markersize)
- marker_transform = Affine2D().scale(offset, 1.0)
+ marker_transform = Affine2D().scale(-offset, 1.0)
renderer.draw_markers(gc, self._tickhoriz_path, marker_transform,
path, self.get_transform())
+
def _draw_tickright(self, renderer, gc, path):
offset = renderer.points_to_pixels(self._markersize)
- marker_transform = Affine2D().scale(-offset, 1.0)
+ marker_transform = Affine2D().scale(offset, 1.0)
renderer.draw_markers(gc, self._tickhoriz_path, marker_transform,
path, self.get_transform())
+
_tickvert_path = Path([[-0.5, 0.0], [-0.5, 1.0]])
def _draw_tickup(self, renderer, gc, path):
offset = renderer.points_to_pixels(self._markersize)
@@ -899,174 +899,99 @@
renderer.draw_markers(gc, self._tickvert_path, marker_transform,
path, self.get_transform())
+
def _draw_tickdown(self, renderer, gc, path):
offset = renderer.points_to_pixels(self._markersize)
marker_transform = Affine2D().scale(1.0, -offset)
renderer.draw_markers(gc, self._tickvert_path, marker_transform,
path, self.get_transform())
- def _draw_plus(self, renderer, gc, xt, yt):
+
+ _plus_path = Path([[-1.0, 0.0], [1.0, 0.0],
+ [0.0, -1.0], [0.0, 1.0]],
+ [Path.MOVETO, Path.LINETO,
+ Path.MOVETO, Path.LINETO])
+ def _draw_plus(self, renderer, gc, path):
offset = 0.5*renderer.points_to_pixels(self._markersize)
- if self._newstyle:
+ transform = Affine2D().scale(offset)
+ renderer.draw_markers(gc, self._plus_path, transform,
+ path, self.get_transform())
- path = agg.path_storage()
- path.move_to(-offset, 0)
- path.line_to( offset, 0)
- path.move_to( 0, -offset)
- path.line_to( 0, offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y, x+offset, y)
- renderer.draw_line(gc, x, y-offset, x, y+offset)
- def _draw_tri_down(self, renderer, gc, xt, yt):
+ _tri_path = Path([[0.0, 0.0], [0.0, -1.0],
+ [0.0, 0.0], [0.8, 0.5],
+ [0.0, 0.0], [-0.8, 0.5]],
+ [Path.MOVETO, Path.LINETO,
+ Path.MOVETO, Path.LINETO,
+ Path.MOVETO, Path.LINETO])
+ def _draw_tri_down(self, renderer, gc, path):
offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = offset*0.8
- offset2 = offset*0.5
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, 0)
- path.line_to(0, -offset)
- path.move_to(0, 0)
- path.line_to(offset1, offset2)
- path.move_to(0, 0)
- path.line_to(-offset1, offset2)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y, x, y-offset)
- renderer.draw_line(gc, x, y, x+offset1, y+offset2)
- renderer.draw_line(gc, x, y, x-offset1, y+offset2)
+ transform = Affine2D().scale(offset)
+ renderer.draw_markers(gc, self._tri_path, transform,
+ path, self.get_transform())
- def _draw_tri_up(self, renderer, gc, xt, yt):
+
+ def _draw_tri_up(self, renderer, gc, path):
offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = offset*0.8
- offset2 = offset*0.5
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, 0)
- path.line_to(0, offset)
- path.move_to(0, 0)
- path.line_to(offset1, -offset2)
- path.move_to(0, 0)
- path.line_to(-offset1, -offset2)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y, x, y+offset)
- renderer.draw_line(gc, x, y, x+offset1, y-offset2)
- renderer.draw_line(gc, x, y, x-offset1, y-offset2)
+ transform = Affine2D().scale(offset).rotate_deg(180)
+ renderer.draw_markers(gc, self._tri_path, transform,
+ path, self.get_transform())
- def _draw_tri_left(self, renderer, gc, xt, yt):
- offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = offset*0.8
- offset2 = offset*0.5
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, 0)
- path.line_to(-offset, 0)
- path.move_to(0, 0)
- path.line_to(offset2, offset1)
- path.move_to(0, 0)
- path.line_to(offset2, -offset1)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y, x-offset, y)
- renderer.draw_line(gc, x, y, x+offset2, y+offset1)
- renderer.draw_line(gc, x, y, x+offset2, y-offset1)
+
+ def _draw_tri_left(self, renderer, gc, path):
+ offset = 0.5*renderer.points_to_pixels(self._markersize)
+ transform = Affine2D().scale(offset).rotate_deg(90)
+ renderer.draw_markers(gc, self._tri_path, transform,
+ path, self.get_transform())
- def _draw_tri_right(self, renderer, gc, xt, yt):
- offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = offset*0.8
- offset2 = offset*0.5
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, 0)
- path.line_to(offset, 0)
- path.move_to(0, 0)
- path.line_to(-offset2, offset1)
- path.move_to(0, 0)
- path.line_to(-offset2, -offset1)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y, x+offset, y)
- renderer.draw_line(gc, x, y, x-offset2, y+offset1)
- renderer.draw_line(gc, x, y, x-offset2, y-offset1)
+
+ def _draw_tri_right(self, renderer, gc, path):
+ offset = 0.5*renderer.points_to_pixels(self._markersize)
+ transform = Affine2D().scale(offset).rotate_deg(270)
+ renderer.draw_markers(gc, self._tri_path, transform,
+ path, self.get_transform())
- def _draw_caretdown(self, renderer, gc, xt, yt):
+
+ _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]], closed=False)
+ def _draw_caretdown(self, renderer, gc, path):
offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = 1.5*offset
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset, offset1)
- path.line_to(0, 0)
- path.line_to(+offset, offset1)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y+offset1, x, y)
- renderer.draw_line(gc, x, y, x+offset, y+offset1)
+ transform = Affine2D().scale(offset)
+ renderer.draw_markers(gc, self._caret_path, transform,
+ path, self.get_transform())
- def _draw_caretup(self, renderer, gc, xt, yt):
+
+ def _draw_caretup(self, renderer, gc, path):
offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = 1.5*offset
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset, -offset1)
- path.line_to(0, 0)
- path.line_to(+offset, -offset1)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y-offset1, x, y)
- renderer.draw_line(gc, x, y, x+offset, y-offset1)
+ transform = Affine2D().scale(offset).rotate_deg(180)
+ renderer.draw_markers(gc, self._caret_path, transform,
+ path, self.get_transform())
- def _draw_caretleft(self, renderer, gc, xt, yt):
+
+ def _draw_caretleft(self, renderer, gc, path):
offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = 1.5*offset
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(offset1, -offset)
- path.line_to(0, 0)
- path.line_to(offset1, offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x+offset1, y-offset, x, y)
- renderer.draw_line(gc, x, y, x+offset1, y+offset)
+ transform = Affine2D().scale(offset).rotate_deg(90)
+ renderer.draw_markers(gc, self._caret_path, transform,
+ path, self.get_transform())
- def _draw_caretright(self, renderer, gc, xt, yt):
+
+ def _draw_caretright(self, renderer, gc, path):
offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = 1.5*offset
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset1, -offset)
- path.line_to(0, 0)
- path.line_to(-offset1, offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset1, y-offset, x, y)
- renderer.draw_line(gc, x, y, x-offset1, y+offset)
+ transform = Affine2D().scale(offset).rotate_deg(270)
+ renderer.draw_markers(gc, self._caret_path, transform,
+ path, self.get_transform())
+
+ _x_path = Path([[-1.0, -1.0], [1.0, 1.0],
+ [-1.0, 1.0], [1.0, -1.0]],
+ [Path.MOVETO, Path.LINETO,
+ Path.MOVETO, Path.LINETO])
def _draw_x(self, renderer, gc, xt, yt):
offset = 0.5*renderer.points_to_pixels(self._markersize)
+ transform = Affine2D().scale(offset)
+ renderer.draw_markers(gc, self._x_path, transform,
+ path, self.get_transform())
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset, -offset)
- path.line_to(offset, offset)
- path.move_to(-offset, offset)
- path.line_to(offset, -offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y-offset, x+offset, y+offset)
- renderer.draw_line(gc, x-offset, y+offset, x+offset, y-offset)
-
+
def update_from(self, other):
'copy properties from other to self'
Artist.update_from(self, other)
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py 2007-09-17 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/path.py 2007-09-18 16:21:37 UTC (rev 3855)
@@ -50,6 +50,9 @@
i += NUM_VERTICES[code]
assert i == len(self.vertices)
+ def __repr__(self):
+ return "Path(%s, %s)" % (self.vertices, self.codes)
+
def _get_codes(self):
return self._codes
codes = property(_get_codes)
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py 2007-09-17 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/transforms.py 2007-09-18 16:21:37 UTC (rev 3855)
@@ -88,11 +88,13 @@
intervaly = property(_get_intervaly)
def _get_width(self):
- return self.xmax - self.xmin
+ points = self.get_points()
+ return points[1, 0] - points[0, 0]
width = property(_get_width)
def _get_height(self):
- return self.ymax - self.ymin
+ points = self.get_points()
+ return points[1, 1] - points[0, 1]
height = property(_get_height)
def _get_bounds(self):
Modified: branches/transforms/lib/matplotlib/type1font.py
===================================================================
--- branches/transforms/lib/matplotlib/type1font.py 2007-09-17 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/type1font.py 2007-09-18 16:21:37 UTC (rev 3855)
@@ -1,15 +1,15 @@
"""
A class representing a Type 1 font.
-This version merely allows reading in pfa and pfb files, stores the
-data in pfa format, and allows reading the parts of the data in a
-format suitable for embedding in pdf files. A more complete class
-might support subsetting.
+This version merely reads pfa and pfb files and splits them for
+embedding in pdf files. There is no support yet for subsetting or
+anything like that.
-Usage: font = Type1Font(filename)
- somefile.write(font.data) # writes out font in pfa format
- len1, len2, len3 = font.lengths() # needed for pdf embedding
+Usage (subject to change):
+ font = Type1Font(filename)
+ clear_part, encrypted_part, finale = font.parts
+
Source: Adobe Technical Note #5040, Supporting Downloadable PostScript
Language Fonts.
@@ -32,8 +32,7 @@
def _read(self, file):
rawdata = file.read()
if not rawdata.startswith(chr(128)):
- self.data = rawdata
- return
+ return rawdata
data = ''
while len(rawdata) > 0:
@@ -101,4 +100,6 @@
if __name__ == '__main__':
import sys
font = Type1Font(sys.argv[1])
- sys.stdout.write(font.data)
+ parts = font.parts
+ print len(parts[0]), len(parts[1]), len(parts[2])
+
Modified: branches/transforms/src/_backend_agg.cpp
===================================================================
--- branches/transforms/src/_backend_agg.cpp 2007-09-17 13:41:38 UTC (rev 3854)
+++ branches/transforms/src/_backend_agg.cpp 2007-09-18 16:21:37 UTC (rev 3855)
@@ -10,7 +10,6 @@
#include <time.h>
#include <algorithm>
-
#include "agg_conv_transform.h"
#include "agg_conv_curve.h"
#include "agg_scanline_storage_aa.h"
@@ -43,28 +42,48 @@
#define M_PI_2 1.57079632679489661923
#endif
-agg::trans_affine py_sequence_to_agg_transformation_matrix(const Py::Object& obj) {
- Py::SeqBase<Py::Float> seq;
+/** A helper function to convert from a Numpy affine transformation matrix
+ * to an agg::trans_affine.
+ */
+agg::trans_affine py_to_agg_transformation_matrix(const Py::Object& obj) {
+ PyArrayObject* matrix = NULL;
+
+ double a = 1.0, b = 0.0, c = 0.0, d = 1.0, e = 0.0, f = 0.0;
+
try {
- seq = obj;
- } catch(...) {
- throw Py::ValueError("Transformation matrix must be given as a 6-element list.");
- }
+ matrix = (PyArrayObject*) PyArray_ContiguousFromObject(obj.ptr(), PyArray_DOUBLE, 2, 2);
+ if (!matrix || matrix->nd != 2 || matrix->dimensions[0] != 3 || matrix->dimensions[1] != 3) {
+ throw Py::ValueError("Invalid affine transformation matrix.");
+ }
- if (seq.size() != 6) {
- throw Py::ValueError("Transformation matrix must be given as a 6-element list.");
+ size_t stride0 = matrix->strides[0];
+ size_t stride1 = matrix->strides[1];
+ char* row0 = matrix->data;
+ char* row1 = row0 + stride0;
+
+ a = *(double*)(row0);
+ row0 += stride1;
+ c = *(double*)(row0);
+ row0 += stride1;
+ e = *(double*)(row0);
+
+ b = *(double*)(row1);
+ row1 += stride1;
+ d = *(double*)(row1);
+ row1 += stride1;
+ f = *(double*)(row1);
+ } catch (...) {
+ Py_XDECREF(matrix);
}
- return agg::trans_affine
- (Py::Float(seq[0]),
- Py::Float(seq[1]),
- Py::Float(seq[2]),
- Py::Float(seq[3]),
- Py::Float(seq[4]),
- Py::Float(seq[5]));
+ Py_XDECREF(matrix);
+
+ return agg::trans_affine(a, b, c, d, e, f);
}
-// MGDTODO: Implement this as a nice iterator
+/** Helper function to get the next vertex in a Numpy array of vertices.
+ * Will generally be used through the GET_NEXT_VERTEX macro.
+ */
inline void get_next_vertex(const char* & vertex_i, const char* vertex_end,
double& x, double& y,
size_t next_vertex_stride,
@@ -78,12 +97,18 @@
#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride)
+Py::Object BufferRegion::to_string(const Py::Tuple &args) {
+
+ // owned=true to prevent memory leak
+ return Py::String(PyString_FromStringAndSize((const char*)aggbuf.data,aggbuf.height*aggbuf.stride), true);
+}
+
+
GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) :
dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0),
cliprect(NULL), clippath(NULL),
Ndash(0), dashOffset(0.0), dasha(NULL)
{
-
_VERBOSE("GCAgg::GCAgg");
linewidth = points_to_pixels ( gc.getAttr("_linewidth") ) ;
alpha = Py::Float( gc.getAttr("_alpha") );
@@ -100,7 +125,6 @@
GCAgg::_set_antialiased(const Py::Object& gc) {
_VERBOSE("GCAgg::antialiased");
isaa = Py::Int( gc.getAttr( "_antialiased") );
-
}
agg::rgba
@@ -123,13 +147,12 @@
return p * dpi/72.0;
}
-
void
GCAgg::_set_linecap(const Py::Object& gc) {
_VERBOSE("GCAgg::_set_linecap");
std::string capstyle = Py::String( gc.getAttr( "_capstyle" ) );
-
+
if (capstyle=="butt")
cap = agg::butt_cap;
else if (capstyle=="round")
@@ -138,7 +161,6 @@
cap = agg::square_cap;
else
throw Py::ValueError(Printf("GC _capstyle attribute must be one of butt, round, projecting; found %s", capstyle.c_str()).str());
-
}
void
@@ -155,7 +177,6 @@
join = agg::bevel_join;
else
throw Py::ValueError(Printf("GC _joinstyle attribute must be one of butt, round, projecting; found %s", joinstyle.c_str()).str());
-
}
void
@@ -193,7 +214,7 @@
}
}
-
+// MGDTODO: Convert directly from Bbox object (numpy)
void
GCAgg::_set_clip_rectangle( const Py::Object& gc) {
//set the clip rectangle from the gc
@@ -204,7 +225,7 @@
cliprect = NULL;
Py::Object o ( gc.getAttr( "_cliprect" ) );
- if (o.ptr()==Py_None) {
+ if (o.ptr() == Py_None) {
return;
}
@@ -229,38 +250,18 @@
_VERBOSE("GCAgg::_set_clip_path");
- delete clippath;
+ Py_XINCREF(clippath);
clippath = NULL;
- Py::Object o = gc.getAttr( "_clippath" );
+ Py::Object o = gc.getAttr("_clippath");
if (o.ptr()==Py_None) {
return;
}
- agg::path_storage *tmppath;
- swig_type_info * descr = SWIG_TypeQuery("agg::path_storage *");
- assert(descr);
- if (SWIG_ConvertPtr(o.ptr(),(void **)(&tmppath), descr, 0) == -1) {
- throw Py::TypeError("Could not convert gc path_storage");
- }
-
- tmppath->rewind(0);
- clippath = new agg::path_storage();
- clippath->copy_from(*tmppath);
- clippath->rewind(0);
- tmppath->rewind(0);
+ clippath = new PathAgg(o);
}
-Py::Object BufferRegion::to_string(const Py::Tuple &args) {
-
- // owned=true to prevent memory leak
- return Py::String(PyString_FromStringAndSize((const char*)aggbuf.data,aggbuf.height*aggbuf.stride), true);
-}
-
-
-
-
const size_t
RendererAgg::PIXELS_PER_INCH(96);
@@ -311,19 +312,14 @@
void
-RendererAgg::set_clipbox_rasterizer( double *cliprect) {
+RendererAgg::set_clipbox_rasterizer(double *cliprect) {
//set the clip rectangle from the gc
_VERBOSE("RendererAgg::set_clipbox_rasterizer");
-
theRasterizer->reset_clipping();
rendererBase->reset_clipping(true);
- //if (cliprect==NULL) {
- // theRasterizer->reset_clipping();
- // rendererBase->reset_clipping(true);
- //}
if (cliprect!=NULL) {
double l = cliprect[0] ;
@@ -355,273 +351,10 @@
}
-// MGDTODO: Remove this method (it has been conglomerated into draw_path
-template <class VS>
-void
-RendererAgg::_fill_and_stroke(VS& path,
- const GCAgg& gc,
- const facepair_t& face,
- bool curvy) {
- typedef agg::conv_curve<VS> curve_t;
-
- //bool isclippath(gc.clippath!=NULL);
- //if (isclippath) _process_alpha_mask(gc);
-
- if (face.first) {
- rendererAA->color(face.second);
- if (curvy) {
- curve_t curve(path);
- theRasterizer->add_path(curve);
- }
- else
- theRasterizer->add_path(path);
-
- /*
- if (isclippath) {
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- pixfmt_amask_type pfa(*pixFmt, *alphaMask);
- amask_ren_type r(pfa);
- typedef agg::renderer_scanline_aa_solid<amask_ren_type> renderer_type;
- renderer_type ren(r);
- ren.color(gc.color);
- //std::cout << "render clippath" << std::endl;
-
- agg::render_scanlines(*theRasterizer, *slineP8, ren);
- }
- else {
- rendererAA->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
- }
- */
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
- }
-
- //now stroke the edge
- if (gc.linewidth) {
- if (curvy) {
- curve_t curve(path);
- agg::conv_stroke<curve_t> stroke(curve);
- stroke.width(gc.linewidth);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- theRasterizer->add_path(stroke);
- }
- else {
- agg::conv_stroke<VS> stroke(path);
- stroke.width(gc.linewidth);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- theRasterizer->add_path(stroke);
- }
-
-
- /*
- if ( gc.isaa ) {
- if (isclippath) {
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- pixfmt_amask_type pfa(*pixFmt, *alphaMask);
- amask_ren_type r(pfa);
- typedef agg::renderer_scanline_aa_solid<amask_ren_type> renderer_type;
- renderer_type ren(r);
- ren.color(gc.color);
- //std::cout << "render clippath" << std::endl;
-
- agg::render_scanlines(*theRasterizer, *slineP8, ren);
- }
- else {
- rendererAA->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
- }
- }
- else {
- if (isclippath) {
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- pixfmt_amask_type pfa(*pixFmt, *alphaMask);
- amask_ren_type r(pfa);
- typedef agg::renderer_scanline_bin_solid<amask_ren_type> renderer_type;
- renderer_type ren(r);
- ren.color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, ren);
- }
- else{
- rendererBin->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
- }
- }
-
- */
-
- if ( gc.isaa ) {
- rendererAA->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
- }
- else {
- rendererBin->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
- }
- }
-
-
-}
-
-Py::Object
-RendererAgg::draw_rectangle(const Py::Tuple & args) {
- _VERBOSE("RendererAgg::draw_rectangle");
- args.verify_length(6);
-
-
- GCAgg gc = GCAgg(args[0], dpi);
- facepair_t face = _get_rgba_face(args[1], gc.alpha);
-
-
- double l = Py::Float( args[2] );
- double b = Py::Float( args[3] );
- double w = Py::Float( args[4] );
- double h = Py::Float( args[5] );
-
- b = height - (b+h);
- double r = l + w;
- double t = b + h;
-
- //snapto pixel centers
- l = (int)l + 0.5;
- b = (int)b + 0.5;
- r = (int)r + 0.5;
- t = (int)t + 0.5;
-
-
- set_clipbox_rasterizer(gc.cliprect);
-
- agg::path_storage path;
-
-
- path.move_to(l, t);
- path.line_to(r, t);
- path.line_to(r, b);
- path.line_to(l, b);
- path.close_polygon();
-
- _fill_and_stroke(path, gc, face, false);
-
- return Py::Object();
-
-}
-
-Py::Object
-RendererAgg::draw_ellipse(const Py::Tuple& args) {
- _VERBOSE("RendererAgg::draw_ellipse");
- args.verify_length(7);
-
- GCAgg gc = GCAgg(args[0], dpi);
- facepair_t face = _get_rgba_face(args[1], gc.alpha);
-
- double x = Py::Float( args[2] );
- double y = Py::Float( args[3] );
- double w = Py::Float( args[4] );
- double h = Py::Float( args[5] );
- double rot = Py::Float( args[6] );
-
- double r; // rot in radians
-
- set_clipbox_rasterizer(gc.cliprect);
-
- // Approximate the ellipse with 4 bezier paths
- agg::path_storage path;
- if (rot == 0.0) // simple case
- {
- path.move_to(x, height-(y+h));
- path.arc_to(w, h, 0.0, false, true, x+w, height-y);
- path.arc_to(w, h, 0.0, false, true, x, height-(y-h));
- path.arc_to(w, h, 0.0, false, true, x-w, height-y);
- path.arc_to(w, h, 0.0, false, true, x, height-(y+h));
- path.close_polygon();
- }
- else // rotate by hand :(
- {
- // deg to rad
- r = rot * (M_PI/180.0);
- path.move_to( x+(cos(r)*w), height-(y+(sin(r)*w)));
- path.arc_to(w, h, -r, false, true, x+(cos(r+M_PI_2*3)*h), height-(y+(sin(r+M_PI_2*3)*h)));
- path.arc_to(w, h, -r, false, true, x+(cos(r+M_PI)*w), height-(y+(sin(r+M_PI)*w)));
- path.arc_to(w, h, -r, false, true, x+(cos(r+M_PI_2)*h), height-(y+(sin(r+M_PI_2)*h)));
- path.arc_to(w, h, -r, false, true, x+(cos(r)*w), height-(y+(sin(r)*w)));
- path.close_polygon();
- }
-
- _fill_and_stroke(path, gc, face);
- return Py::Object();
-
-}
-
-Py::Object
-RendererAgg::draw_polygon(const Py::Tuple& args) {
- _VERBOSE("RendererAgg::draw_polygon");
-
- args.verify_length(3);
-
- GCAgg gc = GCAgg(args[0], dpi);
- facepair_t face = _get_rgba_face(args[1], gc.alpha);
-
- Py::SeqBase<Py::Object> points( args[2] );
-
- set_clipbox_rasterizer(gc.cliprect);
-
- size_t Npoints = points.length();
- if (Npoints<=0)
- return Py::Object();
-
-
- // dump the x.y vertices into a double array for faster look ahead
- // and behind access
- double *xs = new double[Npoints];
- double *ys = new double[Npoints];
-
- for (size_t i=0; i<Npoints; i++) {
- Py::SeqBase<Py::Object> xy(points[i]);
- xy = Py::Tuple(points[i]);
- xs[i] = Py::Float(xy[0]);
- ys[i] = Py::Float(xy[1]);
- ys[i] = height - ys[i];
- }
-
-
-
- agg::path_storage path;
- for (size_t j=0; j<Npoints; j++) {
-
- double x = xs[j];
- double y = ys[j];
-
- //snapto pixel centers
- x = (int)x + 0.5;
- y = (int)y + 0.5;
-
- if (j==0) path.move_to(x,y);
- else path.line_to(x,y);
- }
- path.close_polygon();
-
- _fill_and_stroke(path, gc, face, false);
-
- delete [] xs;
- delete [] ys;
-
- _VERBOSE("RendererAgg::draw_polygon DONE");
- return Py::Object();
-
-}
-
-
-
SnapData
SafeSnap::snap (const float& x, const float& y) {
xsnap = (int)x + 0.5;
ysnap = (int)y + 0.5;
-
-
if ( first || ( (xsnap!=lastxsnap) || (ysnap!=lastysnap) ) ) {
lastxsnap = xsnap;
@@ -690,9 +423,6 @@
rb.copy_from(*renderingBuffer, &r, -r.x1, -r.y1);
BufferRegion* reg = new BufferRegion(buf, r, true);
return Py::asObject(reg);
-
-
-
}
Py::Object
@@ -715,25 +445,20 @@
rendererBase->copy_from(rbuf, 0, region->rect.x1, region->rect.y1);
return Py::Object();
-
-
-
}
-
+/**
+ * Helper function to convert a Python Bbox object to an agg rectangle
+ */
template<class T>
agg::rect_base<T>
RendererAgg::bbox_to_rect(const Py::Object& o) {
//return the agg::rect for bbox, flipping y
PyArrayObject *bbox = (PyArrayObject *) PyArray_ContiguousFromObject(o.ptr(), PyArray_DOUBLE, 2, 2);
- if (!bbox)
+ if (!bbox || bbox->nd != 2 bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2)
throw Py::TypeError
("Expected a Bbox object.");
-
- if (bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2)
- throw Py::TypeError
- ("Expected a Bbox object.");
double l = bbox->data[0];
double b = bbox->data[1];
@@ -805,469 +530,8 @@
return numIntersect;
}
-void RendererAgg::DrawQuadMesh(int meshWidth, int meshHeight, const agg::rgba8 colorArray[], const double xCoords[], const double yCoords[])
-{
- /* draw each quadrilateral */
- // agg::renderer_primitives<agg::renderer_base<agg::pixfmt_rgba32> > lineRen(*rendererBase);
- int i = 0;
- int j = 0;
- int k = 0;
- double xs[4];
- double ys[4];
- int col[4];
- int numCol;
- double ymin;
- int firstRow;
- double ymax;
- int lastRow;
- for(i=0; i < meshHeight; i++)
- {
- for(j=0; j < meshWidth; j++)
- {
- //currTime = clock();
- xs[0] = xCoords[(i * (meshWidth + 1)) + j];
- ys[0] = yCoords[(i * (meshWidth + 1)) + j];
- xs[1] = xCoords[(i * (meshWidth + 1)) + j+1];
- ys[1] = yCoords[(i * (meshWidth + 1)) + j+1];
- xs[3] = xCoords[((i+1) * (meshWidth + 1)) + j];
- ys[3] = yCoords[((i+1) * (meshWidth + 1)) + j];
- xs[2] = xCoords[((i+1) * (meshWidth + 1)) + j+1];
- ys[2] = yCoords[((i+1) * (meshWidth + 1)) + j+1];
- ymin = std::min(std::min(std::min(ys[0], ys[1]), ys[2]), ys[3]);
- ymax = std::max(std::max(std::max(ys[0], ys[1]), ys[2]), ys[3]);
- firstRow = (int)(ymin);
- lastRow = (int)(ymax);
- //timer1 += (clock() - currTime);
- //currTime = clock();
- //timer2 += (clock() - currTime);
- //currTime = clock();
- for(k = firstRow; k <= lastRow; k++)
- {
- numCol = inPolygon(k, xs, ys, col);
- if (numCol >= 2) rendererBase->copy_hline(col[0], k, col[1] - 1, colorArray[(i * meshWidth) + j]);
- if (numCol == 4) rendererBase->copy_hline(col[2], k, col[3] - 1, colorArray[(i * meshWidth) + j]);
- }
- }
- }
- return;
-}
-void RendererAgg::DrawQuadMeshEdges(int meshWidth, int meshHeight, const agg::rgba8 colorArray[], const double xCoords[], const double yCoords[])
-{
- int i, j;
- agg::renderer_primitives<agg::renderer_base<agg::pixfmt_rgba32> > lineRen(*rendererBase);
- agg::rgba8 lc(0, 0, 0, 32);
- lineRen.line_color(lc);
- /* show the vertical edges */
- for(i=0; i <= meshWidth; i++)
- {
- lineRen.move_to((int)(256.0 * (xCoords[i])), (int)(256.0 * (yCoords[i])));
- for(j=1; j <= meshHeight; j++)
- lineRen.line_to((int)(256.0 *(xCoords[(j * (meshWidth + 1))+i])), (int)(256.0 * (yCoords[(j * (meshWidth + 1))+i])));
- }
- /* show the horizontal edges */
- for(i=0; i <= meshHeight; i++)
- {
- lineRen.move_to((int)(256.0 * (xCoords[i * (meshWidth + 1)])), (int)(256.0 * (yCoords[i * (meshWidth + 1)])));
- for(j=1; j <= meshWidth; j++)
- lineRen.line_to((int)(256.0 * (xCoords[(i * (meshWidth + 1))+j])), (int)(256.0 * (yCoords[(i * (meshWidth + 1))+j])));
- }
-}
-
-
-
Py::Object
-RendererAgg::draw_lines(const Py::Tuple& args) {
-
- _VERBOSE("RendererAgg::draw_lines");
- args.verify_length(4);
-
- Py::Object xo = args[1];
- Py::Object yo = args[2];
-
- PyArrayObject *xa = (PyArrayObject *) PyArray_ContiguousFromObject(xo.ptr(), PyArray_DOUBLE, 1, 1);
-
- if (xa==NULL)
- throw Py::TypeError("RendererAgg::draw_lines expected numerix array");
-
-
- PyArrayObject *ya = (PyArrayObject *) PyArray_ContiguousFromObject(yo.ptr(), PyArray_DOUBLE, 1, 1);
-
- if (ya==NULL)
- throw Py::TypeError("RendererAgg::draw_lines expected numerix array");
-
-
- size_t Nx = xa->dimensions[0];
- size_t Ny = ya->dimensions[0];
-
- if (Nx!=Ny)
- throw Py::ValueError(Printf("x and y must be equal length arrays; found %d and %d", Nx, Ny).str());
-
- // call gc with snapto==True if line len is 2 to fix grid line
- // problem
- bool snapto = false;
- if (Nx==2) {
- // disable subpiel rendering for len(2) horizontal or vertical
- // lines
- double x0 = *(double *)(xa->data + 0*xa->strides[0]);
- double x1 = *(double *)(xa->data + 1*xa->strides[0]);
- double y0 = *(double *)(ya->data + 0*ya->strides[0]);
- double y1 = *(double *)(ya->data + 1*ya->strides[0]);
- snapto = (x0==x1) || (y0==y1);
-
- }
- GCAgg gc = GCAgg(args[0], dpi, snapto);
-
- set_clipbox_rasterizer(gc.cliprect);
- //path_t transpath(path, xytrans);
- _process_alpha_mask(gc);
-
- agg::trans_affine xytrans = py_sequence_to_agg_transformation_matrix(args[3]);
-
- agg::path_storage path;
-
- // MGDTODO
- bool needNonlinear = false;
- // mpltransform->need_nonlinear_api();
-
- double thisx(0.0), thisy(0.0);
- double origdx(0.0), origdy(0.0), origdNorm2(0);
- bool moveto = true;
- double heightd = height;
-
- double lastx(0), lasty(0);
- double lastWrittenx(0), lastWritteny(0);
- bool clipped = false;
-
- bool haveMin = false, lastMax = true;
- double dnorm2Min(0), dnorm2Max(0);
- double maxX(0), maxY(0), minX(0), minY(0);
-
- double totdx, totdy, totdot;
- double paradx, parady, paradNorm2;
- double perpdx, perpdy, perpdNorm2;
-
- int counter = 0;
- //idea: we can skip drawing many lines: lines < 1 pixel in length, lines
- //outside of the drawing area, and we can combine sequential parallel lines
- //into a single line instead of redrawing lines over the same points.
- //The loop below works a bit like a state machine, where what it does depends
- //on what it did in the last looping. To test whether sequential lines
- //are close to parallel, I calculate the distance moved perpendicular to the
- //last line. Once it gets too big, the lines cannot be combined.
- for (size_t i=0; i<Nx; i++) {
-
- thisx = *(double *)(xa->data + i*xa->strides[0]);
- thisy = *(double *)(ya->data + i*ya->strides[0]);
-
- if (needNonlinear)
- try {
- // MGDTODO
- // mpltransform->nonlinear_only_api(&thisx, &thisy);
- }
- catch (...) {
- moveto = true;
- continue;
- }
- if (MPL_isnan64(thisx) || MPL_isnan64(thisy)) {
- moveto = true;
- continue;
- }
-
- //use agg's transformer?
- xytrans.transform(&thisx, &thisy);
- thisy = heightd - thisy; //flipy
-
- if (snapto) {
- //disable subpixel rendering for horizontal or vertical lines of len=2
- //because it causes irregular line widths for grids and ticks
- thisx = (int)thisx + 0.5;
- thisy = (int)thisy + 0.5;
- }
-
- //if we are starting a new path segment, move to the first point + init
- if(moveto){
- path.move_to(thisx, thisy);
- lastx = thisx;
- lasty = thisy;
- origdNorm2 = 0; //resets the orig-vector variables (see if-statement below)
- moveto = false;
- continue;
- }
-
- //don't render line segments less that on pixel long!
- if (fabs(thisx-lastx) < 1.0 && fabs(thisy-lasty) < 1.0 ){
- continue; //don't update lastx this time!
- }
-
- //skip any lines that are outside the drawing area. Note: More lines
- //could be clipped, but a more involved calculation would be needed
- if( (thisx < 0 && lastx < 0 ) ||
- (thisx > width && lastx > width ) ||
- (thisy < 0 && lasty < 0 ) ||
- (thisy > height && lasty > height) ){
- lastx = thisx;
- lasty = thisy;
- clipped = true;
- continue;
- }
-
- //if we have no orig vector, set it to this vector and continue.
- //this orig vector is the reference vector we will build up the line to
- if(origdNorm2 == 0){
- //if we clipped after the moveto but before we got here, redo the moveto
- if(clipped){
- path.move_to(lastx, lasty);
- clipped = false;
- }
-
- origdx = thisx - lastx;
- origdy = thisy - lasty;
- origdNorm2 = origdx*origdx + origdy*origdy;
-
- //set all the variables to reflect this new orig vecor
- dnorm2Max = origdNorm2;
- dnorm2Min = 0;
- haveMin = false;
- lastMax = true;
- maxX = thisx;
- maxY = thisy;
- minX = lastx;
- minY = lasty;
-
- lastWrittenx = lastx;
- lastWritteny = lasty;
-
- //set the last point seen
- lastx = thisx;
- lasty = thisy;
- continue;
- }
-
- //if got to here, then we have an orig vector and we just got
- //a vector in the sequence.
-
- //check that the perpendicular distance we have moved from the
- //last written point compared to the line we are building is not too
- //much. If o is the orig vector (we are building on), and v is the vector
- //from the last written point to the current point, then the perpendicular
- //vector is p = v - (o.v)o, and we normalize o (by dividing the
- //second term by o.o).
-
- //get the v vector
- totdx = thisx - lastWrittenx;
- totdy = thisy - lastWritteny;
- totdot = origdx*totdx + origdy*totdy;
-
- //get the para vector ( = (o.v)o/(o.o) )
- paradx = totdot*origdx/origdNorm2;
- parady = totdot*origdy/origdNorm2;
- paradNorm2 = paradx*paradx + parady*parady;
-
- //get the perp vector ( = v - para )
- perpdx = totdx - paradx;
- perpdy = totdy - parady;
- perpdNorm2 = perpdx*perpdx + perpdy*perpdy;
-
- //if the perp vector is less than some number of (squared) pixels in size,
- //then merge the current vector
- if(perpdNorm2 < 0.25 ){
- //check if the current vector is parallel or
- //anti-parallel to the orig vector. If it is parallel, test
- //if it is the longest of the vectors we are merging in that direction.
- //If anti-p, test if it is the longest in the opposite direction (the
- //min of our final line)
-
- lastMax = false;
- if(totdot >= 0){
- if(paradNorm2 > dnorm2Max){
- lastMax = true;
- dnorm2Max = paradNorm2;
- maxX = lastWrittenx + paradx;
- maxY = lastWritteny + parady;
- }
- }
- else{
-
- haveMin = true;
- if(paradNorm2 > dnorm2Min){
- dnorm2Min = paradNorm2;
- minX = lastWrittenx + paradx;
- minY = lastWritteny + parady;
- }
- }
-
- lastx = thisx;
- lasty = thisy;
- continue;
- }
-
- //if we get here, then this vector was not similar enough to the line
- //we are building, so we need to draw that line and start the next one.
-
- //if the line needs to extend in the opposite direction from the direction
- //we are drawing in, move back to we start drawing from back there.
- if(haveMin){
- path.line_to(minX, minY); //would be move_to if not for artifacts
- }
-
- path.line_to(maxX, maxY);
-
- //if we clipped some segments between this line and the next line
- //we are starting, we also need to move to the last point.
- if(clipped){
- path.move_to(lastx, lasty);
- }
- else if(!lastMax){
- //if the last line was not the longest line, then move back to the end
- //point of the last line in the sequence. Only do this if not clipped,
- //since in that case lastx,lasty is not part of the line just drawn.
- path.line_to(lastx, lasty); //would be move_to if not for artifacts
- }
-
- //std::cout << "draw lines (" << lastx << ", " << lasty << ")" << std::endl;
-
- //now reset all the variables to get ready for the next line
-
- origdx = thisx - lastx;
- origdy = thisy - lasty;
- origdNorm2 = origdx*origdx + origdy*origdy;
-
- dnorm2Max = origdNorm2;
- dnorm2Min = 0;
- haveMin = false;
- lastMax = true;
- maxX = thisx;
- maxY = thisy;
- minX = lastx;
- minY = lasty;
-
- lastWrittenx = lastx;
- lastWritteny = lasty;
-
- clipped = false;
-
- lastx = thisx;
- lasty = thisy;
-
- counter++;
- }
-
- //draw the last line, which is usually not drawn in the loop
- if(origdNorm2 != 0){
- if(haveMin){
- path.line_to(minX, minY); //would be move_to if not for artifacts
- }
-
- path.line_to(maxX, maxY);
- }
-
- //std::cout << "drew " << counter+1 << " lines" << std::endl;
-
- Py_XDECREF(xa);
- Py_XDECREF(ya);
-
- //typedef agg::conv_transform<agg::path_storage, agg::trans_affine> path_t;
- //path_t transpath(path, xytrans);
- _VERBOSE("RendererAgg::draw_lines rendering lines path");
- _render_lines_path(path, gc);
-
- _VERBOSE("RendererAgg::draw_lines DONE");
- return Py::Object();
-
-}
-
-bool
-RendererAgg::_process_alpha_mask(const GCAgg& gc)
- //if gc has a clippath set, process the alpha mask and return True,
- //else return False
-{
- if (gc.clippath==NULL) {
- return false;
- }
- if (0 &(gc.clippath==lastclippath)) {
- //std::cout << "seen it" << std::endl;
- return true;
- }
- rendererBaseAlphaMask->clear(agg::gray8(0, 0));
- gc.clippath->rewind(0);
- theRasterizer->add_path(*(gc.clippath));
- rendererAlphaMask->color(agg::gray8(255,255));
- agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask);
- lastclippath = gc.clippath;
- return true;
-}
-
-template<class PathSource>
-void
-RendererAgg::_render_lines_path(PathSource &path, const GCAgg& gc) {
- _VERBOSE("RendererAgg::_render_lines_path");
- typedef PathSource path_t;
- //typedef agg::conv_transform<agg::path_storage, agg::trans_affine> path_t;
- typedef agg::conv_stroke<path_t> stroke_t;
- typedef agg::conv_dash<path_t> dash_t;
-
- bool isclippath(gc.clippath!=NULL);
-
- if (gc.dasha==NULL ) { //no dashes
- stroke_t stroke(path);
- stroke.width(gc.linewidth);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- theRasterizer->add_path(stroke);
- }
- else {
- dash_t dash(path);
-
- //todo: dash.dash_start(gc.dashOffset);
- for (size_t i=0; i<gc.Ndash/2; i+=1)
- dash.add_dash(gc.dasha[2*i], gc.dasha[2*i+1]);
-
- agg::conv_stroke<dash_t> stroke(dash);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- stroke.width(gc.linewidth);
- theRasterizer->add_path(stroke); //boyle freeze is herre
- }
-
-
- if ( gc.isaa ) {
- if (isclippath) {
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- pixfmt_amask_type pfa(*pixFmt, *alphaMask);
- amask_ren_type r(pfa);
- typedef agg::renderer_scanline_aa_solid<amask_ren_type> renderer_type;
- renderer_type ren(r);
- ren.color(gc.color);
- //std::cout << "render clippath" << std::endl;
-
- agg::render_scanlines(*theRasterizer, *slineP8, ren);
- }
- else {
- rendererAA->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
- }
- }
- else {
- if (isclippath) {
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- pixfmt_amask_type pfa(*pixFmt, *alphaMask);
- amask_ren_type r(pfa);
- typedef agg::renderer_scanline_bin_solid<amask_ren_type> renderer_type;
- renderer_type ren(r);
- ren.color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, ren);
- }
- else{
- rendererBin->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
- }
- }
-}
-
-Py::Object
RendererAgg::draw_markers(const Py::Tuple& args) {
typedef agg::conv_transform<agg::path_storage> transformed_path_t;
typedef agg::conv_curve<transformed_path_t> curve_t;
@@ -1284,10 +548,10 @@
if (!PathAgg::check(marker_path_obj))
throw Py::TypeError("Native path object is not of correct type");
PathAgg* marker_path = static_cast<PathAgg*>(marker_path_obj.ptr());
- agg::trans_affine marker_trans = py_sequence_to_agg_transformation_matrix(args[2]);
+ agg::trans_affine marker_trans = py_to_agg_transformation_matrix(args[2]);
Py::Object vertices_obj = args[3];
Py::Object codes_obj = args[4];
- agg::trans_affine trans = py_sequence_to_agg_transformation_matrix(args[5]);
+ agg::trans_affine trans = py_to_agg_transformation_matrix(args[5]);
facepair_t face = _get_rgba_face(args[6], gc.alpha);
// Deal with the difference in y-axis direction
@@ -1337,7 +601,8 @@
unsigned strokeSize = scanlines.byte_size();
strokeCache = new agg::int8u[strokeSize]; // or any container
scanlines.serialize(strokeCache);
-
+
+ // MGDTODO: Clean this up and support clippaths as well
theRasterizer->reset_clipping();
if (gc.cliprect==NULL) {
rendererBase->reset_clipping(true);
@@ -1557,14 +822,20 @@
Py::Object
RendererAgg::convert_to_native_path(const Py::Tuple& args) {
_VERBOSE("RendererAgg::draw_image");
- args.verify_length(2);
+ args.verify_length(1);
- Py::Object vertices_obj = args[0];
- Py::Object codes_obj = args[1];
+ Py::Object path = args[0];
+
+ return Py::asObject(new PathAgg(path));
+}
+
+PathAgg::PathAgg(const Py::Object& path_obj) : curvy(false) {
+ Py::Object vertices_obj = path_obj.getAttr("vertices");
+ Py::Object codes_obj = path_obj.getAttr("codes");
+
PyArrayObject* vertices = NULL;
PyArrayObject* codes = NULL;
- PathAgg* path = NULL;
try {
vertices = (PyArrayObject*)PyArray_ContiguousFromObject
@@ -1576,8 +847,6 @@
if (!codes)
throw Py::ValueError("Invalid codes array.");
- path = new PathAgg();
-
size_t next_vertex_stride = vertices->strides[0];
size_t next_axis_stride = vertices->strides[1];
size_t code_stride = codes->strides[0];
@@ -1593,31 +862,31 @@
switch (*(unsigned char*)(code_i)) {
case MOVETO:
GET_NEXT_VERTEX(x0, y0);
- path->move_to(x0, y0);
+ move_to(x0, y0);
_VERBOSE("MOVETO");
break;
case LINETO:
GET_NEXT_VERTEX(x0, y0);
- path->line_to(x0, y0);
+ line_to(x0, y0);
_VERBOSE("LINETO");
break;
case CURVE3:
GET_NEXT_VERTEX(x0, y0);
GET_NEXT_VERTEX(x1, y1);
- path->curve3(x0, y0, x1, y1);
- path->curvy = true;
+ curve3(x0, y0, x1, y1);
+ curvy = true;
_VERBOSE("CURVE3");
break;
case CURVE4:
GET_NEXT_VERTEX(x0, y0);
GET_NEXT_VERTEX(x1, y1);
GET_NEXT_VERTEX(x2, y2);
- path->curve4(x0, y0, x1, y1, x2, y2);
- path->curvy = true;
+ curve4(x0, y0, x1, y1, x2, y2);
+ curvy = true;
_VERBOSE("CURVE4");
break;
case CLOSEPOLY:
- path->close_polygon();
+ close_polygon();
_VERBOSE("CLOSEPOLY");
break;
}
@@ -1626,14 +895,11 @@
} catch(...) {
Py_XDECREF(vertices);
Py_XDECREF(codes);
- delete path;
throw;
}
Py_XDECREF(vertices);
Py_XDECREF(codes);
-
- return Py::asObject(path);
}
Py::Object
@@ -1643,7 +909,11 @@
typedef agg::conv_stroke<curve_t> stroke_t;
typedef agg::conv_dash<curve_t> dash_t;
typedef agg::conv_stroke<dash_t> stroke_dash_t;
- //draw_path(gc, rgbFace, path, transform)
+ typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
+ typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
+ typedef agg::renderer_scanline_aa_solid<amask_ren_type> amask_aa_renderer_type;
+ typedef agg::renderer_scanline_bin_solid<amask_ren_type> amask_bin_renderer_type;
+
theRasterizer->reset_clipping();
_VERBOSE("RendererAgg::draw_path");
@@ -1654,52 +924,118 @@
if (!PathAgg::check(path_obj))
throw Py::TypeError("Native path object is not of correct type");
PathAgg* path = static_cast<PathAgg*>(path_obj.ptr());
- agg::trans_affine trans = py_sequence_to_agg_transformation_matrix(args[2]);
+ agg::trans_affine trans = py_to_agg_transformation_matrix(args[2]);
facepair_t face = _get_rgba_face(args[3], gc.alpha);
trans *= agg::trans_affine_scaling(1.0, -1.0);
trans *= agg::trans_affine_translation(0.0, (double)height);
- transformed_path_t tpath(*path, trans);
- // MGDTODO: See if there is any advantage to only curving if necessary
- curve_t curve(tpath);
+ transformed_path_t* tpath = NULL;
+ agg::path_storage new_path;
- set_clipbox_rasterizer(gc.cliprect);
-
- if (face.first) {
- rendererAA->color(face.second);
- theRasterizer->add_path(curve);
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
+ bool has_clippath = (gc.clippath != NULL);
+
+ if (has_clippath && (gc.clippath != lastclippath || trans != lastclippath_transform)) {
+ rendererBaseAlphaMask->clear(agg::gray8(0, 0));
+ gc.clippath->rewind(0);
+ transformed_path_t transformed_clippath(*(gc.clippath), trans);
+ theRasterizer->add_path(transformed_clippath);
+ rendererAlphaMask->color(agg::gray8(255, 255));
+ agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask);
+ lastclippath = gc.clippath;
+ lastclippath_transform = trans;
}
- if (gc.linewidth) {
- if (gc.dasha == NULL) {
- stroke_t stroke(curve);
- stroke.width(gc.linewidth);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- theRasterizer->add_path(stroke);
- } else {
- dash_t dash(curve);
- for (size_t i = 0; i < (gc.Ndash / 2); ++i)
- dash.add_dash(gc.dasha[2 * i], gc.dasha[2 * i + 1]);
- stroke_dash_t stroke(dash);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- stroke.width(gc.linewidth);
- theRasterizer->add_path(stroke); //boyle freeze is herre
+ try {
+ // If this is a straight horizontal or vertical line, quantize to nearest
+ // pixels
+ if (path->total_vertices() == 2) {
+ double x0, y0, x1, y1;
+ path->vertex(0, &x0, &y0);
+ trans.transform(&x0, &y0);
+ path->vertex(1, &x1, &y1);
+ trans.transform(&x1, &y1);
+ if (((int)x0 == (int)x1) || ((int)y0 == (int)y1)) {
+ new_path.move_to((int)x0 + 0.5, (int)y0 + 0.5);
+ new_path.line_to((int)x1 + 0.5, (int)y1 + 0.5);
+ tpath = new transformed_path_t(new_path, agg::trans_affine());
+ }
}
+
+ if (!tpath) {
+ tpath = new transformed_path_t(*path, trans);
+ }
+
+ // Benchmarking shows that there is no noticable slowdown to always
+ // treating paths as having curved segments. Doing so greatly
+ // simplifies the code
+ curve_t curve(*tpath);
- if ( gc.isaa ) {
- rendererAA->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
+ set_clipbox_rasterizer(gc.cliprect);
+
+ if (face.first) {
+ if (has_clippath) {
+ pixfmt_amask_type pfa(*pixFmt, *alphaMask);
+ amask_ren_type r(pfa);
+ amask_aa_renderer_type ren(r);
+ ren.color(gc.color);
+ agg::render_scanlines(*theRasterizer, *slineP8, ren);
+ } else{
+ rendererAA->color(face.second);
+ theRasterizer->add_path(curve);
+ agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
+ }
}
- else {
- rendererBin->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
+
+ if (gc.linewidth) {
+ if (gc.dasha == NULL) {
+ stroke_t stroke(curve);
+ stroke.width(gc.linewidth);
+ stroke.line_cap(gc.cap);
+ stroke.line_join(gc.join);
+ theRasterizer->add_path(stroke);
+ } else {
+ dash_t dash(curve);
+ for (size_t i = 0; i < (gc.Ndash / 2); ++i)
+ dash.add_dash(gc.dasha[2 * i], gc.dasha[2 * i + 1]);
+ stroke_dash_t stroke(dash);
+ stroke.line_cap(gc.cap);
+ stroke.line_join(gc.join);
+ stroke.width(gc.linewidth);
+ theRasterizer->add_path(stroke);
+ }
+
+ if (gc.isaa) {
+ if (has_clippath) {
+ pixfmt_amask_type pfa(*pixFmt, *alphaMask);
+ amask_ren_type r(pfa);
+ amask_aa_renderer_type ren(r);
+ ren.color(gc.color);
+ agg::render_scanlines(*theRasterizer, *slineP8, ren);
+ } else {
+ rendererAA->color(gc.color);
+ agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
+ }
+ } else {
+ if (has_clippath) {
+ pixfmt_amask_type pfa(*pixFmt, *alphaMask);
+ amask_ren_type r(pfa);
+ amask_bin_renderer_type ren(r);
+ ren.color(gc.color);
+ agg::render_scanlines(*theRasterizer, *slineP8, ren);
+ } else {
+ rendererBin->color(gc.color);
+ agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
+ }
+ }
}
+ } catch (...) {
+ delete tpath;
+ throw;
}
+ delete tpath;
+
return Py::Object();
}
@@ -2033,18 +1369,10 @@
behaviors().name("RendererAgg");
behaviors().doc("The agg backend extension module");
- add_varargs_method("draw_rectangle", &RendererAgg::draw_rectangle,
- "draw_rectangle(gc, rgbFace, l, b, w, h)\n");
- add_varargs_method("draw_ellipse", &RendererAgg::draw_ellipse,
- "draw_ellipse(gc, rgbFace, x, y, w, h)\n");
- add_varargs_method("draw_polygon", &RendererAgg::draw_polygon,
- "draw_polygon(gc, rgbFace, points)\n");
add_varargs_method("draw_path",...
[truncated message content] |