uim.model.helpers.spline API documentation
Description: Spline helpers Helper functions to interpolate list of coordinates.

# Module `uim.model.helpers.spline`

# Spline helpers

Helper functions to interpolate list of coordinates.

Expand source code

    # -*- coding: utf-8 -*-
    # Copyright © 2021 Wacom Authors. All Rights Reserved.
    #
    #  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.
    """
    Spline helpers
    ==============
    Helper functions to interpolate list of coordinates.
    """
    from typing import Tuple, List

    import numpy as np

    def catmull_rom_one_point(x: float, v0: float, v1: float, v2: float, v3: float) -> float:
        """
        Computes interpolated x-coord for given x-coord using Catmull-Rom.
        Computes an interpolated y-coordinate for the given x-coordinate between
        the support points v1 and v2. The neighboring support points v0 and v3 are
        used by Catmull-Rom to ensure a smooth transition between the spline
        segments.

        Parameters
        ----------
        x: ´float´
            The x-coord, for which the y-coord is needed
        v0: ´float´
            1st support point
        v1: ´float´
            2nd support point
        v2: ´float´
            3rd support point
        v3: ´float´
            4th support point

        Returns
        -------
        coord - ´float´
            Point
        """
        c1: float = 1. * v1
        c2: float = -.5 * v0 + .5 * v2
        c3: float = 1. * v0 + -2.5 * v1 + 2. * v2 - .5 * v3
        c4: float = -.5 * v0 + 1.5 * v1 + -1.5 * v2 + .5 * v3
        return ((c4 * x + c3) * x + c2) * x + c1

    def catmull_rom(p_x: List[float], p_y: List[float], res: int = 2) -> Tuple[List[float], List[float]]:
        """
        Computes Catmull-Rom Spline for given support points and resolution.

        Parameters
        ----------
        p_x: list
            Array of x-coords
        p_y: list
            Array of y-coords
        res: int
            Resolution of a segment (including the start point, but not the endpoint of the segment)

        Returns
        -------
        interp_x: list
            List of interpolated x values
        interp_y: list
            List of interpolated y values

        References
        ----------
        - [1] Wikipedia article on Catmull-Rom spline
                URL: https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline
        """
        # create arrays for spline points
        x_intpol: np.ndarray = np.empty(res * (len(p_x) - 1) + 1)
        y_intpol: np.ndarray = np.empty(res * (len(p_x) - 1) + 1)

        # set the last x- and y-coord, the others will be set in the loop
        x_intpol[-1] = p_x[-1]
        y_intpol[-1] = p_y[-1]

        # loop over segments (we have n-1 segments for n points)
        for i in range(len(p_x) - 1):
            # set x-coords
            x_intpol[i * res:(i + 1) * res] = np.linspace(
                p_x[i], p_x[i + 1], res, endpoint=False)
            if i == 0:
                # need to estimate an additional support point before the first
                y_intpol[:res] = np.array([
                    catmull_rom_one_point(
                        x,
                        p_y[0] - (p_y[1] - p_y[0]),  # estimated start point,
                        p_y[0],
                        p_y[1],
                        p_y[2])
                    for x in np.linspace(0., 1., res, endpoint=False)])
            elif i == len(p_x) - 2:
                # need to estimate an additional support point after the last
                y_intpol[i * res:-1] = np.array([
                    catmull_rom_one_point(
                        x,
                        p_y[i - 1],
                        p_y[i],
                        p_y[i + 1],
                        p_y[i + 1] + (p_y[i + 1] - p_y[i])  # estimated end point
                    ) for x in np.linspace(0., 1., res, endpoint=False)])
            else:
                y_intpol[i * res:(i + 1) * res] = np.array([
                    catmull_rom_one_point(
                        x,
                        p_y[i - 1],
                        p_y[i],
                        p_y[i + 1],
                        p_y[i + 2]) for x in np.linspace(0., 1., res, endpoint=False)])
        return x_intpol.tolist(), y_intpol.tolist()

    def linear_interpol(p_x: list, p_y: list) -> Tuple[List[float], List[float]]:
        """
        Linear interpolation of the first and the last point in array.

        Parameters
        ----------
        p_x: list -
            array of x-coordinates
        p_y: list -
            array of y-coordinates

        Returns
        --------
        interp_x: list
            List of linear interpolated x coordinates
        interp_y: list
            List of linear interpolated x coordinates
        """
        x_intpol = np.linspace(p_x[0], p_x[-1], 4)
        return x_intpol.tolist(), np.interp(x_intpol, p_x, p_y).tolist()

## Functions

