From 1c521fa3d13bdce6f6a90828fca40377132a52d0 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Thu, 9 Oct 2008 01:19:54 +0000 Subject: [PATCH] path simplification for paths with gaps svn path=/trunk/matplotlib/; revision=6174 --- CHANGELOG | 2 + examples/pylab_examples/clippedline.py | 2 +- lib/matplotlib/path.py | 5 +- src/agg_py_path_iterator.h | 129 ++++++++++++++++--------- 4 files changed, 87 insertions(+), 51 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cc7b650396cf..2274aea0312e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +2008-10-08 Add path simplification support to paths with gaps. - EF + 2008-10-05 Fix problem with AFM files that don't specify the font's full name or family name. - JKS diff --git a/examples/pylab_examples/clippedline.py b/examples/pylab_examples/clippedline.py index 998c3dec9481..d0bf422c03d8 100644 --- a/examples/pylab_examples/clippedline.py +++ b/examples/pylab_examples/clippedline.py @@ -19,7 +19,7 @@ def __init__(self, ax, *args, **kwargs): def set_data(self, *args, **kwargs): Line2D.set_data(self, *args, **kwargs) - if self._invalid: + if self._invalid: self.recache() self.xorig = np.array(self._x) self.yorig = np.array(self._y) diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index 8870ec70b7fb..34d094beffbf 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -109,9 +109,8 @@ def __init__(self, vertices, codes=None): assert vertices.ndim == 2 assert vertices.shape[1] == 2 - self.should_simplify = (codes is None and - np.all(np.isfinite(vertices)) and - len(vertices) >= 128) + self.should_simplify = (len(vertices) >= 128 and + (codes is None or np.all(codes <= Path.LINETO))) self.codes = codes self.vertices = vertices diff --git a/src/agg_py_path_iterator.h b/src/agg_py_path_iterator.h index a01d13fa2752..21fb4715c310 100644 --- a/src/agg_py_path_iterator.h +++ b/src/agg_py_path_iterator.h @@ -137,7 +137,8 @@ class SimplifyPath double width = 0.0, double height = 0.0) : m_source(&source), m_quantize(quantize), m_simplify(simplify), m_width(width + 1.0), m_height(height + 1.0), m_queue_read(0), m_queue_write(0), - m_moveto(true), m_lastx(0.0), m_lasty(0.0), m_clipped(false), + m_moveto(true), m_after_moveto(false), + m_lastx(0.0), m_lasty(0.0), m_clipped(false), m_do_clipping(width > 0.0 && height > 0.0), m_origdx(0.0), m_origdy(0.0), m_origdNorm2(0.0), m_dnorm2Max(0.0), m_dnorm2Min(0.0), @@ -205,6 +206,7 @@ class SimplifyPath *y = front.y; #if DEBUG_SIMPLIFY printf((cmd == agg::path_cmd_move_to) ? "|" : "-"); + printf(" 1 %f %f\n", *x, *y); #endif return cmd; } @@ -239,18 +241,40 @@ class SimplifyPath //if we are starting a new path segment, move to the first point // + init - if (m_moveto) + +#if DEBUG_SIMPLIFY + printf("x, y, code: %f, %f, %d\n", *x, *y, cmd); +#endif + if (m_moveto || cmd == agg::path_cmd_move_to) { + // m_moveto check is not generally needed because + // m_source generates an initial moveto; but it + // is retained for safety in case circumstances + // arise where this is not true. + if (m_origdNorm2 && !m_after_moveto) + { + // m_origdNorm2 is nonzero only if we have a vector; + // the m_after_moveto check ensures we push this + // vector to the queue only once. + _push(x,y); + } + m_after_moveto = true; m_lastx = *x; m_lasty = *y; m_moveto = false; m_origdNorm2 = 0.0; -#if DEBUG_SIMPLIFY - m_pushed++; - printf("|"); -#endif - return agg::path_cmd_move_to; + // A moveto resulting from a nan yields a missing + // line segment, hence a break in the line, just + // like clipping, so we treat it the same way. + m_clipped = true; + if (m_queue_read < m_queue_write) + { + // If we did a push, empty the queue now. + break; + } + continue; } + m_after_moveto = false; // Don't render line segments less than one pixel long if (fabs(*x - m_lastx) < 1.0 && fabs(*y - m_lasty) < 1.0) @@ -295,7 +319,7 @@ class SimplifyPath m_origdy = *y - m_lasty; m_origdNorm2 = m_origdx*m_origdx + m_origdy*m_origdy; - //set all the variables to reflect this new orig vecor + //set all the variables to reflect this new orig vector m_dnorm2Max = m_origdNorm2; m_dnorm2Min = 0.0; m_haveMin = false; @@ -376,7 +400,6 @@ class SimplifyPath #endif 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. @@ -384,46 +407,9 @@ class SimplifyPath //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 (m_haveMin) - { - m_queue[m_queue_write++].set(agg::path_cmd_line_to, m_minX, m_minY); - } - m_queue[m_queue_write++].set(agg::path_cmd_line_to, m_maxX, m_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 (m_clipped) { - m_queue[m_queue_write++].set(agg::path_cmd_move_to, m_lastx, m_lasty); - } - else if (!m_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. - - //Would be move_to if not for the artifacts - m_queue[m_queue_write++].set(agg::path_cmd_line_to, m_lastx, m_lasty); - } + _push(x, y); - //now reset all the variables to get ready for the next line - m_origdx = *x - m_lastx; - m_origdy = *y - m_lasty; - m_origdNorm2 = m_origdx*m_origdx + m_origdy*m_origdy; - - m_dnorm2Max = m_origdNorm2; - m_dnorm2Min = 0.0; - m_haveMin = false; - m_lastMax = true; - m_lastx = m_maxX = *x; - m_lasty = m_maxY = *y; - m_lastWrittenX = m_minX = m_lastx; - m_lastWrittenY = m_minY = m_lasty; - - m_clipped = false; -#if DEBUG_SIMPLIFY - m_pushed += m_queue_write - m_queue_read; -#endif break; } @@ -453,6 +439,8 @@ class SimplifyPath *y = front.y; #if DEBUG_SIMPLIFY printf((cmd == agg::path_cmd_move_to) ? "|" : "-"); + printf(" 3 %f %f\n", *x, *y); + #endif return cmd; } @@ -489,6 +477,7 @@ class SimplifyPath item m_queue[6]; bool m_moveto; + bool m_after_moveto; double m_lastx, m_lasty; bool m_clipped; bool m_do_clipping; @@ -512,6 +501,52 @@ class SimplifyPath unsigned m_pushed; unsigned m_skipped; #endif + + void _push(double* x, double* y) + { + if (m_haveMin) + { + m_queue[m_queue_write++].set(agg::path_cmd_line_to, m_minX, m_minY); + } + m_queue[m_queue_write++].set(agg::path_cmd_line_to, m_maxX, m_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 (m_clipped) { + m_queue[m_queue_write++].set(agg::path_cmd_move_to, m_lastx, m_lasty); + } + else if (!m_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. + + //Would be move_to if not for the artifacts + m_queue[m_queue_write++].set(agg::path_cmd_line_to, m_lastx, m_lasty); + } + + //now reset all the variables to get ready for the next line + m_origdx = *x - m_lastx; + m_origdy = *y - m_lasty; + m_origdNorm2 = m_origdx*m_origdx + m_origdy*m_origdy; + + m_dnorm2Max = m_origdNorm2; + m_dnorm2Min = 0.0; + m_haveMin = false; + m_lastMax = true; + m_lastx = m_maxX = *x; + m_lasty = m_maxY = *y; + m_lastWrittenX = m_minX = m_lastx; + m_lastWrittenY = m_minY = m_lasty; + + m_clipped = false; +#if DEBUG_SIMPLIFY + m_pushed += m_queue_write - m_queue_read; +#endif + + } + }; #endif // __AGG_PY_PATH_ITERATOR_H__