# Source code for pypdevsbbl.extra.spatial

    #  Copyright 2020 Modelling, Simulation and Design Lab (MSDL) at
    #  McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
    #
    #  Licensed under the Apache License, Version 2.0 (the "License");
    #  you may not use this file except in compliance with the License.
    #  You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    #  Unless required by applicable law or agreed to in writing, software
    #  distributed under the License is distributed on an "AS IS" BASIS,
    #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    #  See the License for the specific language governing permissions and
    #  limitations under the License.

    """This file contains additional classes w.r.t. spatial properties.

    Such properties include:
    - Coordinates
    - Distance computation
    - Multiple axes movement
    """

    import numpy as np

    class Coordinate:
        """Simple 3-dimensional coordinate.

        A coordinate in 3D will follow a cartesian coorinate system over
        3 axes: x, y and z.

        Args:
            x (numeric):    The x-value of the coordinate.
            y (numeric):    The y-value of the coordinate.
            z (numeric):    The z-value of the coordinate.
        """
        def __init__(self, x, y, z):
            self.x = x
            self.y = y
            self.z = z

        def __repr__(self):
            return "Coord(%.5f, %.5f, %.5f)" % (self.x, self.y, self.z)

    class distance:
        """Compute the distance between two points."""

        @staticmethod
        def euclidean(A, B):
            """Computes the Euclidean distance between :attr:`A` and :attr:`B`.

            Args:
                A (Coordinate): The first coordinate.
                B (Coordinate): The second coordinate.
            """
            return np.sqrt((A.x - B.x) ** 2 + (A.y - B.y) ** 2 + (A.z - B.z) ** 2)

        @staticmethod
        def manhattan(A, B):
            """Computes the Manhattan distance between :attr:`A` and :attr:`B`.

            Args:
                A (Coordinate): The first coordinate.
                B (Coordinate): The second coordinate.
            """
            return np.abs(A.x - B.x) + np.abs(A.y - B.y) + np.abs(A.z - B.z)

        @staticmethod
        def chebyshev(A, B):
            """Computes the Chebyshev distance between :attr:`A` and :attr:`B`.

            Args:
                A (Coordinate): The first coordinate.
                B (Coordinate): The second coordinate.
            """
            return np.max(np.abs(B.x - A.x), np.abs(B.y - A.y), np.abs(B.z - A.z))

        @staticmethod
        def minkowski(A, B, p=2):
            """Computes the Minkowski distance between :attr:`A` and :attr:`B`.

            Args:
                A (Coordinate): The first coordinate.
                B (Coordinate): The second coordinate.
                p (int):        The order of the distance. Must be greater than
                                or equal to 1. Defaults to 2 (= :meth:`euclidean`).
            """
            assert p >= 1
            return np.power((np.abs(B.x - A.x) ** p) + (np.abs(B.y - A.y) ** p) + (np.abs(B.z - A.z) ** p), 1.0 / p)