11"""2-dimensional regions of interest.""" 
22
3+ from  __future__ import  annotations 
4+ 
35from  collections .abc  import  Sequence 
46
57from  movement .roi .base  import  BaseRegionOfInterest , PointLikeList 
@@ -18,36 +20,53 @@ class PolygonOfInterest(BaseRegionOfInterest):
1820    interest (RoIs) in an analysis. The basic usage is to construct an 
1921    instance of this class by passing in a list of points, which will then be 
2022    joined (in sequence) by straight lines between consecutive pairs of points, 
21-     to form the boundary of the RoI. Note that the boundary itself is a 
22-     (closed) ``LineOfInterest``, and may be treated accordingly. 
23+     to form the exterior boundary of the RoI. Note that the exterior boundary 
24+     (accessible as via the ``.exterior`` property) is a (closed) 
25+     ``LineOfInterest``, and may be treated accordingly. 
26+ 
27+     The class also supports holes - subregions properly contained inside the 
28+     region that are not part of the region itself. These can be specified by 
29+     the ``holes`` argument, and define the interior boundaries of the region. 
30+     These interior boundaries are accessible via the ``.interior_boundaries`` 
31+     property, and the polygonal regions that make up the holes are accessible 
32+     via the ``holes`` property. 
2333    """ 
2434
2535    def  __init__ (
2636        self ,
27-         boundary : PointLikeList ,
37+         exterior_boundary : PointLikeList ,
2838        holes : Sequence [PointLikeList ] |  None  =  None ,
2939        name : str  |  None  =  None ,
3040    ) ->  None :
3141        """Create a new region of interest (RoI). 
3242
3343        Parameters 
3444        ---------- 
35-         boundary  : tuple of (x, y) pairs 
45+         exterior_boundary  : tuple of (x, y) pairs 
3646            The points (in sequence) that make up the boundary of the region. 
3747            At least three points must be provided. 
3848        holes : sequence of sequences of (x, y) pairs, default None 
3949            A sequence of items, where each item will be interpreted like 
4050            ``boundary``. These items will be used to construct internal holes 
4151            within the region. See the ``holes`` argument to 
4252            ``shapely.Polygon`` for details. 
43-         name : str 
44-             Name of the RoI that is to be created. 
53+         name : str, optional 
54+             Name of the RoI that is to be created. A default name will be 
55+             inherited from the base class if not provided. 
56+ 
57+         See Also 
58+         -------- 
59+         movement.roi.base.BaseRegionOfInterest 
60+             The base class that constructor arguments are passed to, and 
61+             defaults are inherited from. 
4562
4663        """ 
47-         super ().__init__ (points = boundary , dimensions = 2 , holes = holes , name = name )
64+         super ().__init__ (
65+             points = exterior_boundary , dimensions = 2 , holes = holes , name = name 
66+         )
4867
4968    @property  
50-     def  exterior (self ) ->  LineOfInterest :
69+     def  exterior_boundary (self ) ->  LineOfInterest :
5170        """The exterior boundary of this RoI.""" 
5271        return  LineOfInterest (
5372            self .region .exterior .coords ,
@@ -56,12 +75,26 @@ def exterior(self) -> LineOfInterest:
5675        )
5776
5877    @property  
59-     def  interiors (self ) ->  tuple [LineOfInterest , ...]:
60-         """The interior boundaries  of this RoI. 
78+     def  holes (self ) ->  tuple [PolygonOfInterest , ...]:
79+         """The interior holes  of this RoI. 
6180
62-         Interior boundaries are the boundaries of holes contained within the polygon. 
81+         Holes are regions properly contained within the exterior boundary of 
82+         the RoI that are not part of the RoI itself (like the centre of a 
83+         doughnut, for example). A region with no holes returns the empty tuple. 
84+         """ 
85+         return  tuple (
86+             PolygonOfInterest (
87+                 int_boundary .coords , name = f"Hole { i }   of { self .name }  " 
88+             )
89+             for  i , int_boundary  in  enumerate (self .region .interiors )
90+         )
91+ 
92+     @property  
93+     def  interior_boundaries (self ) ->  tuple [LineOfInterest , ...]:
94+         """The interior boundaries of this RoI. 
6395
64-         A region with no interior boundaries returns the empty tuple. 
96+         Interior boundaries are the boundaries of holes contained within the 
97+         polygon.  A region with no holes returns the empty tuple. 
6598        """ 
6699        return  tuple (
67100            LineOfInterest (
0 commit comments