from collections.abc import Iterator, Sequence
from typing import BinaryIO, Self, TextIO, overload

import numpy as np
from numpy.typing import ArrayLike, NDArray

class EOFError(Exception): ...

class parameterEdge:
    NONE: int
    WEST: int
    EAST: int
    SOUTH: int
    NORTH: int
    TOP: int
    BOTTOM: int

class refinementStrategy:
    LR_MINSPAN: int
    LR_FULLSPAN: int
    LR_STRUCTURED_MESH: int

class Basisfunction:
    def getId(self) -> int: ...
    def getControlPoint(self) -> NDArray[np.double]: ...
    def nVariate(self) -> int: ...
    @overload
    def evaluate(self, u: np.floating, v: np.floating, u_from_right: bool, v_from_right: bool) -> float: ...
    @overload
    def evaluate(
        self, u: np.floating, v: np.floating, d: int, u_from_right: bool, v_from_right: bool
    ) -> NDArray[np.double]: ...
    @overload
    def evaluate(
        self,
        u: np.floating,
        v: np.floating,
        w: np.floating,
        u_from_right: bool,
        v_from_right: bool,
        w_from_right: bool,
    ) -> float: ...
    @overload
    def evaluate(
        self,
        u: np.floating,
        v: np.floating,
        w: np.floating,
        d: int,
        u_from_right: bool,
        v_from_right: bool,
        w_from_right: bool,
    ) -> NDArray[np.double]: ...
    def supportIter(self) -> Iterator[Element]: ...
    def getknots(self, idx: int) -> NDArray[np.double]: ...

class Element:
    def getId(self) -> int: ...
    def getDim(self) -> int: ...
    def getParmin(self, i: int) -> float: ...
    def getParmax(self, i: int) -> float: ...
    def nBasisFunctions(self) -> int: ...
    def supportIter(self) -> Iterator[Basisfunction]: ...

class Meshline:
    def is_spanning_u(self) -> int: ...
    @property
    def const_par_(self) -> float: ...
    @property
    def start_(self) -> float: ...
    @property
    def stop_(self) -> float: ...
    @property
    def multiplicity_(self) -> int: ...

class MeshRectangle:
    @overload
    def __init__(self) -> None: ...
    @overload
    def __init__(
        self, u0: float, v0: float, w0: float, u1: float, v1: float, w1: float, multiplicity: int = ...
    ) -> None: ...
    def constDirection(self) -> int: ...
    def constParameter(self) -> float: ...
    @property
    def start_(self) -> NDArray[np.double]: ...
    @property
    def stop_(self) -> NDArray[np.double]: ...
    @property
    def multiplicity_(self) -> int: ...
    def copy(self) -> MeshRectangle: ...

class LRSplineObject:
    def nVariate(self) -> int: ...
    def dimension(self) -> int: ...
    def rebuildDimension(self, dim: int) -> None: ...
    def nBasisFunctions(self) -> int: ...
    def nElements(self) -> int: ...
    def startparam(self, i: int) -> float: ...
    def endparam(self, i: int) -> float: ...
    def order(self, i: int) -> int: ...
    def elementIter(self) -> Iterator[Element]: ...
    def getElement(self, i: int) -> Element: ...
    def getEdgeElementsIter(self, edge: int) -> Iterator[Element]: ...
    def basisIter(self) -> Iterator[Basisfunction]: ...
    def getBasifunction(self) -> Iterator[Basisfunction]: ...
    def getEdgeFunctionsIter(self, edge: int, depth: int = ...) -> Iterator[Basisfunction]: ...
    def setControlpoints(self, cpts: NDArray[np.double]) -> None: ...
    def generateIDs(self) -> int: ...
    def refineBasisFunction(self, i: int | list[int]) -> None: ...
    def refineElement(self, i: int | list[int]) -> None: ...
    def refineByDimensionIncrease(self, errors: NDArray[np.double], beta: float) -> None: ...
    def setRefStrat(self, strat: int) -> None: ...
    def setRefSymmetry(self, symmetry: int) -> None: ...
    def setRefMultiplicity(self, mult: int) -> None: ...
    def setMaxTjoints(self, n: int) -> None: ...
    def setCloseGaps(self, close: bool) -> None: ...
    def setMaxAspectRatio(self, r: float, aposteriori: bool = ...) -> None: ...
    def write(self, stream: TextIO) -> None: ...
    def getGlobalKnotVector(self) -> tuple[NDArray[np.double], ...]: ...
    def getGlobalUniqueKnotVector(self) -> tuple[NDArray[np.double], ...]: ...
    def getBezierExtraction(self, iEl: int = ...) -> NDArray[np.double]: ...
    def read(self, stream: BinaryIO | TextIO | bytes | str) -> None: ...
    def copy(self) -> Self: ...

