Skip to content

PitchDimensions

kloppy.domain.PitchDimensions dataclass

PitchDimensions(x_dim, y_dim, standardized, unit, goal_width, goal_height, six_yard_width, six_yard_length, penalty_area_width, penalty_area_length, circle_radius, corner_radius, penalty_spot_distance, penalty_arc_radius, pitch_length=None, pitch_width=None)

Specifies the dimensions of a pitch.

ATTRIBUTE DESCRIPTION
x_dim

Limits of pitch boundaries in longitudinal direction.

TYPE: Dimension

y_dim

Limits of pitch boundaries in lateral direction.

TYPE: Dimension

standardized

Used to denote standardized pitch dimensions where data is scaled along the axes independent of the actual dimensions of the pitch. To get non-distored calculations, the length and width of the pitch need to be specified.

TYPE: bool

unit

The unit in which distances are measured along the axes of the pitch.

TYPE: Unit

goal_width

Width of the goal.

TYPE: float

goal_height

Height of the goal.

TYPE: Optional[float]

six_yard_width

Width of the six yard box.

TYPE: float

six_yard_length

Length of the six yard box.

TYPE: float

penalty_area_width

Width of the penalty area.

TYPE: float

penalty_area_length

Length of the penalty area.

TYPE: float

circle_radius

Radius of the center circle (in the longitudinal direction).

TYPE: float

corner_radius

Radius of the corner arcs.

TYPE: float

penalty_spot_distance

Distance from the goal line to the penalty spot.

TYPE: float

penalty_arc_radius

Radius of the penalty arc (in the longitudinal direction).

TYPE: float

pitch_length

True length of the pitch, in meters.

TYPE: Optional[float]

pitch_width

True width of the pitch, in meters.

TYPE: Optional[float]

x_dim instance-attribute

x_dim

y_dim instance-attribute

y_dim

standardized instance-attribute

standardized

unit instance-attribute

unit

goal_width instance-attribute

goal_width

goal_height instance-attribute

goal_height

six_yard_width instance-attribute

six_yard_width

six_yard_length instance-attribute

six_yard_length

penalty_area_width instance-attribute

penalty_area_width

penalty_area_length instance-attribute

penalty_area_length

circle_radius instance-attribute

circle_radius

corner_radius instance-attribute

corner_radius

penalty_spot_distance instance-attribute

penalty_spot_distance

penalty_arc_radius instance-attribute

penalty_arc_radius

pitch_length class-attribute instance-attribute

pitch_length = None

pitch_width class-attribute instance-attribute

pitch_width = None

convert

convert(to_unit)

Convert the pitch dimensions to another unit.

PARAMETER DESCRIPTION
to_unit

The unit to convert to

TYPE: Unit

RETURNS DESCRIPTION
PitchDimensions

The pitch dimensions in the target unit

Source code in kloppy/domain/models/pitch.py
def convert(self, to_unit: Unit) -> "PitchDimensions":
    """Convert the pitch dimensions to another unit.

    Arguments:
        to_unit: The unit to convert to

    Returns:
        The pitch dimensions in the target unit
    """
    return PitchDimensions(
        x_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.x_dim.min)
                if self.x_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.x_dim.max)
                if self.x_dim.max is not None
                else None
            ),
        ),
        y_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.y_dim.min)
                if self.y_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.y_dim.max)
                if self.y_dim.max is not None
                else None
            ),
        ),
        standardized=self.standardized,
        unit=to_unit,
        goal_width=self.unit.convert(to_unit, self.goal_width),
        goal_height=(
            self.unit.convert(to_unit, self.goal_height)
            if self.goal_height is not None
            else None
        ),
        six_yard_width=self.unit.convert(to_unit, self.six_yard_width),
        six_yard_length=self.unit.convert(to_unit, self.six_yard_length),
        penalty_area_width=self.unit.convert(
            to_unit, self.penalty_area_width
        ),
        penalty_area_length=self.unit.convert(
            to_unit, self.penalty_area_length
        ),
        circle_radius=self.unit.convert(to_unit, self.circle_radius),
        corner_radius=self.unit.convert(to_unit, self.corner_radius),
        penalty_spot_distance=self.unit.convert(
            to_unit, self.penalty_spot_distance
        ),
        penalty_arc_radius=self.unit.convert(
            to_unit, self.penalty_arc_radius
        ),
        pitch_length=self.pitch_length,
        pitch_width=self.pitch_width,
    )

to_metric_base

to_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from this pitch dimensions to the IFAB pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the IFAB pitch dimensions

