import math
import textwrap
from collections.abc import Sequence

import numpy as np
from numpy.typing import ArrayLike
from scipy import spatial

from .._shared.utils import get_bound_method_class, safe_as_int

def _affine_matrix_from_vector(v): ...
def _center_and_normalize_points(points): ...
def _umeyama(src, dst, estimate_scale): ...

class GeometricTransform:
    def __call__(self, coords): ...
    def inverse(self, coords): ...
    def residuals(self, src, dst): ...
    def __add__(self, other): ...

class FundamentalMatrixTransform(GeometricTransform):
    def __init__(self, matrix=None, *, dimensionality=2): ...
    def __call__(self, coords): ...
    def inverse(self, coords): ...
    def _setup_constraint_matrix(self, src, dst): ...
    def estimate(self, src, dst) -> bool: ...
    def residuals(self, src, dst): ...

class EssentialMatrixTransform(FundamentalMatrixTransform):
    def __init__(self, rotation=None, translation=None, matrix=None, *, dimensionality=2): ...
    def estimate(self, src, dst) -> bool: ...

class ProjectiveTransform(GeometricTransform):
    def __init__(self, matrix=None, *, dimensionality: int = 2): ...
    @property
    def _inv_matrix(self): ...
    def _apply_mat(self, coords, matrix): ...
    def __array__(self, dtype=None): ...
    def __call__(self, coords): ...
    def inverse(self, coords): ...
    def estimate(self, src, dst, weights=None) -> bool: ...
    def __add__(self, other): ...
    def __nice__(self): ...
    def __repr__(self): ...
    def __str__(self): ...
    @property
    def dimensionality(self): ...

class AffineTransform(ProjectiveTransform):
    def __init__(
        self,
        matrix=None,
        scale=None,
        rotation: float | None = None,
        shear: float | None = None,
        translation=None,
        *,
        dimensionality: int = 2,
    ): ...
    @property
    def scale(self): ...
    @property
    def rotation(self): ...
    @property
    def shear(self): ...
    @property
    def translation(self): ...

class PiecewiseAffineTransform(GeometricTransform):
    def __init__(self): ...
    def estimate(self, src, dst) -> bool: ...
    def __call__(self, coords): ...
    def inverse(self, coords): ...

def _euler_rotation(axis, angle): ...
def _euler_rotation_matrix(angles, axes=None): ...

class EuclideanTransform(ProjectiveTransform):
    def __init__(
        self, matrix=None, rotation: float | Sequence[float] | None = None, translation=None, *, dimensionality: int = 2
    ): ...
    def estimate(self, src, dst) -> bool: ...
    @property
    def rotation(self): ...
    @property
    def translation(self): ...

class SimilarityTransform(EuclideanTransform):
    def __init__(
        self, matrix=None, scale: float | None = None, rotation: float | None = None, translation=None, *, dimensionality=2
    ): ...
    def estimate(self, src, dst) -> bool: ...
    @property
    def scale(self): ...

class PolynomialTransform(GeometricTransform):
    def __init__(self, params=None, *, dimensionality=2): ...
    def estimate(self, src, dst, order: int = 2, weights=None) -> bool: ...
    def __call__(self, coords): ...
    def inverse(self, coords): ...

TRANSFORMS: dict = ...

def estimate_transform(ttype, src, dst, *args, **kwargs: ArrayLike | int): ...
def matrix_transform(coords, matrix): ...