`def catmull_rom(p_x: List[float], p_y: List[float], res: int = 2) ‑> Tuple[List[float], List[float]]`

  Computes Catmull-Rom Spline for given support points and resolution.

  ## Parameters

  `p_x` :`list`
    Array of x-coords
  `p_y` :`list`
    Array of y-coords
  `res` :`int`
    Resolution of a segment (including the start point, but not the endpoint of the segment)

  ## Returns

  `interp_x` :`list`
    List of interpolated x values
  `interp_y` :`list`
    List of interpolated y values

  ## References

  - [1] Wikipedia article on Catmull-Rom spline URL: https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline
  Expand source code

      def catmull_rom(p_x: List[float], p_y: List[float], res: int = 2) -> Tuple[List[float], List[float]]:
          """
          Computes Catmull-Rom Spline for given support points and resolution.

          Parameters
          ----------
          p_x: list
              Array of x-coords
          p_y: list
              Array of y-coords
          res: int
              Resolution of a segment (including the start point, but not the endpoint of the segment)

          Returns
          -------
          interp_x: list
              List of interpolated x values
          interp_y: list
              List of interpolated y values

          References
          ----------
          - [1] Wikipedia article on Catmull-Rom spline
                  URL: https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline
          """
          # create arrays for spline points
          x_intpol: np.ndarray = np.empty(res * (len(p_x) - 1) + 1)
          y_intpol: np.ndarray = np.empty(res * (len(p_x) - 1) + 1)

          # set the last x- and y-coord, the others will be set in the loop
          x_intpol[-1] = p_x[-1]
          y_intpol[-1] = p_y[-1]

          # loop over segments (we have n-1 segments for n points)
          for i in range(len(p_x) - 1):
              # set x-coords
              x_intpol[i * res:(i + 1) * res] = np.linspace(
                  p_x[i], p_x[i + 1], res, endpoint=False)
              if i == 0:
                  # need to estimate an additional support point before the first
                  y_intpol[:res] = np.array([
                      catmull_rom_one_point(
                          x,
                          p_y[0] - (p_y[1] - p_y[0]),  # estimated start point,
                          p_y[0],
                          p_y[1],
                          p_y[2])
                      for x in np.linspace(0., 1., res, endpoint=False)])
              elif i == len(p_x) - 2:
                  # need to estimate an additional support point after the last
                  y_intpol[i * res:-1] = np.array([
                      catmull_rom_one_point(
                          x,
                          p_y[i - 1],
                          p_y[i],
                          p_y[i + 1],
                          p_y[i + 1] + (p_y[i + 1] - p_y[i])  # estimated end point
                      ) for x in np.linspace(0., 1., res, endpoint=False)])
              else:
                  y_intpol[i * res:(i + 1) * res] = np.array([
                      catmull_rom_one_point(
                          x,
                          p_y[i - 1],
                          p_y[i],
                          p_y[i + 1],
                          p_y[i + 2]) for x in np.linspace(0., 1., res, endpoint=False)])
          return x_intpol.tolist(), y_intpol.tolist()

`def catmull_rom_one_point(x: float, v0: float, v1: float, v2: float, v3: float) ‑> float`

  Computes interpolated x-coord for given x-coord using Catmull-Rom. Computes an interpolated y-coordinate for the given x-coordinate between the support points v1 and v2. The neighboring support points v0 and v3 are used by Catmull-Rom to ensure a smooth transition between the spline segments.

  ## Parameters

  `x` :`´float´`
    The x-coord, for which the y-coord is needed
  `v0` :`´float´`
    1st support point
  `v1` :`´float´`
    2nd support point
  `v2` :`´float´`
    3rd support point
  `v3` :`´float´`
    4th support point

  ## Returns

  `coord - ´float´`
    Point
  Expand source code

      def catmull_rom_one_point(x: float, v0: float, v1: float, v2: float, v3: float) -> float:
          """
          Computes interpolated x-coord for given x-coord using Catmull-Rom.
          Computes an interpolated y-coordinate for the given x-coordinate between
          the support points v1 and v2. The neighboring support points v0 and v3 are
          used by Catmull-Rom to ensure a smooth transition between the spline
          segments.

          Parameters
          ----------
          x: ´float´
              The x-coord, for which the y-coord is needed
          v0: ´float´
              1st support point
          v1: ´float´
              2nd support point
          v2: ´float´
              3rd support point
          v3: ´float´
              4th support point

          Returns
          -------
          coord - ´float´
              Point
          """
          c1: float = 1. * v1
          c2: float = -.5 * v0 + .5 * v2
          c3: float = 1. * v0 + -2.5 * v1 + 2. * v2 - .5 * v3
          c4: float = -.5 * v0 + 1.5 * v1 + -1.5 * v2 + .5 * v3
          return ((c4 * x + c3) * x + c2) * x + c1

`def linear_interpol(p_x: list, p_y: list) ‑> Tuple[List[float], List[float]]`

  Linear interpolation of the first and the last point in array.

  ## Parameters

  `p_x` :`list -`
    array of x-coordinates
  `p_y` :`list -`
    array of y-coordinates

  ## Returns

  `interp_x` :`list`
    List of linear interpolated x coordinates
  `interp_y` :`list`
    List of linear interpolated x coordinates
  Expand source code

      def linear_interpol(p_x: list, p_y: list) -> Tuple[List[float], List[float]]:
          """
          Linear interpolation of the first and the last point in array.

          Parameters
          ----------
          p_x: list -
              array of x-coordinates
          p_y: list -
              array of y-coordinates

          Returns
          --------
          interp_x: list
              List of linear interpolated x coordinates
          interp_y: list
              List of linear interpolated x coordinates
          """
          x_intpol = np.linspace(p_x[0], p_x[-1], 4)
          return x_intpol.tolist(), np.interp(x_intpol, p_x, p_y).tolist()