diff --git a/lib/matplotlib/tests/test_triangulation.py b/lib/matplotlib/tests/test_triangulation.py index 3aca6eeea73d..682a0fbe4b75 100644 --- a/lib/matplotlib/tests/test_triangulation.py +++ b/lib/matplotlib/tests/test_triangulation.py @@ -1340,3 +1340,64 @@ def test_triplot_label(): assert labels == ['label'] assert len(handles) == 1 assert handles[0] is lines + + +def test_tricontour_path(): + x = [0, 4, 4, 0, 2] + y = [0, 0, 4, 4, 2] + triang = mtri.Triangulation(x, y) + _, ax = plt.subplots() + + # Line strip from boundary to boundary + cs = ax.tricontour(triang, [1, 0, 0, 0, 0], levels=[0.5]) + paths = cs.get_paths() + assert len(paths) == 1 + expected_vertices = [[2, 0], [1, 1], [0, 2]] + assert_array_almost_equal(paths[0].vertices, expected_vertices) + assert_array_equal(paths[0].codes, [1, 2, 2]) + assert_array_almost_equal( + paths[0].to_polygons(closed_only=False), [expected_vertices]) + + # Closed line loop inside domain + cs = ax.tricontour(triang, [0, 0, 0, 0, 1], levels=[0.5]) + paths = cs.get_paths() + assert len(paths) == 1 + expected_vertices = [[3, 1], [3, 3], [1, 3], [1, 1], [3, 1]] + assert_array_almost_equal(paths[0].vertices, expected_vertices) + assert_array_equal(paths[0].codes, [1, 2, 2, 2, 79]) + assert_array_almost_equal(paths[0].to_polygons(), [expected_vertices]) + + +def test_tricontourf_path(): + x = [0, 4, 4, 0, 2] + y = [0, 0, 4, 4, 2] + triang = mtri.Triangulation(x, y) + _, ax = plt.subplots() + + # Polygon inside domain + cs = ax.tricontourf(triang, [0, 0, 0, 0, 1], levels=[0.5, 1.5]) + paths = cs.get_paths() + assert len(paths) == 1 + expected_vertices = [[3, 1], [3, 3], [1, 3], [1, 1], [3, 1]] + assert_array_almost_equal(paths[0].vertices, expected_vertices) + assert_array_equal(paths[0].codes, [1, 2, 2, 2, 79]) + assert_array_almost_equal(paths[0].to_polygons(), [expected_vertices]) + + # Polygon following boundary and inside domain + cs = ax.tricontourf(triang, [1, 0, 0, 0, 0], levels=[0.5, 1.5]) + paths = cs.get_paths() + assert len(paths) == 1 + expected_vertices = [[2, 0], [1, 1], [0, 2], [0, 0], [2, 0]] + assert_array_almost_equal(paths[0].vertices, expected_vertices) + assert_array_equal(paths[0].codes, [1, 2, 2, 2, 79]) + assert_array_almost_equal(paths[0].to_polygons(), [expected_vertices]) + + # Polygon is outer boundary with hole + cs = ax.tricontourf(triang, [0, 0, 0, 0, 1], levels=[-0.5, 0.5]) + paths = cs.get_paths() + assert len(paths) == 1 + expected_vertices = [[0, 0], [4, 0], [4, 4], [0, 4], [0, 0], + [1, 1], [1, 3], [3, 3], [3, 1], [1, 1]] + assert_array_almost_equal(paths[0].vertices, expected_vertices) + assert_array_equal(paths[0].codes, [1, 2, 2, 2, 79, 1, 2, 2, 2, 79]) + assert_array_almost_equal(paths[0].to_polygons(), np.split(expected_vertices, [5])) diff --git a/src/tri/_tri.cpp b/src/tri/_tri.cpp index b54eb3e07fb8..2674a3140b35 100644 --- a/src/tri/_tri.cpp +++ b/src/tri/_tri.cpp @@ -733,6 +733,9 @@ py::tuple TriContourGenerator::contour_to_segs_and_kinds(const Contour& contour) *segs_ptr++ = point->y; *codes_ptr++ = (point == line->begin() ? MOVETO : LINETO); } + + if (line->size() > 1) + *(codes_ptr-1) = CLOSEPOLY; } py::list vertices_list(1); @@ -849,11 +852,8 @@ void TriContourGenerator::find_boundary_lines_filled(Contour& contour, lower_level, upper_level, on_upper); } while (tri_edge != start_tri_edge); - // Filled contour lines must not have same first and last - // points. - if (contour_line.size() > 1 && - contour_line.front() == contour_line.back()) - contour_line.pop_back(); + // Close polygon. + contour_line.push_back(contour_line.front()); } } } @@ -872,6 +872,9 @@ void TriContourGenerator::find_boundary_lines_filled(Contour& contour, for (Boundary::size_type j = 0; j < boundary.size(); ++j) contour_line.push_back(triang.get_point_coords( triang.get_triangle_point(boundary[j]))); + + // Close polygon. + contour_line.push_back(contour_line.front()); } } } @@ -904,13 +907,8 @@ void TriContourGenerator::find_interior_lines(Contour& contour, TriEdge tri_edge = triang.get_neighbor_edge(tri, edge); follow_interior(contour_line, tri_edge, false, level, on_upper); - if (!filled) - // Non-filled contour lines must be closed. - contour_line.push_back(contour_line.front()); - else if (contour_line.size() > 1 && - contour_line.front() == contour_line.back()) - // Filled contour lines must not have same first and last points. - contour_line.pop_back(); + // Close line loop + contour_line.push_back(contour_line.front()); } }