Playing with it, I encountered some cases where this method answers that the two paths are not intersecting, while after plotting them, they do (see the example script and picture below). I still didn't have time to look into further (especially the C++ code that is wrapped by the method), but it seems to me that this behavior is not correct, is it?
Details
Matplotlib version, Python version and Platform (Windows, OSX, Linux ...)
Matplotlib 1.5.1, with Python 2.7.11 (and IPython 4.0.1), on Linux (CentOS 7 or Manjaro)
How did you install Matplotlib and Python (pip, anaconda, from source ...)
Anaconda 2.4.0 (64-bit)
If possible please supply a Short, Self Contained, Correct, Example
that demonstrates the issue i.e a small piece of code which reproduces the issue
and can be run with out any other (or as few as possible) external dependencies.
# -*- coding: utf-8 -*-importmatplotlib.pyplotaspltfrommatplotlib.patchesimportPathPatchfrommatplotlib.pathimportPathcubic_bezier_codes= [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4]
defplot_ctrls(verts, ax, label='',
ls='--', marker='o', ms=5, lw=1, alpha=0.6, color='Gray'):
"""Plot the control points of a Bezier curve (debugging purpose) """ax.plot(*zip(*verts), ls=ls, lw=lw, color=color, ms=ms, marker=marker,
alpha=alpha, label=label)
returnax# For your viewing pleasure when plottingdetection_color= {True: "OliveDrab", False: "Crimson"}
if__name__=="__main__":
plt.ion()
# A dummy path to play withverts_1= [(0.5, 0.01), (0.21, 0.99), (0.99, 0.8), (0.99, 0.99)]
path_1=Path(verts_1, cubic_bezier_codes)
# A path that does intersect with path_1 but for which the ad-hoc test# method failsverts_2a= [(0.5, 0.8), (0.5, 0.7), (0.6, 0.75), (0.56, 0.7)]
path_2a=Path(verts_2a, cubic_bezier_codes)
# Decreasing a bit the y-value of the last control point leads to a# correct detection of path intersecting.verts_2b= [(0.5, 0.8), (0.5, 0.7), (0.6, 0.75), (0.56, 0.6)]
path_2b=Path(verts_2b, cubic_bezier_codes)
# Plot everything to be surefig, (axA, axB) =plt.subplots(ncols=2, sharex=True, sharey=True)
title_prefix="path_1.intersects_path(path_2):\n"forax, p1, p2in [(axA, path_1, path_2a), (axB, path_1, path_2b)]:
# Detect if the two paths intersectdetection=p1.intersects_path(p2)
ax.set_title(title_prefix+"{}".format(detection))
# Plot the two pathspatch_1=PathPatch(p1, lw=2, fc='none', ec='CornFlowerBlue')
pc1=ax.add_patch(patch_1)
patch_2=PathPatch(p2, lw=2, fc='none', ec=detection_color[detection])
ax.add_patch(patch_2)
# Plot the controls nodes for debuggingax=plot_ctrls(p1.vertices, ax, marker='s', color=patch_1.get_ec(),
label='verts_1')
ax=plot_ctrls(p2.vertices, ax, color=patch_2.get_ec(),
label='verts_2')
ax.legend(loc='lower right', handlelength=3.5)
#fig.savefig("Issue_with_intersecting_path_detection.png", dpi=150)
If this is an image generation bug attach a screenshot demonstrating the issue.
The paths are plotted in solid lines, and the vertices (control points) of the paths are plotted with markers (with thin dashed lines between them, and of the same color as the path they correspond to).
Left panel: the red path (path_2) is indicated as non intersecting with the blue one (path_1) by path_1.intersects_path(path_2), while from the plot they seem to be intersecting…
Right panel: the green path (path_2) is indicated as intersecting with the blue one (path_1) by path_1.intersects_path(path_2), which seems correct from the plot…
The only difference between the two red and green paths is their last control point (on the right), which is a bit lower in the right panel case than in the left panel case.
If this is a regression (Used to work in an earlier version of Matplotlib), please
note where it used to work.
Never used Path.intersects_path method before, so I can't tell if it's a regression.
Here's the issue -- but I'll have to think on a fix.
Path intersection is done by converting the curves to line segments and then converting the intersection based on the line segments. This conversion happens by "sampling" the curve at increments of 1.0. This is generally the right thing to do when the paths are already scaled in display space, because sampling the curve at a resolution finer than a single pixel doesn't really help. However, when calculating the intersection in data space as you've done here, we obviously need to sample at a finer resolution.
A workaround that should work for you now would be to convert the paths to pixel space and do the intersection calculation there:
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!
Activity
mdboom commented on Feb 29, 2016
Here's the issue -- but I'll have to think on a fix.
Path intersection is done by converting the curves to line segments and then converting the intersection based on the line segments. This conversion happens by "sampling" the curve at increments of 1.0. This is generally the right thing to do when the paths are already scaled in display space, because sampling the curve at a resolution finer than a single pixel doesn't really help. However, when calculating the intersection in data space as you've done here, we obviously need to sample at a finer resolution.
A workaround that should work for you now would be to convert the paths to pixel space and do the intersection calculation there:
Though I think the long term fix is to replace the algorithm with something that is directly curve-aware.
afvincent commented on Feb 29, 2016
Thank you for the explanation. Your workaround indeed solves my problem of the misdetected intersecting path (left panel on previous picture).
github-actions commented on Mar 22, 2023
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!