Source code in kloppy/domain/models/pitch.py
def to_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from this pitch dimensions to the IFAB pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the IFAB pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_from_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_from_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, from_zones, from_length, ifab_zones, ifab_length):
        mirror = False
        if v > from_zones[-1][1]:
            v = from_length - (v - from_zones[0][0]) + from_zones[0][0]
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(from_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in IFAB dimensions
                (ifab_zones[zone][1] - ifab_zones[zone][0])
                # length of the zone in the original dimensions
                / (from_zones[zone][1] - from_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            ifab = ifab_zones[zone][0] + (v - from_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            ifab = ifab_zones[0][0] + (v - from_zones[0][0]) * (
                ifab_length / from_length
            )
        if mirror:
            ifab = ifab_length - ifab
        return ifab

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * 2.44 / self.goal_height
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

from_metric_base

from_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from the IFAB pitch dimensions to this pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the regular pitch dimensions

Source code in kloppy/domain/models/pitch.py
def from_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from the IFAB pitch dimensions to this pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the regular pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_to_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_to_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, to_zones, to_length, ifab_zones, ifab_length):
        mirror = False
        if v > ifab_length / 2:
            v = ifab_length - v
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(ifab_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in the original dimensions
                (to_zones[zone][1] - to_zones[zone][0])
                # length of the zone in IFAB dimensions
                / (ifab_zones[zone][1] - ifab_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            v = to_zones[zone][0] + (v - ifab_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            v = to_zones[0][0] + (v - ifab_zones[0][0]) * (
                to_length / ifab_length
            )
        if mirror:
            v = (to_length + to_zones[0][0] - v) + to_zones[0][0]
        return v

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * self.goal_height / 2.44
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

distance_between

distance_between(point1, point2, unit=METERS)

Calculate the distance between two points in the coordinate system.

PARAMETER DESCRIPTION
point1

The first point

TYPE: Point

point2

The second point

TYPE: Point

unit

The unit to measure the distance in

TYPE: Unit DEFAULT: METERS

RETURNS DESCRIPTION
float

The distance between the two points in the given unit

Source code in kloppy/domain/models/pitch.py
def distance_between(
    self, point1: Point, point2: Point, unit: Unit = Unit.METERS
) -> float:
    """
    Calculate the distance between two points in the coordinate system.

    Arguments:
        point1: The first point
        point2: The second point
        unit: The unit to measure the distance in

    Returns:
        The distance between the two points in the given unit
    """
    if self.pitch_length is None or self.pitch_width is None:
        warnings.warn(
            "The pitch length and width are not specified. "
            "Assuming a standard pitch size of 105x68 meters. "
            "This may lead to incorrect results.",
            stacklevel=2,
        )
        pitch_length = DEFAULT_PITCH_LENGTH
        pitch_width = DEFAULT_PITCH_WIDTH
    else:
        pitch_length = self.pitch_length
        pitch_width = self.pitch_width
    point1_ifab = self.to_metric_base(point1, pitch_length, pitch_width)
    point2_ifab = self.to_metric_base(point2, pitch_length, pitch_width)
    dist = point1_ifab.distance_to(point2_ifab)
    return Unit.METERS.convert(unit, dist)

kloppy.domain.MetricPitchDimensions dataclass

MetricPitchDimensions(x_dim, y_dim, standardized, unit=METERS, goal_width=7.32, goal_height=2.44, six_yard_width=18.32, six_yard_length=5.5, penalty_area_width=40.32, penalty_area_length=16.5, circle_radius=9.15, corner_radius=1, penalty_spot_distance=11, penalty_arc_radius=9.15, pitch_length=None, pitch_width=None)

Bases: PitchDimensions

The standard pitch dimensions in meters by IFAB regulations.

For national matches, the length of the pitch can be between 90 and 120 meters, and the width can be between 45 and 90 meters. For international matches, the length can be between 100 and 110 meters, and the width can be between 64 and 75 meters. All other dimensions are fixed.

See https://www.theifab.com/laws/latest/the-field-of-play.

unit class-attribute instance-attribute

unit = METERS

goal_width class-attribute instance-attribute

goal_width = 7.32

goal_height class-attribute instance-attribute

goal_height = 2.44

six_yard_width class-attribute instance-attribute

six_yard_width = 18.32

six_yard_length class-attribute instance-attribute

six_yard_length = 5.5

penalty_area_width class-attribute instance-attribute

penalty_area_width = 40.32

penalty_area_length class-attribute instance-attribute

penalty_area_length = 16.5

circle_radius class-attribute instance-attribute

circle_radius = 9.15

corner_radius class-attribute instance-attribute

corner_radius = 1

penalty_spot_distance class-attribute instance-attribute

penalty_spot_distance = 11

penalty_arc_radius class-attribute instance-attribute

penalty_arc_radius = 9.15

x_dim instance-attribute

x_dim

y_dim instance-attribute

y_dim

standardized instance-attribute

standardized

pitch_length class-attribute instance-attribute

pitch_length = None

pitch_width class-attribute instance-attribute

pitch_width = None

convert

convert(to_unit)

Convert the pitch dimensions to another unit.

PARAMETER DESCRIPTION
to_unit

The unit to convert to

TYPE: Unit

RETURNS DESCRIPTION
PitchDimensions

The pitch dimensions in the target unit

Source code in kloppy/domain/models/pitch.py
def convert(self, to_unit: Unit) -> "PitchDimensions":
    """Convert the pitch dimensions to another unit.

    Arguments:
        to_unit: The unit to convert to

    Returns:
        The pitch dimensions in the target unit
    """
    return PitchDimensions(
        x_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.x_dim.min)
                if self.x_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.x_dim.max)
                if self.x_dim.max is not None
                else None
            ),
        ),
        y_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.y_dim.min)
                if self.y_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.y_dim.max)
                if self.y_dim.max is not None
                else None
            ),
        ),
        standardized=self.standardized,
        unit=to_unit,
        goal_width=self.unit.convert(to_unit, self.goal_width),
        goal_height=(
            self.unit.convert(to_unit, self.goal_height)
            if self.goal_height is not None
            else None
        ),
        six_yard_width=self.unit.convert(to_unit, self.six_yard_width),
        six_yard_length=self.unit.convert(to_unit, self.six_yard_length),
        penalty_area_width=self.unit.convert(
            to_unit, self.penalty_area_width
        ),
        penalty_area_length=self.unit.convert(
            to_unit, self.penalty_area_length
        ),
        circle_radius=self.unit.convert(to_unit, self.circle_radius),
        corner_radius=self.unit.convert(to_unit, self.corner_radius),
        penalty_spot_distance=self.unit.convert(
            to_unit, self.penalty_spot_distance
        ),
        penalty_arc_radius=self.unit.convert(
            to_unit, self.penalty_arc_radius
        ),
        pitch_length=self.pitch_length,
        pitch_width=self.pitch_width,
    )

