# Path: pylinac/core/utilities.py
# def is_iterable(object) -> bool:
#     """Determine if an object is iterable."""
#     return isinstance(object, Iterable)
# 
# Path: pylinac/core/typing.py



from itertools import zip_longest
from typing import Union, Optional, List, Iterable, Tuple
from matplotlib.patches import Circle as mpl_Circle
from matplotlib.patches import Rectangle as mpl_Rectangle
from .utilities import is_iterable
from .typing import NumberLike
import math
import numpy as np
import matplotlib.pyplot as plt

class Point:
    """A geometric point with x, y, and z coordinates/attributes."""
    z: Union[int, float]
    y: Union[int, float]
    x: Union[int, float]
    _attr_list: List[str] = ['x', 'y', 'z', 'idx', 'value']
    _coord_list: List[str] = ['x', 'y', 'z']

    def __init__(self, x: Union[NumberLike, tuple, 'Point'] = 0, y: NumberLike = 0, z: NumberLike = 0, idx: Optional[int]=None,
                 value: Optional[NumberLike]=None, as_int: bool=False):
        """
        Parameters
        ----------
        x : number-like, Point, iterable
            x-coordinate or iterable type containing all coordinates. If iterable, values are assumed to be in order: (x,y,z).
        y : number-like, optional
            y-coordinate
        idx : int, optional
            Index of point. Useful for sequential coordinates; e.g. a point on a circle profile is sometimes easier to describe
            in terms of its index rather than x,y coords.
        value : number-like, optional
            value at point location (e.g. pixel value of an image)
        as_int : boolean
            If True, coordinates are converted to integers.
        """
        if isinstance(x, Point):
            for attr in self._attr_list:
                item = getattr(x, attr, None)
                setattr(self, attr, item)

# Path: pylinac/core/utilities.py
# def is_iterable(object) -> bool:
#     """Determine if an object is iterable."""
#     return isinstance(object, Iterable)
# 
# Path: pylinac/core/typing.py



# Path: pylinac/core/geometry.py
from itertools import zip_longest
from typing import Union, Optional, List, Iterable, Tuple
from matplotlib.patches import Circle as mpl_Circle
from matplotlib.patches import Rectangle as mpl_Rectangle
from .utilities import is_iterable
from .typing import NumberLike
import math
import numpy as np
import matplotlib.pyplot as plt


class Point:
    """A geometric point with x, y, and z coordinates/attributes."""
    z: Union[int, float]
    y: Union[int, float]
    x: Union[int, float]
    _attr_list: List[str] = ['x', 'y', 'z', 'idx', 'value']
    _coord_list: List[str] = ['x', 'y', 'z']

    def __init__(self, x: Union[NumberLike, tuple, 'Point'] = 0, y: NumberLike = 0, z: NumberLike = 0, idx: Optional[int]=None,
                 value: Optional[NumberLike]=None, as_int: bool=False):
        """
        Parameters
        ----------
        x : number-like, Point, iterable
            x-coordinate or iterable type containing all coordinates. If iterable, values are assumed to be in order: (x,y,z).
        y : number-like, optional
            y-coordinate
        idx : int, optional
            Index of point. Useful for sequential coordinates; e.g. a point on a circle profile is sometimes easier to describe
            in terms of its index rather than x,y coords.
        value : number-like, optional
            value at point location (e.g. pixel value of an image)
        as_int : boolean
            If True, coordinates are converted to integers.
        """
        if isinstance(x, Point):
            for attr in self._attr_list:
                item = getattr(x, attr, None)
                setattr(self, attr, item)

        elif is_iterable(x):