diff --git a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg b/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg
index 3f7c4c2a57ce..eb1c1194c131 100644
--- a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg
+++ b/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg
@@ -27,8 +27,7 @@ z
" style="fill:#ffffff;"/>
-
+" id="mdc24d94838" style="stroke:#000000;stroke-width:0.5;"/>
-
+
+" id="m110d6fc078" style="stroke:#000000;stroke-width:0.5;"/>
-
+
-
+
-
-
-
+
+
+
-
+
-
+
@@ -207,21 +206,21 @@ L 12.40625 0
z
" id="DejaVuSans-31"/>
-
-
-
+
+
+
-
+
-
+
@@ -251,9 +250,9 @@ Q 44.1875 33.984375 37.640625 27.21875
Q 31.109375 20.453125 19.1875 8.296875
" id="DejaVuSans-32"/>
-
-
-
+
+
+
@@ -262,176 +261,176 @@ Q 31.109375 20.453125 19.1875 8.296875
+" id="md652217826" style="stroke:#000000;stroke-width:0.5;"/>
-
+
+" id="m85d89dbb30" style="stroke:#000000;stroke-width:0.5;"/>
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -442,37 +441,25 @@ L 0 2
+" id="m0525a49047" style="stroke:#000000;stroke-width:0.5;"/>
-
+
+" id="m60671aa7ca" style="stroke:#000000;stroke-width:0.5;"/>
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
+
+
-
+
@@ -554,104 +553,104 @@ z
+" id="mbe24b9f137" style="stroke:#000000;stroke-width:0.5;"/>
-
+
+" id="m7965eaa9d8" style="stroke:#000000;stroke-width:0.5;"/>
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -659,8 +658,8 @@ L -2 0
-
-
+
+
diff --git a/lib/matplotlib/tests/test_simplification.py b/lib/matplotlib/tests/test_simplification.py
index df16d0de3e5f..ac0ef91f2a4f 100644
--- a/lib/matplotlib/tests/test_simplification.py
+++ b/lib/matplotlib/tests/test_simplification.py
@@ -212,6 +212,22 @@ def test_clipping_with_nans():
ax.set_ylim(-0.25, 0.25)
+def test_clipping_full():
+ p = path.Path([[1e30, 1e30]] * 5)
+ simplified = list(p.iter_segments(clip=[0, 0, 100, 100]))
+ assert simplified == []
+
+ p = path.Path([[50, 40], [75, 65]], [1, 2])
+ simplified = list(p.iter_segments(clip=[0, 0, 100, 100]))
+ assert ([(list(x), y) for x, y in simplified] ==
+ [([50, 40], 1), ([75, 65], 2)])
+
+ p = path.Path([[50, 40]], [1])
+ simplified = list(p.iter_segments(clip=[0, 0, 100, 100]))
+ assert ([(list(x), y) for x, y in simplified] ==
+ [([50, 40], 1)])
+
+
if __name__=='__main__':
import nose
nose.runmodule(argv=['-s','--with-doctest'], exit=False)
diff --git a/lib/matplotlib/tests/test_transforms.py b/lib/matplotlib/tests/test_transforms.py
index d961741c06ac..b804219a4e79 100644
--- a/lib/matplotlib/tests/test_transforms.py
+++ b/lib/matplotlib/tests/test_transforms.py
@@ -209,10 +209,7 @@ def test_clipping_of_log():
simplify=False)
tpoints, tcodes = list(zip(*result))
- # Because y coordinate -99 is outside the clip zone, the first
- # line segment is effectively removed. That means that the closepoly
- # operation must be replaced by a move to the first point.
- assert np.allclose(tcodes, [M, M, L, L, L, C])
+ assert np.allclose(tcodes, [M, L, L, L, C])
class NonAffineForTest(mtrans.Transform):
diff --git a/src/path_converters.h b/src/path_converters.h
index c13cc7c91a72..d19b17dc17ae 100644
--- a/src/path_converters.h
+++ b/src/path_converters.h
@@ -278,7 +278,7 @@ class PathNanRemover : protected EmbeddedQueue<4>
clipped, but are always included in their entirety.
*/
template
-class PathClipper
+class PathClipper : public EmbeddedQueue<3>
{
VertexSource *m_source;
bool m_do_clipping;
@@ -286,14 +286,9 @@ class PathClipper
double m_lastX;
double m_lastY;
bool m_moveto;
- double m_nextX;
- double m_nextY;
- bool m_has_next;
- bool m_end_poly;
double m_initX;
double m_initY;
bool m_has_init;
- bool m_broke_path;
public:
PathClipper(VertexSource &source, bool do_clipping, double width, double height)
@@ -301,10 +296,7 @@ class PathClipper
m_do_clipping(do_clipping),
m_cliprect(-1.0, -1.0, width + 1.0, height + 1.0),
m_moveto(true),
- m_has_next(false),
- m_end_poly(false),
- m_has_init(false),
- m_broke_path(false)
+ m_has_init(false)
{
// empty
}
@@ -314,10 +306,7 @@ class PathClipper
m_do_clipping(do_clipping),
m_cliprect(rect),
m_moveto(true),
- m_has_next(false),
- m_end_poly(false),
- m_has_init(false),
- m_broke_path(false)
+ m_has_init(false)
{
m_cliprect.x1 -= 1.0;
m_cliprect.y1 -= 1.0;
@@ -327,11 +316,30 @@ class PathClipper
inline void rewind(unsigned path_id)
{
- m_has_next = false;
+ m_has_init = false;
m_moveto = true;
m_source->rewind(path_id);
}
+ int draw_clipped_line(double x0, double y0, double x1, double y1)
+ {
+ unsigned moved = agg::clip_line_segment(&x0, &y0, &x1, &y1, m_cliprect);
+ // moved >= 4 - Fully clipped
+ // moved & 1 != 0 - First point has been moved
+ // moved & 2 != 0 - Second point has been moved
+ if (moved < 4) {
+ if (moved & 1 || m_moveto) {
+ queue_push(agg::path_cmd_move_to, x0, y0);
+ }
+ queue_push(agg::path_cmd_line_to, x1, y1);
+
+ m_moveto = false;
+ return 1;
+ }
+
+ return 0;
+ }
+
unsigned vertex(double *x, double *y)
{
unsigned code;
@@ -339,74 +347,69 @@ class PathClipper
if (m_do_clipping) {
/* This is the slow path where we actually do clipping */
- if (m_end_poly) {
- m_end_poly = false;
- return (agg::path_cmd_end_poly | agg::path_flags_close);
- }
-
- if (m_has_next) {
- m_has_next = false;
- *x = m_nextX;
- *y = m_nextY;
- return agg::path_cmd_line_to;
+ if (queue_pop(&code, x, y)) {
+ return code;
}
while ((code = m_source->vertex(x, y)) != agg::path_cmd_stop) {
- if (code == (agg::path_cmd_end_poly | agg::path_flags_close)) {
+ switch (code) {
+ case (agg::path_cmd_end_poly | agg::path_flags_close):
if (m_has_init) {
- *x = m_initX;
- *y = m_initY;
- code = agg::path_cmd_line_to;
- m_end_poly = true;
- } else {
- continue;
+ draw_clipped_line(m_lastX, m_lastY, m_initX, m_initY);
}
- }
-
- if (code == agg::path_cmd_move_to) {
- m_initX = *x;
- m_initY = *y;
+ queue_push(
+ agg::path_cmd_end_poly | agg::path_flags_close,
+ m_lastX, m_lastY);
+ goto exit_loop;
+
+ case agg::path_cmd_move_to:
+ m_initX = m_lastX = *x;
+ m_initY = m_lastY = *y;
m_has_init = true;
m_moveto = true;
- }
- if (m_moveto) {
- m_moveto = false;
- code = agg::path_cmd_move_to;
break;
- } else if (code == agg::path_cmd_line_to) {
- double x0, y0, x1, y1;
- x0 = m_lastX;
- y0 = m_lastY;
- x1 = *x;
- y1 = *y;
+
+ case agg::path_cmd_line_to:
+ if (draw_clipped_line(m_lastX, m_lastY, *x, *y)) {
+ m_lastX = *x;
+ m_lastY = *y;
+ goto exit_loop;
+ }
m_lastX = *x;
m_lastY = *y;
- unsigned moved = agg::clip_line_segment(&x0, &y0, &x1, &y1, m_cliprect);
- // moved >= 4 - Fully clipped
- // moved & 1 != 0 - First point has been moved
- // moved & 2 != 0 - Second point has been moved
- if (moved < 4) {
- if (moved & 1) {
- *x = x0;
- *y = y0;
- m_nextX = x1;
- m_nextY = y1;
- m_has_next = true;
- m_broke_path = true;
- return agg::path_cmd_move_to;
- }
- *x = x1;
- *y = y1;
- return code;
- }
- } else {
break;
+
+ default:
+ if (m_moveto) {
+ queue_push(agg::path_cmd_move_to, m_lastX, m_lastY);
+ m_moveto = false;
+ }
+
+ queue_push(code, *x, *y);
+ m_lastX = *x;
+ m_lastY = *y;
+ goto exit_loop;
}
}
- m_lastX = *x;
- m_lastY = *y;
- return code;
+ exit_loop:
+
+ if (queue_pop(&code, x, y)) {
+ return code;
+ }
+
+ if (m_moveto &&
+ m_lastX >= m_cliprect.x1 &&
+ m_lastX <= m_cliprect.x2 &&
+ m_lastY >= m_cliprect.y1 &&
+ m_lastY <= m_cliprect.y2) {
+ *x = m_lastX;
+ *y = m_lastY;
+ m_moveto = false;
+ return agg::path_cmd_move_to;
+ }
+
+ return agg::path_cmd_stop;
} else {
// If not doing any clipping, just pass along the vertices
// verbatim