to_metric_base

to_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from this pitch dimensions to the IFAB pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the IFAB pitch dimensions

Source code in kloppy/domain/models/pitch.py
def to_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from this pitch dimensions to the IFAB pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the IFAB pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_from_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_from_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, from_zones, from_length, ifab_zones, ifab_length):
        mirror = False
        if v > from_zones[-1][1]:
            v = from_length - (v - from_zones[0][0]) + from_zones[0][0]
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(from_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in IFAB dimensions
                (ifab_zones[zone][1] - ifab_zones[zone][0])
                # length of the zone in the original dimensions
                / (from_zones[zone][1] - from_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            ifab = ifab_zones[zone][0] + (v - from_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            ifab = ifab_zones[0][0] + (v - from_zones[0][0]) * (
                ifab_length / from_length
            )
        if mirror:
            ifab = ifab_length - ifab
        return ifab

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * 2.44 / self.goal_height
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

from_metric_base

from_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from the IFAB pitch dimensions to this pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the regular pitch dimensions

Source code in kloppy/domain/models/pitch.py
def from_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from the IFAB pitch dimensions to this pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the regular pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_to_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_to_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, to_zones, to_length, ifab_zones, ifab_length):
        mirror = False
        if v > ifab_length / 2:
            v = ifab_length - v
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(ifab_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in the original dimensions
                (to_zones[zone][1] - to_zones[zone][0])
                # length of the zone in IFAB dimensions
                / (ifab_zones[zone][1] - ifab_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            v = to_zones[zone][0] + (v - ifab_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            v = to_zones[0][0] + (v - ifab_zones[0][0]) * (
                to_length / ifab_length
            )
        if mirror:
            v = (to_length + to_zones[0][0] - v) + to_zones[0][0]
        return v

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * self.goal_height / 2.44
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

distance_between

distance_between(point1, point2, unit=METERS)

Calculate the distance between two points in the coordinate system.

PARAMETER DESCRIPTION
point1

The first point

TYPE: Point

point2

The second point

TYPE: Point

unit

The unit to measure the distance in

TYPE: Unit DEFAULT: METERS

RETURNS DESCRIPTION
float

The distance between the two points in the given unit

Source code in kloppy/domain/models/pitch.py
def distance_between(
    self, point1: Point, point2: Point, unit: Unit = Unit.METERS
) -> float:
    """
    Calculate the distance between two points in the coordinate system.

    Arguments:
        point1: The first point
        point2: The second point
        unit: The unit to measure the distance in

    Returns:
        The distance between the two points in the given unit
    """
    if self.pitch_length is None or self.pitch_width is None:
        warnings.warn(
            "The pitch length and width are not specified. "
            "Assuming a standard pitch size of 105x68 meters. "
            "This may lead to incorrect results.",
            stacklevel=2,
        )
        pitch_length = DEFAULT_PITCH_LENGTH
        pitch_width = DEFAULT_PITCH_WIDTH
    else:
        pitch_length = self.pitch_length
        pitch_width = self.pitch_width
    point1_ifab = self.to_metric_base(point1, pitch_length, pitch_width)
    point2_ifab = self.to_metric_base(point2, pitch_length, pitch_width)
    dist = point1_ifab.distance_to(point2_ifab)
    return Unit.METERS.convert(unit, dist)

kloppy.domain.ImperialPitchDimensions dataclass

ImperialPitchDimensions(x_dim, y_dim, standardized, unit=YARDS, goal_width=8, goal_height=2.66, six_yard_width=20, six_yard_length=6, penalty_area_width=44, penalty_area_length=18, circle_radius=10, corner_radius=1, penalty_spot_distance=12, penalty_arc_radius=10, pitch_length=None, pitch_width=None)

Bases: PitchDimensions

The standard pitch dimensions in yards by IFAB regulations.

For national matches, the length of the pitch can be between 100 and 130 yards, and the width can be between 50 and 100 yards. For international matches, the length can be between 110 and 120 yards, and the width can be between 70 and 80 yards. All other dimensions are fixed.

See https://www.theifab.com/laws/latest/the-field-of-play.

unit class-attribute instance-attribute

unit = YARDS

goal_width class-attribute instance-attribute

goal_width = 8

goal_height class-attribute instance-attribute

goal_height = 2.66

six_yard_width class-attribute instance-attribute

six_yard_width = 20

six_yard_length class-attribute instance-attribute

six_yard_length = 6

penalty_area_width class-attribute instance-attribute

penalty_area_width = 44

penalty_area_length class-attribute instance-attribute

penalty_area_length = 18

circle_radius class-attribute instance-attribute

circle_radius = 10

corner_radius class-attribute instance-attribute

corner_radius = 1

penalty_spot_distance class-attribute instance-attribute

penalty_spot_distance = 12

penalty_arc_radius class-attribute instance-attribute

penalty_arc_radius = 10

x_dim instance-attribute

x_dim

y_dim instance-attribute

y_dim

standardized instance-attribute

standardized

pitch_length class-attribute instance-attribute

pitch_length = None

pitch_width class-attribute instance-attribute

pitch_width = None

convert

convert(to_unit)

Convert the pitch dimensions to another unit.

PARAMETER DESCRIPTION
to_unit

The unit to convert to

TYPE: Unit

RETURNS DESCRIPTION
PitchDimensions

The pitch dimensions in the target unit

Source code in kloppy/domain/models/pitch.py
def convert(self, to_unit: Unit) -> "PitchDimensions":
    """Convert the pitch dimensions to another unit.

    Arguments:
        to_unit: The unit to convert to

    Returns:
        The pitch dimensions in the target unit
    """
    return PitchDimensions(
        x_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.x_dim.min)
                if self.x_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.x_dim.max)
                if self.x_dim.max is not None
                else None
            ),
        ),
        y_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.y_dim.min)
                if self.y_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.y_dim.max)
                if self.y_dim.max is not None
                else None
            ),
        ),
        standardized=self.standardized,
        unit=to_unit,
        goal_width=self.unit.convert(to_unit, self.goal_width),
        goal_height=(
            self.unit.convert(to_unit, self.goal_height)
            if self.goal_height is not None
            else None
        ),
        six_yard_width=self.unit.convert(to_unit, self.six_yard_width),
        six_yard_length=self.unit.convert(to_unit, self.six_yard_length),
        penalty_area_width=self.unit.convert(
            to_unit, self.penalty_area_width
        ),
        penalty_area_length=self.unit.convert(
            to_unit, self.penalty_area_length
        ),
        circle_radius=self.unit.convert(to_unit, self.circle_radius),
        corner_radius=self.unit.convert(to_unit, self.corner_radius),
        penalty_spot_distance=self.unit.convert(
            to_unit, self.penalty_spot_distance
        ),
        penalty_arc_radius=self.unit.convert(
            to_unit, self.penalty_arc_radius
        ),
        pitch_length=self.pitch_length,
        pitch_width=self.pitch_width,
    )

