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

Skip to content

Commit 90e5384

Browse files
committed
Add line simplification, to cut down on the number of line segments
that need to be stroked. Affects *Agg and Gdk backends. svn path=/trunk/matplotlib/; revision=4875
1 parent 2e7b542 commit 90e5384

5 files changed

Lines changed: 413 additions & 53 deletions

File tree

lib/matplotlib/backends/backend_gdk.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def set_width_height (self, width, height):
8484
def draw_path(self, gc, path, transform, rgbFace=None):
8585
transform = transform + Affine2D(). \
8686
scale(1.0, -1.0).translate(0, self.height)
87-
polygons = path.to_polygons(transform)
87+
polygons = path.to_polygons(transform, self.width, self.height)
8888
for polygon in polygons:
8989
# draw_polygon won't take an arbitrary sequence -- it must be a list
9090
# of tuples

lib/matplotlib/path.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ def interpolated(self, steps):
283283
new_codes = None
284284
return Path(vertices, new_codes)
285285

286-
def to_polygons(self, transform=None):
286+
def to_polygons(self, transform=None, width=0, height=0):
287287
"""
288288
Convert this path to a list of polygons. Each polygon is an
289289
Nx2 array of vertices. In other words, each polygon has no
@@ -292,13 +292,13 @@ def to_polygons(self, transform=None):
292292
if transform is not None:
293293
transform = transform.frozen()
294294
# Deal with the common and simple case
295-
if self.codes is None:
295+
if self.codes is None and len(self.vertices) < 100:
296296
if len(self.vertices):
297297
return [transform.transform(self.vertices)]
298298
return []
299299
# Deal with the case where there are curves and/or multiple
300300
# subpaths (using extension code)
301-
return convert_path_to_polygons(self, transform)
301+
return convert_path_to_polygons(self, transform, width, height)
302302

303303
_unit_rectangle = None
304304
#@classmethod

src/_backend_agg.cpp

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "agg_span_image_filter_gray.h"
2121
#include "agg_span_image_filter_rgba.h"
2222
#include "agg_span_interpolator_linear.h"
23+
#include "agg_conv_shorten_path.h"
2324
#include "util/agg_color_conv_rgb8.h"
2425

2526
#include "ft2font.h"
@@ -84,31 +85,6 @@ Py::Object BufferRegion::to_string(const Py::Tuple &args) {
8485
return Py::String(PyString_FromStringAndSize((const char*)data, height*stride), true);
8586
}
8687

87-
template<class VertexSource> class conv_quantize
88-
{
89-
public:
90-
conv_quantize(VertexSource& source, bool quantize) :
91-
m_source(&source), m_quantize(quantize) {}
92-
93-
void rewind(unsigned path_id) {
94-
m_source->rewind(path_id);
95-
}
96-
97-
unsigned vertex(double* x, double* y) {
98-
unsigned cmd = m_source->vertex(x, y);
99-
if (m_quantize && agg::is_vertex(cmd)) {
100-
*x = round(*x) + 0.5;
101-
*y = round(*y) + 0.5;
102-
}
103-
return cmd;
104-
}
105-
106-
private:
107-
VertexSource* m_source;
108-
bool m_quantize;
109-
};
110-
111-
11288
GCAgg::GCAgg(const Py::Object &gc, double dpi) :
11389
dpi(dpi), isaa(true), linewidth(1.0), alpha(1.0),
11490
dashOffset(0.0)
@@ -358,8 +334,8 @@ SafeSnap::snap (const float& x, const float& y) {
358334

359335
template<class Path>
360336
bool should_snap(Path& path, const agg::trans_affine& trans) {
361-
// If this contains only straight horizontal or vertical lines, quantize to nearest
362-
// pixels
337+
// If this contains only straight horizontal or vertical lines, it should be
338+
// quantized to the nearest pixels
363339
double x0, y0, x1, y1;
364340
unsigned code;
365341

@@ -392,6 +368,11 @@ bool should_snap(Path& path, const agg::trans_affine& trans) {
392368
return true;
393369
}
394370

371+
template<class Path>
372+
bool should_simplify(Path& path) {
373+
return !path.has_curves() && path.total_vertices() > 5;
374+
}
375+
395376
Py::Object
396377
RendererAgg::copy_from_bbox(const Py::Tuple& args) {
397378
//copy region in bbox to buffer and return swig/agg buffer object
@@ -479,7 +460,7 @@ bool RendererAgg::render_clippath(const Py::Object& clippath, const agg::trans_a
479460
Py::Object
480461
RendererAgg::draw_markers(const Py::Tuple& args) {
481462
typedef agg::conv_transform<PathIterator> transformed_path_t;
482-
typedef conv_quantize<transformed_path_t> quantize_t;
463+
typedef SimplifyPath<transformed_path_t> simplify_t;
483464
typedef agg::conv_curve<transformed_path_t> curve_t;
484465
typedef agg::conv_stroke<curve_t> stroke_t;
485466
typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
@@ -510,8 +491,8 @@ RendererAgg::draw_markers(const Py::Tuple& args) {
510491
bool snap = should_snap(path, trans);
511492
transformed_path_t path_transformed(path, trans);
512493
GCAgg gc = GCAgg(gc_obj, dpi);
513-
quantize_t path_quantized(path_transformed, snap);
514-
path_quantized.rewind(0);
494+
simplify_t path_simplified(path_transformed, snap, false, width, height);
495+
path_simplified.rewind(0);
515496

516497
facepair_t face = _get_rgba_face(face_obj, gc.alpha);
517498

@@ -564,7 +545,7 @@ RendererAgg::draw_markers(const Py::Tuple& args) {
564545
agg::serialized_scanlines_adaptor_aa8::embedded_scanline sl;
565546

566547
if (has_clippath) {
567-
while (path_quantized.vertex(&x, &y) != agg::path_cmd_stop) {
548+
while (path_simplified.vertex(&x, &y) != agg::path_cmd_stop) {
568549
pixfmt_amask_type pfa(*pixFmt, *alphaMask);
569550
amask_ren_type r(pfa);
570551
amask_aa_renderer_type ren(r);
@@ -579,7 +560,7 @@ RendererAgg::draw_markers(const Py::Tuple& args) {
579560
agg::render_scanlines(sa, sl, ren);
580561
}
581562
} else {
582-
while (path_quantized.vertex(&x, &y) != agg::path_cmd_stop) {
563+
while (path_simplified.vertex(&x, &y) != agg::path_cmd_stop) {
583564
if (face.first) {
584565
rendererAA->color(face.second);
585566
sa.init(fillCache, fillSize, x, y);
@@ -881,8 +862,8 @@ void RendererAgg::_draw_path(path_t& path, bool has_clippath,
881862
Py::Object
882863
RendererAgg::draw_path(const Py::Tuple& args) {
883864
typedef agg::conv_transform<PathIterator> transformed_path_t;
884-
typedef conv_quantize<transformed_path_t> quantize_t;
885-
typedef agg::conv_curve<quantize_t> curve_t;
865+
typedef SimplifyPath<transformed_path_t> simplify_t;
866+
typedef agg::conv_curve<simplify_t> curve_t;
886867

887868
_VERBOSE("RendererAgg::draw_path");
888869
args.verify_length(3, 4);
@@ -906,9 +887,11 @@ RendererAgg::draw_path(const Py::Tuple& args) {
906887
trans *= agg::trans_affine_scaling(1.0, -1.0);
907888
trans *= agg::trans_affine_translation(0.0, (double)height);
908889
bool snap = should_snap(path, trans);
890+
bool simplify = should_simplify(path);
891+
909892
transformed_path_t tpath(path, trans);
910-
quantize_t quantized(tpath, snap);
911-
curve_t curve(quantized);
893+
simplify_t simplified(tpath, snap, simplify, width, height);
894+
curve_t curve(simplified);
912895
if (snap)
913896
gc.isaa = false;
914897

@@ -934,8 +917,8 @@ RendererAgg::_draw_path_collection_generic
934917
const Py::SeqBase<Py::Object>& linestyles_obj,
935918
const Py::SeqBase<Py::Int>& antialiaseds) {
936919
typedef agg::conv_transform<typename PathGenerator::path_iterator> transformed_path_t;
937-
typedef conv_quantize<transformed_path_t> quantize_t;
938-
typedef agg::conv_curve<quantize_t> quantized_curve_t;
920+
typedef SimplifyPath<transformed_path_t> simplify_t;
921+
typedef agg::conv_curve<simplify_t> simplified_curve_t;
939922
typedef agg::conv_curve<transformed_path_t> curve_t;
940923

941924
GCAgg gc(dpi);
@@ -1068,12 +1051,12 @@ RendererAgg::_draw_path_collection_generic
10681051
gc.isaa = bool(Py::Int(antialiaseds[i % Naa]));
10691052

10701053
transformed_path_t tpath(path, trans);
1071-
quantize_t quantized(tpath, snap);
1054+
simplify_t simplified(tpath, snap, false, width, height);
10721055
if (has_curves) {
1073-
quantized_curve_t curve(quantized);
1056+
simplified_curve_t curve(simplified);
10741057
_draw_path(curve, has_clippath, face, gc);
10751058
} else {
1076-
_draw_path(quantized, has_clippath, face, gc);
1059+
_draw_path(simplified, has_clippath, face, gc);
10771060
}
10781061
} else {
10791062
gc.isaa = bool(Py::Int(antialiaseds[i % Naa]));

src/_path.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,17 +1102,23 @@ void _add_polygon(Py::List& polygons, const std::vector<double>& polygon) {
11021102
Py::Object _path_module::convert_path_to_polygons(const Py::Tuple& args)
11031103
{
11041104
typedef agg::conv_transform<PathIterator> transformed_path_t;
1105-
typedef agg::conv_curve<transformed_path_t> curve_t;
1105+
typedef SimplifyPath<transformed_path_t> simplify_t;
1106+
typedef agg::conv_curve<simplify_t> curve_t;
11061107

11071108
typedef std::vector<double> vertices_t;
11081109

1109-
args.verify_length(2);
1110+
args.verify_length(4);
11101111

11111112
PathIterator path(args[0]);
11121113
agg::trans_affine trans = py_to_agg_transformation_matrix(args[1], false);
1114+
double width = Py::Float(args[2]);
1115+
double height = Py::Float(args[3]);
1116+
1117+
bool simplify = !path.has_curves();
11131118

11141119
transformed_path_t tpath(path, trans);
1115-
curve_t curve(tpath);
1120+
simplify_t simplified(tpath, false, simplify, width, height);
1121+
curve_t curve(simplified);
11161122

11171123
Py::List polygons;
11181124
vertices_t polygon;

0 commit comments

Comments
 (0)