matplotlib / matplotlib/matplotlib

Behavior of `contains()` inconsistent with fill in overlapping paths

Open
#32,329 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

topic: path handling
Dominant language
Python
Stars
23.2k
Forks
8.5k
Avg merge
1d 6h
Merged PRs (30d)
66

Description

> How do the two cases behave with `contains()` and mouse checking on the various artists?

I've investigated this, and amusingly enough, `contains()` is not fully consistent with either fill rule. The current logic (in [this function](https://github.com/matplotlib/matplotlib/blob/284213d3701a1112521fac0ef4891e3443c5880d/src/_path.h#L108)) is essentially (and possibly unintentionally) consistent with the even-odd rule on any individual subpath (and if the subpath does not self-intersect, the non-zero winding rule is the same). However, if there are multiple subpaths, a point is considered "inside" the combined path if it is inside at least one subpath, even if the combined effect of all subpaths mean that the point should actually be "outside". This means:
* If all subpaths do not self-intersect and do not intersect with each other, `contains()` is consistent with both the non-zero winding rule and the even-odd rule (that is, both rules have the same result)
* If there is a single subpath that self-intersects, `contains()` is consistent with the even-odd rule
* If there are multiple subpaths that do not self-intersect but do intersect with each other, *and* all subpaths are the same orientation, `contains()` is consistent with the non-zero winding rule
* If none of the above, `contains()` gives a "wrong" result: it is not consistent with either rule

My inclination is that fixing `contains()` should be deferred to a future PR.

_Originally posted by @ayshih in https://github.com/matplotlib/matplotlib/issues/32253#issuecomment-5591178865_

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked contains() function in src/_path.h, then compare its behavior with the fill-rule cases described for overlapping and self-intersecting subpaths. Before implementation, establish which fill rule contains() should follow and add coverage for those cases; the issue does not define an accepted behavior or completion test.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
computer-graphics, data-visualization
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.