to_metric_base

to_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from this pitch dimensions to the IFAB pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the IFAB pitch dimensions

Source code in kloppy/domain/models/pitch.py
def to_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from this pitch dimensions to the IFAB pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the IFAB pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_from_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_from_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, from_zones, from_length, ifab_zones, ifab_length):
        mirror = False
        if v > from_zones[-1][1]:
            v = from_length - (v - from_zones[0][0]) + from_zones[0][0]
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(from_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in IFAB dimensions
                (ifab_zones[zone][1] - ifab_zones[zone][0])
                # length of the zone in the original dimensions
                / (from_zones[zone][1] - from_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            ifab = ifab_zones[zone][0] + (v - from_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            ifab = ifab_zones[0][0] + (v - from_zones[0][0]) * (
                ifab_length / from_length
            )
        if mirror:
            ifab = ifab_length - ifab
        return ifab

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * 2.44 / self.goal_height
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

from_metric_base

from_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from the IFAB pitch dimensions to this pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the regular pitch dimensions

Source code in kloppy/domain/models/pitch.py
def from_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from the IFAB pitch dimensions to this pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the regular pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_to_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_to_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, to_zones, to_length, ifab_zones, ifab_length):
        mirror = False
        if v > ifab_length / 2:
            v = ifab_length - v
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(ifab_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in the original dimensions
                (to_zones[zone][1] - to_zones[zone][0])
                # length of the zone in IFAB dimensions
                / (ifab_zones[zone][1] - ifab_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            v = to_zones[zone][0] + (v - ifab_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            v = to_zones[0][0] + (v - ifab_zones[0][0]) * (
                to_length / ifab_length
            )
        if mirror:
            v = (to_length + to_zones[0][0] - v) + to_zones[0][0]
        return v

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * self.goal_height / 2.44
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

distance_between

distance_between(point1, point2, unit=METERS)

Calculate the distance between two points in the coordinate system.

PARAMETER DESCRIPTION
point1

The first point

TYPE: Point

point2

The second point

TYPE: Point

unit

The unit to measure the distance in

TYPE: Unit DEFAULT: METERS

RETURNS DESCRIPTION
float

The distance between the two points in the given unit

Source code in kloppy/domain/models/pitch.py
def distance_between(
    self, point1: Point, point2: Point, unit: Unit = Unit.METERS
) -> float:
    """
    Calculate the distance between two points in the coordinate system.

    Arguments:
        point1: The first point
        point2: The second point
        unit: The unit to measure the distance in

    Returns:
        The distance between the two points in the given unit
    """
    if self.pitch_length is None or self.pitch_width is None:
        warnings.warn(
            "The pitch length and width are not specified. "
            "Assuming a standard pitch size of 105x68 meters. "
            "This may lead to incorrect results.",
            stacklevel=2,
        )
        pitch_length = DEFAULT_PITCH_LENGTH
        pitch_width = DEFAULT_PITCH_WIDTH
    else:
        pitch_length = self.pitch_length
        pitch_width = self.pitch_width
    point1_ifab = self.to_metric_base(point1, pitch_length, pitch_width)
    point2_ifab = self.to_metric_base(point2, pitch_length, pitch_width)
    dist = point1_ifab.distance_to(point2_ifab)
    return Unit.METERS.convert(unit, dist)

kloppy.domain.NormalizedPitchDimensions dataclass

NormalizedPitchDimensions(x_dim=Dimension(0, 1), y_dim=Dimension(0, 1), standardized=False, unit=NORMED, goal_width, goal_height, six_yard_width, six_yard_length, penalty_area_width, penalty_area_length, circle_radius, corner_radius, penalty_spot_distance, penalty_arc_radius, pitch_length=None, pitch_width=None)

Bases: MetricPitchDimensions

The standard pitch dimensions in normalized units.

The pitch dimensions are normalized to a unit square, where the length and width of the pitch are 1. All other dimensions are scaled accordingly.

x_dim class-attribute instance-attribute

x_dim = Dimension(0, 1)

y_dim class-attribute instance-attribute

y_dim = Dimension(0, 1)

standardized class-attribute instance-attribute

standardized = False

unit class-attribute instance-attribute

unit = NORMED

goal_width instance-attribute

goal_width

goal_height instance-attribute

goal_height

six_yard_width instance-attribute

six_yard_width

six_yard_length instance-attribute

six_yard_length

penalty_area_width instance-attribute

penalty_area_width

penalty_area_length instance-attribute

penalty_area_length

circle_radius instance-attribute

circle_radius

corner_radius instance-attribute

corner_radius

penalty_spot_distance instance-attribute

penalty_spot_distance

penalty_arc_radius instance-attribute

penalty_arc_radius

pitch_length class-attribute instance-attribute

pitch_length = None

pitch_width class-attribute instance-attribute

pitch_width = None

convert

convert(to_unit)

Convert the pitch dimensions to another unit.

PARAMETER DESCRIPTION
to_unit

The unit to convert to

TYPE: Unit

RETURNS DESCRIPTION
PitchDimensions

The pitch dimensions in the target unit

Source code in kloppy/domain/models/pitch.py
def convert(self, to_unit: Unit) -> "PitchDimensions":
    """Convert the pitch dimensions to another unit.

    Arguments:
        to_unit: The unit to convert to

    Returns:
        The pitch dimensions in the target unit
    """
    return PitchDimensions(
        x_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.x_dim.min)
                if self.x_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.x_dim.max)
                if self.x_dim.max is not None
                else None
            ),
        ),
        y_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.y_dim.min)
                if self.y_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.y_dim.max)
                if self.y_dim.max is not None
                else None
            ),
        ),
        standardized=self.standardized,
        unit=to_unit,
        goal_width=self.unit.convert(to_unit, self.goal_width),
        goal_height=(
            self.unit.convert(to_unit, self.goal_height)
            if self.goal_height is not None
            else None
        ),
        six_yard_width=self.unit.convert(to_unit, self.six_yard_width),
        six_yard_length=self.unit.convert(to_unit, self.six_yard_length),
        penalty_area_width=self.unit.convert(
            to_unit, self.penalty_area_width
        ),
        penalty_area_length=self.unit.convert(
            to_unit, self.penalty_area_length
        ),
        circle_radius=self.unit.convert(to_unit, self.circle_radius),
        corner_radius=self.unit.convert(to_unit, self.corner_radius),
        penalty_spot_distance=self.unit.convert(
            to_unit, self.penalty_spot_distance
        ),
        penalty_arc_radius=self.unit.convert(
            to_unit, self.penalty_arc_radius
        ),
        pitch_length=self.pitch_length,
        pitch_width=self.pitch_width,
    )