class LRSurface(LRSplineObject):
    @overload
    def __init__(self) -> None: ...
    @overload
    def __init__(self, n1: int, n2: int, order_u: int, order_v: int) -> None: ...
    @overload
    def __init__(
        self, n1: int, n2: int, order_u: int, order_v: int, knot1: ArrayLike, knot2: ArrayLike
    ) -> None: ...
    @overload
    def __init__(
        self,
        n1: int,
        n2: int,
        order_u: int,
        order_v: int,
        knot1: ArrayLike,
        knot2: ArrayLike,
        cps: ArrayLike,
        dim: int = ...,
    ) -> None: ...
    def writePostscriptElements(
        self,
        stream: TextIO,
        nu: int = ...,
        nv: int = ...,
        close: bool = ...,
        colorElements: Sequence[int] | None = ...,
    ) -> None: ...
    def insert_const_u_edge(
        self, u: float, start_v: float, stop_v: float, multiplicity: int = ...
    ) -> None: ...
    def insert_const_v_edge(
        self, v: float, start_u: float, stop_u: float, multiplicity: int = ...
    ) -> None: ...
    @overload
    def point(self, u: np.floating, v: np.floating, *, iEl: int = ...) -> NDArray[np.double]: ...
    @overload
    def point(
        self, u: np.floating, v: np.floating, ufr: bool, vfr: bool, *, iEl: int = ...
    ) -> NDArray[np.double]: ...
    @overload
    def point(self, u: np.floating, v: np.floating, d: int, *, iEl: int = ...) -> NDArray[np.double]: ...
    @overload
    def point(
        self, u: np.floating, v: np.floating, d: int, ufr: bool, vfr: bool, *, iEl: int = ...
    ) -> NDArray[np.double]: ...
    def getElementContaining(self, u: float, v: float) -> int: ...
    def makeIntegerKnots(self) -> float: ...
    def meshlineIter(self) -> Iterator[Meshline]: ...
    def nMeshlines(self) -> int: ...
    def getMeshline(self, i: int) -> Meshline: ...

class LRVolume(LRSplineObject):
    @overload
    def __init__(self) -> None: ...
    @overload
    def __init__(self, n1: int, n2: int, n3: int, order_u: int, order_v: int, order_w: int) -> None: ...
    @overload
    def __init__(
        self,
        n1: int,
        n2: int,
        n3: int,
        order_u: int,
        order_v: int,
        order_w: int,
        knot1: ArrayLike,
        knot2: ArrayLike,
        knot3: ArrayLike,
    ) -> None: ...
    @overload
    def __init__(
        self,
        n1: int,
        n2: int,
        n3: int,
        order_u: int,
        order_v: int,
        order_w: int,
        knot1: ArrayLike,
        knot2: ArrayLike,
        knot3: ArrayLike,
        cps: ArrayLike,
        dim: int = ...,
    ) -> None: ...
    @overload
    def point(
        self, u: np.floating, v: np.floating, w: np.floating, *, iEl: int = ...
    ) -> NDArray[np.double]: ...
    @overload
    def point(
        self,
        u: np.floating,
        v: np.floating,
        w: np.floating,
        ufr: bool,
        vfr: bool,
        wfr: bool,
        *,
        iEl: int = ...,
    ) -> NDArray[np.double]: ...
    @overload
    def point(
        self, u: np.floating, v: np.floating, w: np.floating, d: int, *, iEl: int = ...
    ) -> NDArray[np.double]: ...
    @overload
    def point(
        self,
        u: np.floating,
        v: np.floating,
        w: np.floating,
        d: int,
        ufr: bool,
        vfr: bool,
        wfr: bool,
        *,
        iEl: int = ...,
    ) -> NDArray[np.double]: ...
    def insert_line(self, mr: MeshRectangle) -> None: ...
    def getElementContaining(self, u: float, v: float, w: float) -> int: ...
    def meshrectIter(self) -> Iterator[MeshRectangle]: ...
    def nMeshRectangles(self) -> int: ...
    def getMeshRectangle(self, i: int) -> MeshRectangle: ...
