title: matplotlib.Path.contains_points : "radius" parameter defined inconsistently
body: <p><strong>Problem:</strong></p>
  
  <p>The radius parameter in the function contains_point in <a href="https://matplotlib.org/api/path_api.html" rel="nofollow noreferrer">matplotlib.path</a> is defined inconsistently. This function checks if a specified point is inside or outside of a closed path. The radius parameter is used to make the path a little bit smaller/larger (dependent on the sign of radius). In this way, points can be taken into/out of account, which are close to the path. The problem is, that the sign of radius depends on the orientation of the path (clockwise or counterclockwise).
  The <em>inconsistency</em> (in my opinion) is there, because the orientation of path is ignored when checking if a point is inside or outside the path. In a mathematical strict sense one says: everything which is left along the path is included.</p>
  
  <p><strong>In short:</strong></p>
  
  <p>If the path is orientated counterclockwise, a positive radius takes more points into account.
  If the path is orientated clockwise, a positive radius takes less points into account.</p>
  
  <p><strong>Example:</strong></p>
  
  <p>In the following example there are 3 cases checked - each for a clockwise and a counterclockwise path:</p>
  
  <ol>
  <li>Is a point (close to path) contained with positive radius</li>
  <li>Is a point (close to path) contained with negative radius</li>
  <li>Is the origin contained (which is in the middle of both paths)</li>
  </ol>
  
  <p>Code:</p>
  
  <pre><code>import matplotlib.path as path
  import numpy as np
  
  
  verts=np.array([[-11.5,  16. ],[-11.5, -16. ],[ 11.5, -16. ],[ 11.5,  16. ],[-11.5,  16. ]])
  
  ccwPath=path.Path(verts, closed=True) 
  cwPath=path.Path(verts[::-1,:], closed=True) 
  
  testPoint=[12,0]
  
  
  print('contains:         ','|\t', '[12,0], radius=3','|\t', '[12,0], radius=-3','|\t', '[0,0]|')
  
  print('counterclockwise: ','|\t'
  ,'{0:&gt;16s}'.format(str(ccwPath.contains_point(testPoint,radius=3) )),'|\t'
  ,'{0:&gt;17s}'.format(str(ccwPath.contains_point(testPoint,radius=-3) )),'|\t'
  ,ccwPath.contains_point([0,0],radius=0) ,'|\t'
  ,'=&gt; radius increases tolerance \t'
  )
  
  print('clockwise:        ','|\t'
  ,'{0:&gt;16s}'.format(str(cwPath.contains_point(testPoint,radius=3) )),'|\t'
  ,'{0:&gt;17s}'.format(str(cwPath.contains_point(testPoint,radius=-3) )),'|\t'
  ,cwPath.contains_point([0,0],radius=0) ,'|\t'
  ,'=&gt; radius decreases tolerance \t'
  )
  </code></pre>
  
  <p>Output:</p>
  
  <pre><code>contains:          |     [12,0], radius=3 |      [12,0], radius=-3 |     [0,0]|
  counterclockwise:  |                 True |                  False |     True |  =&gt; radius increases tolerance 
  clockwise:         |                False |                   True |     True |  =&gt; radius decreases tolerance 
  </code></pre>
  
  <p><strong>Solution for convex paths:</strong></p>
  
  <p>The only idea I came up with, is to force the path into a counter-clockwise orientation and use radius according to this.</p>
  
  <pre><code>import matplotlib.path as path
  import numpy as np
  
  
  verts=np.array([[-11.5,  16. ],[-11.5, -16. ],[ 11.5, -16. ],[ 11.5,  16. ],[-11.5,  16. ]])
  
  #comment following line out to make isCounterClockWise crash
  #verts=np.array([[-11.5,  16. ],[-10,0],[-11.5, -16. ],[ 11.5, -16. ],[ 11.5,  16. ],[-11.5,  16. ]])
  
  ccwPath=path.Path(verts, closed=True) 
  cwPath=path.Path(verts[::-1,:], closed=True) 
  
  testPoint=[12,0]
  
  def isCounterClockWise(myPath):
  
          #directions from on vertex to the other
          dirs=myPath.vertices[1:]-myPath.vertices[0:-1]
          #rot: array of rotations at ech edge
          rot=np.cross(dirs[:-1],dirs[1:]) 
          if len(rot[rot&gt;0])==len(rot):
              #counterclockwise
              return True
          elif len(rot[rot&lt;0])==len(rot):
              #clockwise
              return False
          else:
              assert False, 'no yet implemented: This case applies if myPath is concave'
  
  def forceCounterClockWise(myPath):
      if not isCounterClockWise(myPath):
          myPath.vertices=myPath.vertices[::-1]
  
  
  forceCounterClockWise(cwPath)
  print('contains:         ','|\t', '[12,0], radius=3','|\t', '[12,0], radius=-3','|\t', '[0,0]|')
  
  print('counterclockwise: ','|\t'
  ,'{0:&gt;16s}'.format(str(ccwPath.contains_point(testPoint,radius=3) )),'|\t'
  ,'{0:&gt;17s}'.format(str(ccwPath.contains_point(testPoint,radius=-3) )),'|\t'
  ,ccwPath.contains_point([0,0],radius=0) ,'|\t'
  ,'=&gt; radius increases tolerance \t'
  )
  
  print('forced ccw:      ','|\t'
  ,'{0:&gt;16s}'.format(str(cwPath.contains_point(testPoint,radius=3) )),'|\t'
  ,'{0:&gt;17s}'.format(str(cwPath.contains_point(testPoint,radius=-3) )),'|\t'
  ,cwPath.contains_point([0,0],radius=0) ,'|\t'
  ,'=&gt; radius increases tolerance \t'
  )
  </code></pre>
  
  <p>giving the following output:</p>
  
  <pre><code>contains:          |     [12,0], radius=3 |      [12,0], radius=-3 |     [0,0]|
  counterclockwise:  |                 True |                  False |     True |  =&gt; radius increases tolerance 
  forced ccw:       |                  True |                  False |     True |  =&gt; radius increases tolerance 
  </code></pre>
  
  <p>An example, where this solution fails (for a concave path) is given in the comment of the code.</p>
  
  <p><strong>My questions:</strong></p>
  
  <ol>
  <li>Does anyone know, why this inconsistency is there? </li>
  <li>Is there a more elegant way to circumvent this issue? Examples might be: using an other library for contains_point, using the radius parameter in a smarter/proper way or finding the orientation of a path with a predefined function.</li>
  </ol>