to_metric_base

to_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from this pitch dimensions to the IFAB pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the IFAB pitch dimensions

Source code in kloppy/domain/models/pitch.py
def to_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from this pitch dimensions to the IFAB pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the IFAB pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_from_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_from_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, from_zones, from_length, ifab_zones, ifab_length):
        mirror = False
        if v > from_zones[-1][1]:
            v = from_length - (v - from_zones[0][0]) + from_zones[0][0]
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(from_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in IFAB dimensions
                (ifab_zones[zone][1] - ifab_zones[zone][0])
                # length of the zone in the original dimensions
                / (from_zones[zone][1] - from_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            ifab = ifab_zones[zone][0] + (v - from_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            ifab = ifab_zones[0][0] + (v - from_zones[0][0]) * (
                ifab_length / from_length
            )
        if mirror:
            ifab = ifab_length - ifab
        return ifab

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * 2.44 / self.goal_height
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

from_metric_base

from_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from the IFAB pitch dimensions to this pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the regular pitch dimensions

Source code in kloppy/domain/models/pitch.py
def from_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from the IFAB pitch dimensions to this pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the regular pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_to_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_to_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, to_zones, to_length, ifab_zones, ifab_length):
        mirror = False
        if v > ifab_length / 2:
            v = ifab_length - v
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(ifab_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in the original dimensions
                (to_zones[zone][1] - to_zones[zone][0])
                # length of the zone in IFAB dimensions
                / (ifab_zones[zone][1] - ifab_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            v = to_zones[zone][0] + (v - ifab_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            v = to_zones[0][0] + (v - ifab_zones[0][0]) * (
                to_length / ifab_length
            )
        if mirror:
            v = (to_length + to_zones[0][0] - v) + to_zones[0][0]
        return v

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * self.goal_height / 2.44
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

distance_between

distance_between(point1, point2, unit=METERS)

Calculate the distance between two points in the coordinate system.

PARAMETER DESCRIPTION
point1

The first point

TYPE: Point

point2

The second point

TYPE: Point

unit

The unit to measure the distance in

TYPE: Unit DEFAULT: METERS

RETURNS DESCRIPTION
float

The distance between the two points in the given unit

Source code in kloppy/domain/models/pitch.py
def distance_between(
    self, point1: Point, point2: Point, unit: Unit = Unit.METERS
) -> float:
    """
    Calculate the distance between two points in the coordinate system.

    Arguments:
        point1: The first point
        point2: The second point
        unit: The unit to measure the distance in

    Returns:
        The distance between the two points in the given unit
    """
    if self.pitch_length is None or self.pitch_width is None:
        warnings.warn(
            "The pitch length and width are not specified. "
            "Assuming a standard pitch size of 105x68 meters. "
            "This may lead to incorrect results.",
            stacklevel=2,
        )
        pitch_length = DEFAULT_PITCH_LENGTH
        pitch_width = DEFAULT_PITCH_WIDTH
    else:
        pitch_length = self.pitch_length
        pitch_width = self.pitch_width
    point1_ifab = self.to_metric_base(point1, pitch_length, pitch_width)
    point2_ifab = self.to_metric_base(point2, pitch_length, pitch_width)
    dist = point1_ifab.distance_to(point2_ifab)
    return Unit.METERS.convert(unit, dist)

kloppy.domain.OptaPitchDimensions dataclass

OptaPitchDimensions(x_dim=Dimension(0, 100), y_dim=Dimension(0, 100), standardized=True, unit=NORMED, goal_width=9.6, goal_height=38, six_yard_width=26.4, six_yard_length=5.8, penalty_area_width=57.8, penalty_area_length=17.0, circle_radius=9.0, corner_radius=0.97, penalty_spot_distance=11.5, penalty_arc_radius=8.9, pitch_length=None, pitch_width=None)

Bases: PitchDimensions

The pitch dimensions used by Opta.

x_dim class-attribute instance-attribute

x_dim = Dimension(0, 100)

y_dim class-attribute instance-attribute

y_dim = Dimension(0, 100)

standardized class-attribute instance-attribute

standardized = True

unit class-attribute instance-attribute

unit = NORMED

goal_width class-attribute instance-attribute

goal_width = 9.6

goal_height class-attribute instance-attribute

goal_height = 38

six_yard_width class-attribute instance-attribute

six_yard_width = 26.4

six_yard_length class-attribute instance-attribute

six_yard_length = 5.8

penalty_area_width class-attribute instance-attribute

penalty_area_width = 57.8

penalty_area_length class-attribute instance-attribute

penalty_area_length = 17.0

circle_radius class-attribute instance-attribute

circle_radius = 9.0

corner_radius class-attribute instance-attribute

corner_radius = 0.97

penalty_spot_distance class-attribute instance-attribute

penalty_spot_distance = 11.5

penalty_arc_radius class-attribute instance-attribute

penalty_arc_radius = 8.9

pitch_length class-attribute instance-attribute

pitch_length = None

pitch_width class-attribute instance-attribute

pitch_width = None

convert

convert(to_unit)

Convert the pitch dimensions to another unit.

PARAMETER DESCRIPTION
to_unit

The unit to convert to

TYPE: Unit

RETURNS DESCRIPTION
PitchDimensions

The pitch dimensions in the target unit

Source code in kloppy/domain/models/pitch.py
def convert(self, to_unit: Unit) -> "PitchDimensions":
    """Convert the pitch dimensions to another unit.

    Arguments:
        to_unit: The unit to convert to

    Returns:
        The pitch dimensions in the target unit
    """
    return PitchDimensions(
        x_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.x_dim.min)
                if self.x_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.x_dim.max)
                if self.x_dim.max is not None
                else None
            ),
        ),
        y_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.y_dim.min)
                if self.y_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.y_dim.max)
                if self.y_dim.max is not None
                else None
            ),
        ),
        standardized=self.standardized,
        unit=to_unit,
        goal_width=self.unit.convert(to_unit, self.goal_width),
        goal_height=(
            self.unit.convert(to_unit, self.goal_height)
            if self.goal_height is not None
            else None
        ),
        six_yard_width=self.unit.convert(to_unit, self.six_yard_width),
        six_yard_length=self.unit.convert(to_unit, self.six_yard_length),
        penalty_area_width=self.unit.convert(
            to_unit, self.penalty_area_width
        ),
        penalty_area_length=self.unit.convert(
            to_unit, self.penalty_area_length
        ),
        circle_radius=self.unit.convert(to_unit, self.circle_radius),
        corner_radius=self.unit.convert(to_unit, self.corner_radius),
        penalty_spot_distance=self.unit.convert(
            to_unit, self.penalty_spot_distance
        ),
        penalty_arc_radius=self.unit.convert(
            to_unit, self.penalty_arc_radius
        ),
        pitch_length=self.pitch_length,
        pitch_width=self.pitch_width,
    )

