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 a82ca89

Browse filesBrowse files
committed
Merge pull request #5672 from mdboom/double-endpoints
Fix #5670. No double endpoints in Path.to_polygon
2 parents 5904e2f + bf230fd commit a82ca89
Copy full SHA for a82ca89

File tree

Expand file treeCollapse file tree

5 files changed

+93
-19
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+93
-19
lines changed

‎lib/matplotlib/tests/test_path.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_path.py
+36Lines changed: 36 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,41 @@ 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+
116152
if __name__ == '__main__':
117153
import nose
118154
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

‎lib/matplotlib/tests/test_widgets.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_widgets.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def onselect(epress, erelease):
162162
extents = [int(e) for e in tool.extents]
163163
assert extents == [70, 129, 70, 130], extents
164164

165-
assert tool.geometry.shape == (2, 74)
165+
assert tool.geometry.shape == (2, 73)
166166
assert_allclose(tool.geometry[:, 0], [70., 100])
167167

168168

‎lib/matplotlib/widgets.py

Copy file name to clipboardExpand all lines: lib/matplotlib/widgets.py
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ def on_clicked(self, func):
245245
"""
246246
When the button is clicked, call this *func* with event.
247247
248-
A connection id is returned. It can be used to disconnect
248+
A connection id is returned. It can be used to disconnect
249249
the button from its callback.
250250
"""
251251
cid = self.cnt
@@ -265,7 +265,7 @@ class Slider(AxesWidget):
265265
"""
266266
A slider representing a floating point range.
267267
268-
For the slider to remain responsive you must maintain a
268+
For the slider to remain responsive you must maintain a
269269
reference to it.
270270
271271
The following attributes are defined
@@ -2036,7 +2036,7 @@ def geometry(self):
20362036
if hasattr(self.to_draw, 'get_verts'):
20372037
xfm = self.ax.transData.inverted()
20382038
y, x = xfm.transform(self.to_draw.get_verts()).T
2039-
return np.array([x[:-1], y[:-1]])
2039+
return np.array([x, y])
20402040
else:
20412041
return np.array(self.to_draw.get_data())
20422042

‎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.