Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 36ce4a7

Browse filesBrowse files
committed
Fix #5670. No double endpoints in Path.to_polygon
1 parent 0c64cd5 commit 36ce4a7
Copy full SHA for 36ce4a7

File tree

Expand file treeCollapse file tree

3 files changed

+90
-15
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+90
-15
lines changed

‎lib/matplotlib/tests/test_path.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_path.py
+37Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from nose.tools import assert_raises, assert_equal
1111
from matplotlib.testing.decorators import image_comparison
1212
import matplotlib.pyplot as plt
13+
from matplotlib import transforms
1314

1415

1516
def test_readonly_path():
@@ -113,6 +114,42 @@ def test_marker_paths_pdf():
113114
plt.ylim(-1, 7)
114115

115116

117+
def test_path_no_doubled_point_in_to_polygon():
118+
hand = np.array(
119+
[[ 1.64516129, 1.16145833 ],
120+
[ 1.64516129, 1.59375 ],
121+
[ 1.35080645, 1.921875 ],
122+
[ 1.375 , 2.18229167 ],
123+
[ 1.68548387, 1.9375 ],
124+
[ 1.60887097, 2.55208333 ],
125+
[ 1.68548387, 2.69791667 ],
126+
[ 1.76209677, 2.56770833 ],
127+
[ 1.83064516, 1.97395833 ],
128+
[ 1.89516129, 2.75 ],
129+
[ 1.9516129 , 2.84895833 ],
130+
[ 2.01209677, 2.76041667 ],
131+
[ 1.99193548, 1.99479167 ],
132+
[ 2.11290323, 2.63020833 ],
133+
[ 2.2016129 , 2.734375 ],
134+
[ 2.25403226, 2.60416667 ],
135+
[ 2.14919355, 1.953125 ],
136+
[ 2.30645161, 2.36979167 ],
137+
[ 2.39112903, 2.36979167 ],
138+
[ 2.41532258, 2.1875 ],
139+
[ 2.1733871 , 1.703125 ],
140+
[ 2.07782258, 1.16666667 ]])
141+
142+
(r0, c0, r1, c1) = (1.0, 1.5, 2.1, 2.5)
143+
144+
poly = Path(np.vstack((hand[:, 1], hand[:, 0])).T, closed=True)
145+
clip_rect = transforms.Bbox([[r0, c0], [r1, c1]])
146+
poly_clipped = poly.clip_to_bbox(clip_rect).to_polygons()[0]
147+
148+
assert np.all(poly_clipped[-2] != poly_clipped[-1])
149+
assert np.all(poly_clipped[-1] == poly_clipped[0])
150+
151+
152+
116153
if __name__ == '__main__':
117154
import nose
118155
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

‎src/_path.h

Copy file name to clipboardExpand all lines: src/_path.h
+35-10Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ struct XY
2727
XY(double x_, double y_) : x(x_), y(y_)
2828
{
2929
}
30+
31+
bool operator==(const XY& o)
32+
{
33+
return (x == o.x && y == o.y);
34+
}
35+
36+
bool operator!=(const XY& o)
37+
{
38+
return (x != o.x || y != o.y);
39+
}
3040
};
3141

3242
//
@@ -838,6 +848,25 @@ bool path_intersects_path(PathIterator1 &p1, PathIterator2 &p2)
838848
return false;
839849
}
840850

851+
void _finalize_polygon(std::vector<Polygon> &result)
852+
{
853+
Polygon &polygon = result.back();
854+
855+
if (result.size() == 0) {
856+
return;
857+
}
858+
859+
/* Clean up the last polygon in the result. If less than a
860+
triangle, remove it. */
861+
if (polygon.size() < 3) {
862+
result.pop_back();
863+
} else {
864+
if (polygon.front() != polygon.back()) {
865+
polygon.push_back(polygon.front());
866+
}
867+
}
868+
}
869+
841870
template <class PathIterator>
842871
void convert_path_to_polygons(PathIterator &path,
843872
agg::trans_affine &trans,
@@ -867,24 +896,20 @@ void convert_path_to_polygons(PathIterator &path,
867896

868897
while ((code = curve.vertex(&x, &y)) != agg::path_cmd_stop) {
869898
if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
870-
if (polygon->size() >= 1) {
871-
polygon->push_back((*polygon)[0]);
872-
result.push_back(Polygon());
873-
polygon = &result.back();
874-
}
899+
_finalize_polygon(result);
900+
result.push_back(Polygon());
901+
polygon = &result.back();
875902
} else {
876-
if (code == agg::path_cmd_move_to && polygon->size() >= 1) {
877-
polygon->push_back((*polygon)[0]);
903+
if (code == agg::path_cmd_move_to) {
904+
_finalize_polygon(result);
878905
result.push_back(Polygon());
879906
polygon = &result.back();
880907
}
881908
polygon->push_back(XY(x, y));
882909
}
883910
}
884911

885-
if (polygon->size() == 0) {
886-
result.pop_back();
887-
}
912+
_finalize_polygon(result);
888913
}
889914

890915
template <class VertexSource>

‎src/_path_wrapper.cpp

Copy file name to clipboardExpand all lines: src/_path_wrapper.cpp
+18-5Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,29 @@
88
PyObject *convert_polygon_vector(std::vector<Polygon> &polygons)
99
{
1010
PyObject *pyresult = PyList_New(polygons.size());
11+
bool fix_endpoints;
1112

1213
for (size_t i = 0; i < polygons.size(); ++i) {
1314
Polygon poly = polygons[i];
14-
npy_intp dims[] = {(npy_intp)poly.size() + 1, 2 };
15-
numpy::array_view<double, 2> subresult(dims);
15+
npy_intp dims[2];
16+
dims[1] = 2;
17+
18+
if (poly.front() != poly.back()) {
19+
/* Make last point same as first, if not already */
20+
dims[0] = (npy_intp)poly.size() + 1;
21+
fix_endpoints = true;
22+
} else {
23+
dims[0] = (npy_intp)poly.size();
24+
fix_endpoints = false;
25+
}
1626

17-
/* Make last point same as first. */
27+
numpy::array_view<double, 2> subresult(dims);
1828
memcpy(subresult.data(), &poly[0], sizeof(double) * poly.size() * 2);
19-
subresult(poly.size(), 0) = poly[0].x;
20-
subresult(poly.size(), 1) = poly[0].y;
29+
30+
if (fix_endpoints) {
31+
subresult(poly.size(), 0) = poly.front().x;
32+
subresult(poly.size(), 1) = poly.front().y;
33+
}
2134

2235
if (PyList_SetItem(pyresult, i, subresult.pyobj())) {
2336
Py_DECREF(pyresult);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.