to_metric_base

to_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from this pitch dimensions to the IFAB pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the IFAB pitch dimensions

Source code in kloppy/domain/models/pitch.py
def to_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from this pitch dimensions to the IFAB pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the IFAB pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_from_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_from_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, from_zones, from_length, ifab_zones, ifab_length):
        mirror = False
        if v > from_zones[-1][1]:
            v = from_length - (v - from_zones[0][0]) + from_zones[0][0]
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(from_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in IFAB dimensions
                (ifab_zones[zone][1] - ifab_zones[zone][0])
                # length of the zone in the original dimensions
                / (from_zones[zone][1] - from_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            ifab = ifab_zones[zone][0] + (v - from_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            ifab = ifab_zones[0][0] + (v - from_zones[0][0]) * (
                ifab_length / from_length
            )
        if mirror:
            ifab = ifab_length - ifab
        return ifab

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * 2.44 / self.goal_height
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

from_metric_base

from_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from the IFAB pitch dimensions to this pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the regular pitch dimensions

Source code in kloppy/domain/models/pitch.py
def from_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from the IFAB pitch dimensions to this pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the regular pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_to_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_to_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, to_zones, to_length, ifab_zones, ifab_length):
        mirror = False
        if v > ifab_length / 2:
            v = ifab_length - v
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(ifab_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in the original dimensions
                (to_zones[zone][1] - to_zones[zone][0])
                # length of the zone in IFAB dimensions
                / (ifab_zones[zone][1] - ifab_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            v = to_zones[zone][0] + (v - ifab_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            v = to_zones[0][0] + (v - ifab_zones[0][0]) * (
                to_length / ifab_length
            )
        if mirror:
            v = (to_length + to_zones[0][0] - v) + to_zones[0][0]
        return v

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * self.goal_height / 2.44
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

distance_between

distance_between(point1, point2, unit=METERS)

Calculate the distance between two points in the coordinate system.

PARAMETER DESCRIPTION
point1

The first point

TYPE: Point

point2

The second point

TYPE: Point

unit

The unit to measure the distance in

TYPE: Unit DEFAULT: METERS

RETURNS DESCRIPTION
float

The distance between the two points in the given unit

Source code in kloppy/domain/models/pitch.py
def distance_between(
    self, point1: Point, point2: Point, unit: Unit = Unit.METERS
) -> float:
    """
    Calculate the distance between two points in the coordinate system.

    Arguments:
        point1: The first point
        point2: The second point
        unit: The unit to measure the distance in

    Returns:
        The distance between the two points in the given unit
    """
    if self.pitch_length is None or self.pitch_width is None:
        warnings.warn(
            "The pitch length and width are not specified. "
            "Assuming a standard pitch size of 105x68 meters. "
            "This may lead to incorrect results.",
            stacklevel=2,
        )
        pitch_length = DEFAULT_PITCH_LENGTH
        pitch_width = DEFAULT_PITCH_WIDTH
    else:
        pitch_length = self.pitch_length
        pitch_width = self.pitch_width
    point1_ifab = self.to_metric_base(point1, pitch_length, pitch_width)
    point2_ifab = self.to_metric_base(point2, pitch_length, pitch_width)
    dist = point1_ifab.distance_to(point2_ifab)
    return Unit.METERS.convert(unit, dist)

kloppy.domain.WyscoutPitchDimensions dataclass

WyscoutPitchDimensions(x_dim=Dimension(0, 100), y_dim=Dimension(0, 100), standardized=True, unit=NORMED, goal_width=12.0, goal_height=None, six_yard_width=26.0, six_yard_length=6.0, penalty_area_width=62.0, penalty_area_length=16.0, circle_radius=8.84, corner_radius=0.97, penalty_spot_distance=10.0, penalty_arc_radius=7.74, pitch_length=None, pitch_width=None)

Bases: PitchDimensions

The pitch dimensions used by Wyscout.

x_dim class-attribute instance-attribute

x_dim = Dimension(0, 100)

y_dim class-attribute instance-attribute

y_dim = Dimension(0, 100)

standardized class-attribute instance-attribute

standardized = True

unit class-attribute instance-attribute

unit = NORMED

goal_width class-attribute instance-attribute

goal_width = 12.0

goal_height class-attribute instance-attribute

goal_height = None

six_yard_width class-attribute instance-attribute

six_yard_width = 26.0

six_yard_length class-attribute instance-attribute

six_yard_length = 6.0

penalty_area_width class-attribute instance-attribute

penalty_area_width = 62.0

penalty_area_length class-attribute instance-attribute

penalty_area_length = 16.0

circle_radius class-attribute instance-attribute

circle_radius = 8.84

corner_radius class-attribute instance-attribute

corner_radius = 0.97

penalty_spot_distance class-attribute instance-attribute

penalty_spot_distance = 10.0

penalty_arc_radius class-attribute instance-attribute

penalty_arc_radius = 7.74

pitch_length class-attribute instance-attribute

pitch_length = None

pitch_width class-attribute instance-attribute

pitch_width = None

convert

convert(to_unit)

Convert the pitch dimensions to another unit.

PARAMETER DESCRIPTION
to_unit

The unit to convert to

TYPE: Unit

RETURNS DESCRIPTION
PitchDimensions

The pitch dimensions in the target unit

Source code in kloppy/domain/models/pitch.py
def convert(self, to_unit: Unit) -> "PitchDimensions":
    """Convert the pitch dimensions to another unit.

    Arguments:
        to_unit: The unit to convert to

    Returns:
        The pitch dimensions in the target unit
    """
    return PitchDimensions(
        x_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.x_dim.min)
                if self.x_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.x_dim.max)
                if self.x_dim.max is not None
                else None
            ),
        ),
        y_dim=Dimension(
            min=(
                self.unit.convert(to_unit, self.y_dim.min)
                if self.y_dim.min is not None
                else None
            ),
            max=(
                self.unit.convert(to_unit, self.y_dim.max)
                if self.y_dim.max is not None
                else None
            ),
        ),
        standardized=self.standardized,
        unit=to_unit,
        goal_width=self.unit.convert(to_unit, self.goal_width),
        goal_height=(
            self.unit.convert(to_unit, self.goal_height)
            if self.goal_height is not None
            else None
        ),
        six_yard_width=self.unit.convert(to_unit, self.six_yard_width),
        six_yard_length=self.unit.convert(to_unit, self.six_yard_length),
        penalty_area_width=self.unit.convert(
            to_unit, self.penalty_area_width
        ),
        penalty_area_length=self.unit.convert(
            to_unit, self.penalty_area_length
        ),
        circle_radius=self.unit.convert(to_unit, self.circle_radius),
        corner_radius=self.unit.convert(to_unit, self.corner_radius),
        penalty_spot_distance=self.unit.convert(
            to_unit, self.penalty_spot_distance
        ),
        penalty_arc_radius=self.unit.convert(
            to_unit, self.penalty_arc_radius
        ),
        pitch_length=self.pitch_length,
        pitch_width=self.pitch_width,
    )

to_metric_base

to_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from this pitch dimensions to the IFAB pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the IFAB pitch dimensions

Source code in kloppy/domain/models/pitch.py
def to_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from this pitch dimensions to the IFAB pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the IFAB pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_from_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_from_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, from_zones, from_length, ifab_zones, ifab_length):
        mirror = False
        if v > from_zones[-1][1]:
            v = from_length - (v - from_zones[0][0]) + from_zones[0][0]
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(from_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in IFAB dimensions
                (ifab_zones[zone][1] - ifab_zones[zone][0])
                # length of the zone in the original dimensions
                / (from_zones[zone][1] - from_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            ifab = ifab_zones[zone][0] + (v - from_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            ifab = ifab_zones[0][0] + (v - from_zones[0][0]) * (
                ifab_length / from_length
            )
        if mirror:
            ifab = ifab_length - ifab
        return ifab

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * 2.44 / self.goal_height
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_from_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_from_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

from_metric_base

from_metric_base(point, pitch_length=DEFAULT_PITCH_LENGTH, pitch_width=DEFAULT_PITCH_WIDTH)

Convert a point from the IFAB pitch dimensions to this pitch dimensions.

PARAMETER DESCRIPTION
point

The point to convert

TYPE: Point

RETURNS DESCRIPTION
Point

The point in the regular pitch dimensions

Source code in kloppy/domain/models/pitch.py
def from_metric_base(
    self,
    point: Point,
    pitch_length: float = DEFAULT_PITCH_LENGTH,
    pitch_width: float = DEFAULT_PITCH_WIDTH,
) -> Point:
    """
    Convert a point from the IFAB pitch dimensions to this pitch dimensions.

    Arguments:
        point: The point to convert

    Returns:
        The point in the regular pitch dimensions
    """
    if (
        self.x_dim.min is None
        or self.x_dim.max is None
        or self.y_dim.min is None
        or self.y_dim.max is None
    ):
        raise MissingDimensionError(
            "The pitch boundaries need to be fully specified to convert coordinates."
        )

    ifab_dims = MetricPitchDimensions(
        x_dim=Dimension(0, pitch_length),
        y_dim=Dimension(0, pitch_width),
        pitch_length=pitch_length,
        pitch_width=pitch_width,
        standardized=False,
    )
    x_ifab_zones = ifab_dims._transformation_zones_x(pitch_length)
    y_ifab_zones = ifab_dims._transformation_zones_y(pitch_width)
    x_to_zones = self._transformation_zones_x(
        self.x_dim.max - self.x_dim.min
    )
    y_to_zones = self._transformation_zones_y(
        self.y_dim.max - self.y_dim.min
    )

    def transform(v, to_zones, to_length, ifab_zones, ifab_length):
        mirror = False
        if v > ifab_length / 2:
            v = ifab_length - v
            mirror = True
        # find the zone the v coordinate is in
        try:
            zone = next(
                (
                    idx
                    for idx, zone in enumerate(ifab_zones)
                    if zone[0] <= v <= zone[1]
                )
            )
            scale = (
                # length of the zone in the original dimensions
                (to_zones[zone][1] - to_zones[zone][0])
                # length of the zone in IFAB dimensions
                / (ifab_zones[zone][1] - ifab_zones[zone][0])
            )
            # ifab = smallest IFAB value of the zone + (v - smallest v value of the zone) * scaling factor of the zone
            v = to_zones[zone][0] + (v - ifab_zones[zone][0]) * scale
        except StopIteration:
            # value is outside of the pitch dimensions
            v = to_zones[0][0] + (v - ifab_zones[0][0]) * (
                to_length / ifab_length
            )
        if mirror:
            v = (to_length + to_zones[0][0] - v) + to_zones[0][0]
        return v

    if isinstance(point, Point3D):
        return Point3D(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
            z=(
                (
                    point.z * self.goal_height / 2.44
                    if self.goal_height is not None
                    else point.z
                )
                if point.z is not None
                else None
            ),
        )
    else:
        return Point(
            x=transform(
                point.x,
                x_to_zones,
                self.x_dim.max - self.x_dim.min,
                x_ifab_zones,
                pitch_length,
            ),
            y=transform(
                point.y,
                y_to_zones,
                self.y_dim.max - self.y_dim.min,
                y_ifab_zones,
                pitch_width,
            ),
        )

distance_between

distance_between(point1, point2, unit=METERS)

Calculate the distance between two points in the coordinate system.

PARAMETER DESCRIPTION
point1

The first point

TYPE: Point

point2

The second point

TYPE: Point

unit

The unit to measure the distance in

TYPE: Unit DEFAULT: METERS

RETURNS DESCRIPTION
float

The distance between the two points in the given unit

Source code in kloppy/domain/models/pitch.py
def distance_between(
    self, point1: Point, point2: Point, unit: Unit = Unit.METERS
) -> float:
    """
    Calculate the distance between two points in the coordinate system.

    Arguments:
        point1: The first point
        point2: The second point
        unit: The unit to measure the distance in

    Returns:
        The distance between the two points in the given unit
    """
    if self.pitch_length is None or self.pitch_width is None:
        warnings.warn(
            "The pitch length and width are not specified. "
            "Assuming a standard pitch size of 105x68 meters. "
            "This may lead to incorrect results.",
            stacklevel=2,
        )
        pitch_length = DEFAULT_PITCH_LENGTH
        pitch_width = DEFAULT_PITCH_WIDTH
    else:
        pitch_length = self.pitch_length
        pitch_width = self.pitch_width
    point1_ifab = self.to_metric_base(point1, pitch_length, pitch_width)
    point2_ifab = self.to_metric_base(point2, pitch_length, pitch_width)
    dist = point1_ifab.distance_to(point2_ifab)
    return Unit.METERS.convert(unit, dist)