Generated by Cython 0.29.24

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

Raw output: ec_real.c

 001: # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, optimize.use_switch=True
 002: # encoding: utf-8
 003: """
 004: MIT License
 005: 
 006: Copyright (c) 2019 Yoann Berenguer
 007: 
 008: Permission is hereby granted, free of charge, to any person obtaining a copy
 009: of this software and associated documentation files (the "Software"), to deal
 010: in the Software without restriction, including without limitation the rights
 011: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 012: copies of the Software, and to permit persons to whom the Software is
 013: furnished to do so, subject to the following conditions:
 014: 
 015: The above copyright notice and this permission notice shall be included in all
 016: copies or substantial portions of the Software.
 017: 
 018: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 019: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 020: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 021: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 022: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 023: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 024: SOFTWARE.
 025: 
 026: """
 027: 
+028: import warnings
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_warnings, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 28, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_warnings, __pyx_t_1) < 0) __PYX_ERR(0, 28, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 029: 
+030: warnings.filterwarnings("ignore", category=FutureWarning)
  __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_warnings); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 30, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_filterwarnings); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 30, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 30, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_category, __pyx_builtin_FutureWarning) < 0) __PYX_ERR(0, 30, __pyx_L1_error)
  __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__2, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 30, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
/* … */
  __pyx_tuple__2 = PyTuple_Pack(1, __pyx_n_s_ignore); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 30, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__2);
  __Pyx_GIVEREF(__pyx_tuple__2);
+031: warnings.filterwarnings("ignore", category=ImportWarning)
  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_warnings); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 31, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_filterwarnings); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 31, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 31, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_category, __pyx_builtin_ImportWarning) < 0) __PYX_ERR(0, 31, __pyx_L1_error)
  __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_tuple__2, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 31, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 032: 
+033: try:
  {
    /*try:*/ {
/* … */
    }
    __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
    __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
    __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
    goto __pyx_L7_try_end;
    __pyx_L2_error:;
    __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
    __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
/* … */
    __Pyx_XGIVEREF(__pyx_t_4);
    __Pyx_XGIVEREF(__pyx_t_5);
    __Pyx_XGIVEREF(__pyx_t_6);
    __Pyx_ExceptionReset(__pyx_t_4, __pyx_t_5, __pyx_t_6);
    goto __pyx_L1_error;
    __pyx_L7_try_end:;
  }
+034:     import pygame
      __pyx_t_2 = __Pyx_Import(__pyx_n_s_pygame, 0, -1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 34, __pyx_L2_error)
      __Pyx_GOTREF(__pyx_t_2);
      if (PyDict_SetItem(__pyx_d, __pyx_n_s_pygame, __pyx_t_2) < 0) __PYX_ERR(0, 34, __pyx_L2_error)
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 035: 
+036: except ImportError:
    __pyx_t_7 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_ImportError);
    if (__pyx_t_7) {
      __Pyx_AddTraceback("ElasticCollision.ec_real", __pyx_clineno, __pyx_lineno, __pyx_filename);
      if (__Pyx_GetException(&__pyx_t_2, &__pyx_t_3, &__pyx_t_1) < 0) __PYX_ERR(0, 36, __pyx_L4_except_error)
      __Pyx_GOTREF(__pyx_t_2);
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_GOTREF(__pyx_t_1);
+037:     raise ImportError("\n<pygame> library is missing on your system."
      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 37, __pyx_L4_except_error)
      __Pyx_GOTREF(__pyx_t_8);
      __Pyx_Raise(__pyx_t_8, 0, 0, 0);
      __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
      __PYX_ERR(0, 37, __pyx_L4_except_error)
    }
    goto __pyx_L4_except_error;
    __pyx_L4_except_error:;
/* … */
  __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_s_pygame_library_is_missing_on_yo); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 37, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__3);
  __Pyx_GIVEREF(__pyx_tuple__3);
 038:           "\nTry: \n   C:\\pip install pygame on a window command prompt.")
 039: 
+040: from pygame.math import Vector2
  __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 40, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_INCREF(__pyx_n_s_Vector2);
  __Pyx_GIVEREF(__pyx_n_s_Vector2);
  PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_Vector2);
  __pyx_t_3 = __Pyx_Import(__pyx_n_s_pygame_math, __pyx_t_1, -1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 40, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_Vector2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 40, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_Vector2, __pyx_t_1) < 0) __PYX_ERR(0, 40, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 041: 
 042: # Cython is require
+043: try:
  {
    /*try:*/ {
/* … */
    }
  }
 044:     cimport cython
 045: 
 046: except ImportError:
 047:     raise ImportError("\n<cython> library is missing on your system."
 048:           "\nTry: \n   C:\\pip install cython on a window command prompt.")
 049: 
 050: 
 051: # Numpy is require
+052: try:
  {
    /*try:*/ {
/* … */
    }
    __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
    __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
    __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
    goto __pyx_L21_try_end;
    __pyx_L16_error:;
    __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
    __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
    __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
/* … */
    __Pyx_XGIVEREF(__pyx_t_4);
    __Pyx_XGIVEREF(__pyx_t_5);
    __Pyx_XGIVEREF(__pyx_t_6);
    __Pyx_ExceptionReset(__pyx_t_4, __pyx_t_5, __pyx_t_6);
    goto __pyx_L1_error;
    __pyx_L21_try_end:;
  }
+053:     import numpy
      __pyx_t_3 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 53, __pyx_L16_error)
      __Pyx_GOTREF(__pyx_t_3);
      if (PyDict_SetItem(__pyx_d, __pyx_n_s_numpy, __pyx_t_3) < 0) __PYX_ERR(0, 53, __pyx_L16_error)
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
 054: 
+055: except ImportError:
    __pyx_t_7 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_ImportError);
    if (__pyx_t_7) {
      __Pyx_AddTraceback("ElasticCollision.ec_real", __pyx_clineno, __pyx_lineno, __pyx_filename);
      if (__Pyx_GetException(&__pyx_t_3, &__pyx_t_1, &__pyx_t_2) < 0) __PYX_ERR(0, 55, __pyx_L18_except_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_GOTREF(__pyx_t_2);
+056:     raise ImportError("\n<numpy> library is missing on your system."
      __pyx_t_8 = __Pyx_PyObject_Call(__pyx_builtin_ImportError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 56, __pyx_L18_except_error)
      __Pyx_GOTREF(__pyx_t_8);
      __Pyx_Raise(__pyx_t_8, 0, 0, 0);
      __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
      __PYX_ERR(0, 56, __pyx_L18_except_error)
    }
    goto __pyx_L18_except_error;
    __pyx_L18_except_error:;
 057:           "\nTry: \n   C:\\pip install numpy on a window command prompt.")
 058: 
 059: from libc.math cimport cos, sin, atan2, acos, sqrt
 060: 
 061: cdef extern from '../Source/vector.c':
 062: 
 063:     struct vector2d:
 064:        float x
 065:        float y
 066: 
 067:     struct v_struct:
 068:         vector2d vector1
 069:         vector2d vector2
 070: 
 071:     void vecinit(vector2d *v, float x, float y)nogil
 072:     float vlength(vector2d *v)nogil
 073:     void scale_inplace(float c, vector2d *v)nogil
 074:     vector2d subcomponents(vector2d v1, vector2d v2)nogil
 075:     void scale_inplace(float c, vector2d *v)nogil
 076:     float dot(vector2d *v1, vector2d *v2)nogil
 077: 
 078: 
 079: DEF M_PI  = 3.14159265358979323846
 080: DEF M_PI2 = 3.14159265358979323846 / 2.0
 081: 
 082: # **************************** PYTHON INTERFACE ***************************************
 083: 
 084: @cython.boundscheck(False)
 085: @cython.wraparound(False)
 086: @cython.nonecheck(False)
 087: @cython.cdivision(True)
+088: cpdef tuple momentum_trigonometry_real(
static PyObject *__pyx_pw_16ElasticCollision_7ec_real_1momentum_trigonometry_real(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyObject *__pyx_f_16ElasticCollision_7ec_real_momentum_trigonometry_real(PyObject *__pyx_v_obj1_centre, PyObject *__pyx_v_obj2_centre, PyObject *__pyx_v_obj1_vector, PyObject *__pyx_v_obj2_vector, double __pyx_v_obj1_mass, double __pyx_v_obj2_mass, CYTHON_UNUSED int __pyx_skip_dispatch) {
  struct vector2d __pyx_v_vec1;
  struct vector2d __pyx_v_vec2;
  struct v_struct __pyx_v_collision;
  float __pyx_v_v1_x;
  float __pyx_v_v1_y;
  float __pyx_v_v2_x;
  float __pyx_v_v2_y;
  float __pyx_v_c1_x;
  float __pyx_v_c1_y;
  float __pyx_v_c2_x;
  float __pyx_v_c2_y;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("momentum_trigonometry_real", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_6);
  __Pyx_XDECREF(__pyx_t_7);
  __Pyx_XDECREF(__pyx_t_8);
  __Pyx_XDECREF(__pyx_t_9);
  __Pyx_XDECREF(__pyx_t_11);
  __Pyx_XDECREF(__pyx_t_12);
  __Pyx_AddTraceback("ElasticCollision.ec_real.momentum_trigonometry_real", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = 0;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

/* Python wrapper */
static PyObject *__pyx_pw_16ElasticCollision_7ec_real_1momentum_trigonometry_real(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static char __pyx_doc_16ElasticCollision_7ec_real_momentum_trigonometry_real[] = "\n    RETURN VECTORS V1 & V2 AFTER OBJECT COLLISION (TRIGONOMETRY) \n    \n    This method is using trigonometric equations to determine the objects final velocities\n    Refer to Two-dimensional collision with two moving objects in the following link : \n    https://en.wikipedia.org/wiki/Elastic_collision \n    \n    * This method can be used to resolved 2d elastic collision in a cartesian system \n    \n    * obj1_vector & obj2_vector are un-normalized vectors in order to keep the total kinetic \n      energy and to redistribute the force to the final velocities (v1 & v2) \n      \n    :param obj1_centre: Vector2; Centre of object 1. This vector is not normalized and the components x, y \n    correspond to the object position on the screen    \n    :param obj2_centre: Vector2; Centre of object 2. This vector is not normalized and the components x, y \n    correspond to the object position on the screen \n    :param obj1_vector: Vector2; Object 1 direction vector, un-normalized 2d Vector\n    If both vector direction are normalized the output will also be normalized.\n    :param obj2_vector: Vector2; Object 2 direction vector, un-normalized 2d Vector\n    If both vector direction are normalized the output will also be normalized. \n    :param obj1_mass: float; Mass of object 1 in kg \n    :param obj2_mass: float; Mass of object 2 in kg\n    :return: Tuple containing v1 and v2 (object vectors after collision).\n    ";
static PyObject *__pyx_pw_16ElasticCollision_7ec_real_1momentum_trigonometry_real(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyObject *__pyx_v_obj1_centre = 0;
  PyObject *__pyx_v_obj2_centre = 0;
  PyObject *__pyx_v_obj1_vector = 0;
  PyObject *__pyx_v_obj2_vector = 0;
  double __pyx_v_obj1_mass;
  double __pyx_v_obj2_mass;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("momentum_trigonometry_real (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_obj1_centre,&__pyx_n_s_obj2_centre,&__pyx_n_s_obj1_vector,&__pyx_n_s_obj2_vector,&__pyx_n_s_obj1_mass,&__pyx_n_s_obj2_mass,0};
    PyObject* values[6] = {0,0,0,0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
        CYTHON_FALLTHROUGH;
        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
        CYTHON_FALLTHROUGH;
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        CYTHON_FALLTHROUGH;
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        CYTHON_FALLTHROUGH;
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj1_centre)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj2_centre)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("momentum_trigonometry_real", 1, 6, 6, 1); __PYX_ERR(0, 88, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  2:
        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj1_vector)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("momentum_trigonometry_real", 1, 6, 6, 2); __PYX_ERR(0, 88, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  3:
        if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj2_vector)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("momentum_trigonometry_real", 1, 6, 6, 3); __PYX_ERR(0, 88, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  4:
        if (likely((values[4] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj1_mass)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("momentum_trigonometry_real", 1, 6, 6, 4); __PYX_ERR(0, 88, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  5:
        if (likely((values[5] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj2_mass)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("momentum_trigonometry_real", 1, 6, 6, 5); __PYX_ERR(0, 88, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "momentum_trigonometry_real") < 0)) __PYX_ERR(0, 88, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 6) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
      values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
      values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
      values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
    }
    __pyx_v_obj1_centre = values[0];
    __pyx_v_obj2_centre = values[1];
    __pyx_v_obj1_vector = values[2];
    __pyx_v_obj2_vector = values[3];
    __pyx_v_obj1_mass = __pyx_PyFloat_AsDouble(values[4]); if (unlikely((__pyx_v_obj1_mass == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 93, __pyx_L3_error)
    __pyx_v_obj2_mass = __pyx_PyFloat_AsDouble(values[5]); if (unlikely((__pyx_v_obj2_mass == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 94, __pyx_L3_error)
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("momentum_trigonometry_real", 1, 6, 6, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 88, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("ElasticCollision.ec_real.momentum_trigonometry_real", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_16ElasticCollision_7ec_real_momentum_trigonometry_real(__pyx_self, __pyx_v_obj1_centre, __pyx_v_obj2_centre, __pyx_v_obj1_vector, __pyx_v_obj2_vector, __pyx_v_obj1_mass, __pyx_v_obj2_mass);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_16ElasticCollision_7ec_real_momentum_trigonometry_real(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_obj1_centre, PyObject *__pyx_v_obj2_centre, PyObject *__pyx_v_obj1_vector, PyObject *__pyx_v_obj2_vector, double __pyx_v_obj1_mass, double __pyx_v_obj2_mass) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("momentum_trigonometry_real", 0);
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = __pyx_f_16ElasticCollision_7ec_real_momentum_trigonometry_real(__pyx_v_obj1_centre, __pyx_v_obj2_centre, __pyx_v_obj1_vector, __pyx_v_obj2_vector, __pyx_v_obj1_mass, __pyx_v_obj2_mass, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 88, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;

  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_AddTraceback("ElasticCollision.ec_real.momentum_trigonometry_real", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 089:         obj1_centre : Vector2,
 090:         obj2_centre : Vector2,
 091:         obj1_vector : Vector2,
 092:         obj2_vector : Vector2,
 093:         obj1_mass   : float,
 094:         obj2_mass   : float
 095:     ):
 096:     """
 097:     RETURN VECTORS V1 & V2 AFTER OBJECT COLLISION (TRIGONOMETRY)
 098: 
 099:     This method is using trigonometric equations to determine the objects final velocities
 100:     Refer to Two-dimensional collision with two moving objects in the following link :
 101:     https://en.wikipedia.org/wiki/Elastic_collision
 102: 
 103:     * This method can be used to resolved 2d elastic collision in a cartesian system
 104: 
 105:     * obj1_vector & obj2_vector are un-normalized vectors in order to keep the total kinetic
 106:       energy and to redistribute the force to the final velocities (v1 & v2)
 107: 
 108:     :param obj1_centre: Vector2; Centre of object 1. This vector is not normalized and the components x, y
 109:     correspond to the object position on the screen
 110:     :param obj2_centre: Vector2; Centre of object 2. This vector is not normalized and the components x, y
 111:     correspond to the object position on the screen
 112:     :param obj1_vector: Vector2; Object 1 direction vector, un-normalized 2d Vector
 113:     If both vector direction are normalized the output will also be normalized.
 114:     :param obj2_vector: Vector2; Object 2 direction vector, un-normalized 2d Vector
 115:     If both vector direction are normalized the output will also be normalized.
 116:     :param obj1_mass: float; Mass of object 1 in kg
 117:     :param obj2_mass: float; Mass of object 2 in kg
 118:     :return: Tuple containing v1 and v2 (object vectors after collision).
 119:     """
 120:     cdef:
 121:         vector2d vec1, vec2
 122:         v_struct collision
 123:         float v1_x, v1_y, v2_x, v2_y
 124:         float c1_x, c1_y, c2_x, c2_y
 125: 
+126:     v1_x, v1_y, v2_x, v2_y = obj1_vector.x, obj1_vector.y, obj2_vector.x, obj2_vector.y
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj1_vector, __pyx_n_s_x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 126, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_2 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj1_vector, __pyx_n_s_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 126, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj2_vector, __pyx_n_s_x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 126, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_4 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_4 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj2_vector, __pyx_n_s_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 126, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_5 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_5 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 126, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_v1_x = __pyx_t_2;
  __pyx_v_v1_y = __pyx_t_3;
  __pyx_v_v2_x = __pyx_t_4;
  __pyx_v_v2_y = __pyx_t_5;
+127:     c1_x, c1_y, c2_x, c2_y = obj1_centre.x, obj1_centre.y, obj2_centre.x, obj2_centre.y
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj1_centre, __pyx_n_s_x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 127, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_5 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_5 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 127, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj1_centre, __pyx_n_s_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 127, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_4 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_4 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 127, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj2_centre, __pyx_n_s_x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 127, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 127, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj2_centre, __pyx_n_s_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 127, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_2 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 127, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_c1_x = __pyx_t_5;
  __pyx_v_c1_y = __pyx_t_4;
  __pyx_v_c2_x = __pyx_t_3;
  __pyx_v_c2_y = __pyx_t_2;
 128: 
+129:     with nogil:
  {
      #ifdef WITH_THREAD
      PyThreadState *_save;
      Py_UNBLOCK_THREADS
      __Pyx_FastGIL_Remember();
      #endif
      /*try:*/ {
/* … */
      /*finally:*/ {
        /*normal exit:*/{
          #ifdef WITH_THREAD
          __Pyx_FastGIL_Forget();
          Py_BLOCK_THREADS
          #endif
          goto __pyx_L5;
        }
        __pyx_L5:;
      }
  }
+130:         vecinit(&vec1, v1_x, v1_y)
        vecinit((&__pyx_v_vec1), __pyx_v_v1_x, __pyx_v_v1_y);
+131:         vecinit(&vec2, v2_x, v2_y)
        vecinit((&__pyx_v_vec2), __pyx_v_v2_x, __pyx_v_v2_y);
 132:         # DETERMINES V1 & V2 COMPONENTS AFTER COLLISION
 133:         collision = \
+134:             get_momentum_trigonometry_vecR(
        __pyx_v_collision = __pyx_f_16ElasticCollision_7ec_real_get_momentum_trigonometry_vecR(__pyx_v_c1_x, __pyx_v_c1_y, __pyx_v_c2_x, __pyx_v_c2_y, __pyx_v_vec1, __pyx_v_vec2, __pyx_v_obj1_mass, __pyx_v_obj2_mass);
      }
 135:                 c1_x, c1_y, c2_x, c2_y,
 136:                 vec1, vec2, obj1_mass, obj2_mass)
 137: 
+138:     return Vector2(collision.vector1.x, collision.vector1.y), \
  __Pyx_XDECREF(__pyx_r);
  __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_Vector2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 138, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_t_7 = PyFloat_FromDouble(__pyx_v_collision.vector1.x); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 138, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  __pyx_t_8 = PyFloat_FromDouble(__pyx_v_collision.vector1.y); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 138, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_8);
  __pyx_t_9 = NULL;
  __pyx_t_10 = 0;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) {
    __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_6);
    if (likely(__pyx_t_9)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
      __Pyx_INCREF(__pyx_t_9);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_6, function);
      __pyx_t_10 = 1;
    }
  }
  #if CYTHON_FAST_PYCALL
  if (PyFunction_Check(__pyx_t_6)) {
    PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_7, __pyx_t_8};
    __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 138, __pyx_L1_error)
    __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
  } else
  #endif
  #if CYTHON_FAST_PYCCALL
  if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) {
    PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_7, __pyx_t_8};
    __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 138, __pyx_L1_error)
    __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
  } else
  #endif
  {
    __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 138, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_11);
    if (__pyx_t_9) {
      __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_9); __pyx_t_9 = NULL;
    }
    __Pyx_GIVEREF(__pyx_t_7);
    PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_10, __pyx_t_7);
    __Pyx_GIVEREF(__pyx_t_8);
    PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_10, __pyx_t_8);
    __pyx_t_7 = 0;
    __pyx_t_8 = 0;
    __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 138, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
  }
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
/* … */
  __pyx_t_11 = PyTuple_New(2); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 138, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_11);
  __Pyx_GIVEREF(__pyx_t_1);
  PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_1);
  __Pyx_GIVEREF(__pyx_t_6);
  PyTuple_SET_ITEM(__pyx_t_11, 1, __pyx_t_6);
  __pyx_t_1 = 0;
  __pyx_t_6 = 0;
  __pyx_r = ((PyObject*)__pyx_t_11);
  __pyx_t_11 = 0;
  goto __pyx_L0;
+139:            Vector2(collision.vector2.x, collision.vector2.y)
  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_Vector2); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 139, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_11);
  __pyx_t_8 = PyFloat_FromDouble(__pyx_v_collision.vector2.x); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 139, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_8);
  __pyx_t_7 = PyFloat_FromDouble(__pyx_v_collision.vector2.y); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 139, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  __pyx_t_9 = NULL;
  __pyx_t_10 = 0;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_11))) {
    __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_11);
    if (likely(__pyx_t_9)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11);
      __Pyx_INCREF(__pyx_t_9);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_11, function);
      __pyx_t_10 = 1;
    }
  }
  #if CYTHON_FAST_PYCALL
  if (PyFunction_Check(__pyx_t_11)) {
    PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_8, __pyx_t_7};
    __pyx_t_6 = __Pyx_PyFunction_FastCall(__pyx_t_11, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 139, __pyx_L1_error)
    __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
    __Pyx_GOTREF(__pyx_t_6);
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  } else
  #endif
  #if CYTHON_FAST_PYCCALL
  if (__Pyx_PyFastCFunction_Check(__pyx_t_11)) {
    PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_8, __pyx_t_7};
    __pyx_t_6 = __Pyx_PyCFunction_FastCall(__pyx_t_11, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 139, __pyx_L1_error)
    __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
    __Pyx_GOTREF(__pyx_t_6);
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  } else
  #endif
  {
    __pyx_t_12 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 139, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_12);
    if (__pyx_t_9) {
      __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_12, 0, __pyx_t_9); __pyx_t_9 = NULL;
    }
    __Pyx_GIVEREF(__pyx_t_8);
    PyTuple_SET_ITEM(__pyx_t_12, 0+__pyx_t_10, __pyx_t_8);
    __Pyx_GIVEREF(__pyx_t_7);
    PyTuple_SET_ITEM(__pyx_t_12, 1+__pyx_t_10, __pyx_t_7);
    __pyx_t_8 = 0;
    __pyx_t_7 = 0;
    __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_12, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 139, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_6);
    __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
  }
  __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
 140: 
 141: 
 142: # **************************** ANGLE FREE **********************************************************
 143: 
 144: @cython.boundscheck(False)
 145: @cython.wraparound(False)
 146: @cython.nonecheck(False)
 147: @cython.cdivision(True)
+148: cpdef tuple momentum_angle_free_real(
static PyObject *__pyx_pw_16ElasticCollision_7ec_real_3momentum_angle_free_real(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyObject *__pyx_f_16ElasticCollision_7ec_real_momentum_angle_free_real(PyObject *__pyx_v_obj1_vector, PyObject *__pyx_v_obj2_vector, double __pyx_v_obj1_mass, double __pyx_v_obj2_mass, PyObject *__pyx_v_obj1_centre, PyObject *__pyx_v_obj2_centre, CYTHON_UNUSED int __pyx_skip_dispatch) {
  struct vector2d __pyx_v_vec1;
  struct vector2d __pyx_v_vec2;
  struct vector2d __pyx_v_x1_vec;
  struct vector2d __pyx_v_x2_vec;
  float __pyx_v_v1_x;
  float __pyx_v_v1_y;
  float __pyx_v_v2_x;
  float __pyx_v_v2_y;
  float __pyx_v_c1_x;
  float __pyx_v_c1_y;
  float __pyx_v_c2_x;
  float __pyx_v_c2_y;
  struct v_struct __pyx_v_v;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("momentum_angle_free_real", 0);
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_6);
  __Pyx_XDECREF(__pyx_t_7);
  __Pyx_XDECREF(__pyx_t_8);
  __Pyx_XDECREF(__pyx_t_9);
  __Pyx_XDECREF(__pyx_t_11);
  __Pyx_XDECREF(__pyx_t_12);
  __Pyx_AddTraceback("ElasticCollision.ec_real.momentum_angle_free_real", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = 0;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

/* Python wrapper */
static PyObject *__pyx_pw_16ElasticCollision_7ec_real_3momentum_angle_free_real(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static char __pyx_doc_16ElasticCollision_7ec_real_2momentum_angle_free_real[] = "\n    RETURN VECTORS V1 & V2 AFTER OBJECT COLLISION (ANGLE FREE METHOD)\n    \n    This method is using angle free equations to determine the objects final velocities\n    Refer to Two-dimensional collision with two moving objects in the following link : \n    https://en.wikipedia.org/wiki/Elastic_collision \n    \n    * This method can be used to resolved 2d elastic collision in cartesian system coordinates\n    \n    * obj1_vector & obj2_vector are un-normalized vectors in order to keep the total kinetic \n      energy and to redistribute the force to the final velocities (v1 & v2) \n    \n    :param obj1_centre: Vector2; Centre of object 1. This vector is not normalized and the components x, y \n    correspond to the object position on the screen    \n    :param obj2_centre: Vector2; Centre of object 2. This vector is not normalized and the components x, y \n    correspond to the object position on the screen \n    :param obj1_vector: Vector2; Object 1 direction vector, un-normalized 2d Vector\n    If both vector direction are normalized the output will also be normalized.\n    :param obj2_vector: Vector2; Object 2 direction vector un-normalized 2d Vector\n    If both vector direction are normalized the output will also be normalized. \n    :param obj1_mass: float; Mass of object 1 in kg \n    :param obj2_mass: float; Mass of object 2 in kg\n    :return: Tuple containing v1 and v2 (object vectors after collision).\n    ";
static PyObject *__pyx_pw_16ElasticCollision_7ec_real_3momentum_angle_free_real(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  PyObject *__pyx_v_obj1_vector = 0;
  PyObject *__pyx_v_obj2_vector = 0;
  double __pyx_v_obj1_mass;
  double __pyx_v_obj2_mass;
  PyObject *__pyx_v_obj1_centre = 0;
  PyObject *__pyx_v_obj2_centre = 0;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("momentum_angle_free_real (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_obj1_vector,&__pyx_n_s_obj2_vector,&__pyx_n_s_obj1_mass,&__pyx_n_s_obj2_mass,&__pyx_n_s_obj1_centre,&__pyx_n_s_obj2_centre,0};
    PyObject* values[6] = {0,0,0,0,0,0};
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
        CYTHON_FALLTHROUGH;
        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
        CYTHON_FALLTHROUGH;
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        CYTHON_FALLTHROUGH;
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        CYTHON_FALLTHROUGH;
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj1_vector)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj2_vector)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("momentum_angle_free_real", 1, 6, 6, 1); __PYX_ERR(0, 148, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  2:
        if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj1_mass)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("momentum_angle_free_real", 1, 6, 6, 2); __PYX_ERR(0, 148, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  3:
        if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj2_mass)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("momentum_angle_free_real", 1, 6, 6, 3); __PYX_ERR(0, 148, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  4:
        if (likely((values[4] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj1_centre)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("momentum_angle_free_real", 1, 6, 6, 4); __PYX_ERR(0, 148, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  5:
        if (likely((values[5] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_obj2_centre)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("momentum_angle_free_real", 1, 6, 6, 5); __PYX_ERR(0, 148, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "momentum_angle_free_real") < 0)) __PYX_ERR(0, 148, __pyx_L3_error)
      }
    } else if (PyTuple_GET_SIZE(__pyx_args) != 6) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
      values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
      values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
      values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
      values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
    }
    __pyx_v_obj1_vector = values[0];
    __pyx_v_obj2_vector = values[1];
    __pyx_v_obj1_mass = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_obj1_mass == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 151, __pyx_L3_error)
    __pyx_v_obj2_mass = __pyx_PyFloat_AsDouble(values[3]); if (unlikely((__pyx_v_obj2_mass == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 152, __pyx_L3_error)
    __pyx_v_obj1_centre = values[4];
    __pyx_v_obj2_centre = values[5];
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("momentum_angle_free_real", 1, 6, 6, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 148, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("ElasticCollision.ec_real.momentum_angle_free_real", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_16ElasticCollision_7ec_real_2momentum_angle_free_real(__pyx_self, __pyx_v_obj1_vector, __pyx_v_obj2_vector, __pyx_v_obj1_mass, __pyx_v_obj2_mass, __pyx_v_obj1_centre, __pyx_v_obj2_centre);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_16ElasticCollision_7ec_real_2momentum_angle_free_real(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_obj1_vector, PyObject *__pyx_v_obj2_vector, double __pyx_v_obj1_mass, double __pyx_v_obj2_mass, PyObject *__pyx_v_obj1_centre, PyObject *__pyx_v_obj2_centre) {
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("momentum_angle_free_real", 0);
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_1 = __pyx_f_16ElasticCollision_7ec_real_momentum_angle_free_real(__pyx_v_obj1_vector, __pyx_v_obj2_vector, __pyx_v_obj1_mass, __pyx_v_obj2_mass, __pyx_v_obj1_centre, __pyx_v_obj2_centre, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 148, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;

  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_AddTraceback("ElasticCollision.ec_real.momentum_angle_free_real", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 149:     obj1_vector  : Vector2,
 150:     obj2_vector  : Vector2,
 151:     obj1_mass    : float,
 152:     obj2_mass    : float,
 153:     obj1_centre  : Vector2,
 154:     obj2_centre  : Vector2,
 155:     ):
 156:     """
 157:     RETURN VECTORS V1 & V2 AFTER OBJECT COLLISION (ANGLE FREE METHOD)
 158: 
 159:     This method is using angle free equations to determine the objects final velocities
 160:     Refer to Two-dimensional collision with two moving objects in the following link :
 161:     https://en.wikipedia.org/wiki/Elastic_collision
 162: 
 163:     * This method can be used to resolved 2d elastic collision in cartesian system coordinates
 164: 
 165:     * obj1_vector & obj2_vector are un-normalized vectors in order to keep the total kinetic
 166:       energy and to redistribute the force to the final velocities (v1 & v2)
 167: 
 168:     :param obj1_centre: Vector2; Centre of object 1. This vector is not normalized and the components x, y
 169:     correspond to the object position on the screen
 170:     :param obj2_centre: Vector2; Centre of object 2. This vector is not normalized and the components x, y
 171:     correspond to the object position on the screen
 172:     :param obj1_vector: Vector2; Object 1 direction vector, un-normalized 2d Vector
 173:     If both vector direction are normalized the output will also be normalized.
 174:     :param obj2_vector: Vector2; Object 2 direction vector un-normalized 2d Vector
 175:     If both vector direction are normalized the output will also be normalized.
 176:     :param obj1_mass: float; Mass of object 1 in kg
 177:     :param obj2_mass: float; Mass of object 2 in kg
 178:     :return: Tuple containing v1 and v2 (object vectors after collision).
 179:     """
 180: 
 181:     cdef:
 182:         vector2d vec1, vec2, x1_vec, x2_vec
 183:         float v1_x, v1_y, v2_x, v2_y
 184:         float c1_x, c1_y, c2_x, c2_y
 185:         v_struct v
 186: 
+187:     v1_x, v1_y, v2_x, v2_y = obj1_vector.x, obj1_vector.y, obj2_vector.x, obj2_vector.y
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj1_vector, __pyx_n_s_x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 187, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_2 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 187, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj1_vector, __pyx_n_s_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 187, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 187, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj2_vector, __pyx_n_s_x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 187, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_4 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_4 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 187, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj2_vector, __pyx_n_s_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 187, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_5 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_5 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 187, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_v1_x = __pyx_t_2;
  __pyx_v_v1_y = __pyx_t_3;
  __pyx_v_v2_x = __pyx_t_4;
  __pyx_v_v2_y = __pyx_t_5;
+188:     c1_x, c1_y, c2_x, c2_y = obj1_centre.x, obj1_centre.y, obj2_centre.x, obj2_centre.y
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj1_centre, __pyx_n_s_x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 188, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_5 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_5 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 188, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj1_centre, __pyx_n_s_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 188, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_4 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_4 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 188, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj2_centre, __pyx_n_s_x); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 188, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 188, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_obj2_centre, __pyx_n_s_y); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 188, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_2 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 188, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_v_c1_x = __pyx_t_5;
  __pyx_v_c1_y = __pyx_t_4;
  __pyx_v_c2_x = __pyx_t_3;
  __pyx_v_c2_y = __pyx_t_2;
 189: 
+190:     with nogil:
  {
      #ifdef WITH_THREAD
      PyThreadState *_save;
      Py_UNBLOCK_THREADS
      __Pyx_FastGIL_Remember();
      #endif
      /*try:*/ {
/* … */
      /*finally:*/ {
        /*normal exit:*/{
          #ifdef WITH_THREAD
          __Pyx_FastGIL_Forget();
          Py_BLOCK_THREADS
          #endif
          goto __pyx_L5;
        }
        __pyx_L5:;
      }
  }
+191:         vecinit(&vec1, v1_x, v1_y)
        vecinit((&__pyx_v_vec1), __pyx_v_v1_x, __pyx_v_v1_y);
+192:         vecinit(&vec2, v2_x, v2_y)
        vecinit((&__pyx_v_vec2), __pyx_v_v2_x, __pyx_v_v2_y);
+193:         vecinit(&x1_vec, c1_x, c1_y)
        vecinit((&__pyx_v_x1_vec), __pyx_v_c1_x, __pyx_v_c1_y);
+194:         vecinit(&x2_vec, c2_x, c2_y)
        vecinit((&__pyx_v_x2_vec), __pyx_v_c2_x, __pyx_v_c2_y);
 195: 
+196:         v = get_angle_free_vecR(vec1, vec2, obj1_mass, obj2_mass, x1_vec, x2_vec)
        __pyx_v_v = __pyx_f_16ElasticCollision_7ec_real_get_angle_free_vecR(__pyx_v_vec1, __pyx_v_vec2, __pyx_v_obj1_mass, __pyx_v_obj2_mass, __pyx_v_x1_vec, __pyx_v_x2_vec);
      }
 197: 
+198:     return Vector2(v.vector1.x, v.vector1.y), \
  __Pyx_XDECREF(__pyx_r);
  __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_Vector2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 198, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_t_7 = PyFloat_FromDouble(__pyx_v_v.vector1.x); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 198, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  __pyx_t_8 = PyFloat_FromDouble(__pyx_v_v.vector1.y); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 198, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_8);
  __pyx_t_9 = NULL;
  __pyx_t_10 = 0;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) {
    __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_6);
    if (likely(__pyx_t_9)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
      __Pyx_INCREF(__pyx_t_9);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_6, function);
      __pyx_t_10 = 1;
    }
  }
  #if CYTHON_FAST_PYCALL
  if (PyFunction_Check(__pyx_t_6)) {
    PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_7, __pyx_t_8};
    __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 198, __pyx_L1_error)
    __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
  } else
  #endif
  #if CYTHON_FAST_PYCCALL
  if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) {
    PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_7, __pyx_t_8};
    __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 198, __pyx_L1_error)
    __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
  } else
  #endif
  {
    __pyx_t_11 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 198, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_11);
    if (__pyx_t_9) {
      __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_9); __pyx_t_9 = NULL;
    }
    __Pyx_GIVEREF(__pyx_t_7);
    PyTuple_SET_ITEM(__pyx_t_11, 0+__pyx_t_10, __pyx_t_7);
    __Pyx_GIVEREF(__pyx_t_8);
    PyTuple_SET_ITEM(__pyx_t_11, 1+__pyx_t_10, __pyx_t_8);
    __pyx_t_7 = 0;
    __pyx_t_8 = 0;
    __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_11, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 198, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
  }
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
/* … */
  __pyx_t_11 = PyTuple_New(2); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 198, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_11);
  __Pyx_GIVEREF(__pyx_t_1);
  PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_1);
  __Pyx_GIVEREF(__pyx_t_6);
  PyTuple_SET_ITEM(__pyx_t_11, 1, __pyx_t_6);
  __pyx_t_1 = 0;
  __pyx_t_6 = 0;
  __pyx_r = ((PyObject*)__pyx_t_11);
  __pyx_t_11 = 0;
  goto __pyx_L0;
+199:            Vector2(v.vector2.x, v.vector2.y)
  /* "ElasticCollision/real/ec_real.pyx":199
 * 
 *     return Vector2(v.vector1.x, v.vector1.y), \
 *            Vector2(v.vector2.x, v.vector2.y)             # <<<<<<<<<<<<<<
 * 
 * # ***************************END INTERFACE *************************************
 */
  __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_n_s_Vector2); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 199, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_11);
  __pyx_t_8 = PyFloat_FromDouble(__pyx_v_v.vector2.x); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 199, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_8);
  __pyx_t_7 = PyFloat_FromDouble(__pyx_v_v.vector2.y); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 199, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  __pyx_t_9 = NULL;
  __pyx_t_10 = 0;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_11))) {
    __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_11);
    if (likely(__pyx_t_9)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11);
      __Pyx_INCREF(__pyx_t_9);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_11, function);
      __pyx_t_10 = 1;
    }
  }
  #if CYTHON_FAST_PYCALL
  if (PyFunction_Check(__pyx_t_11)) {
    PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_8, __pyx_t_7};
    __pyx_t_6 = __Pyx_PyFunction_FastCall(__pyx_t_11, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 199, __pyx_L1_error)
    __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
    __Pyx_GOTREF(__pyx_t_6);
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  } else
  #endif
  #if CYTHON_FAST_PYCCALL
  if (__Pyx_PyFastCFunction_Check(__pyx_t_11)) {
    PyObject *__pyx_temp[3] = {__pyx_t_9, __pyx_t_8, __pyx_t_7};
    __pyx_t_6 = __Pyx_PyCFunction_FastCall(__pyx_t_11, __pyx_temp+1-__pyx_t_10, 2+__pyx_t_10); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 199, __pyx_L1_error)
    __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
    __Pyx_GOTREF(__pyx_t_6);
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  } else
  #endif
  {
    __pyx_t_12 = PyTuple_New(2+__pyx_t_10); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 199, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_12);
    if (__pyx_t_9) {
      __Pyx_GIVEREF(__pyx_t_9); PyTuple_SET_ITEM(__pyx_t_12, 0, __pyx_t_9); __pyx_t_9 = NULL;
    }
    __Pyx_GIVEREF(__pyx_t_8);
    PyTuple_SET_ITEM(__pyx_t_12, 0+__pyx_t_10, __pyx_t_8);
    __Pyx_GIVEREF(__pyx_t_7);
    PyTuple_SET_ITEM(__pyx_t_12, 1+__pyx_t_10, __pyx_t_7);
    __pyx_t_8 = 0;
    __pyx_t_7 = 0;
    __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_11, __pyx_t_12, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 199, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_6);
    __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
  }
  __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
 200: 
 201: # ***************************END INTERFACE *************************************
 202: 
 203: 
 204: 
 205: # *************************** CYTHON INTERFACE *********************************
 206: 
 207: @cython.boundscheck(False)
 208: @cython.wraparound(False)
 209: @cython.nonecheck(False)
 210: @cython.cdivision(True)
+211: cdef v_struct get_momentum_trigonometry_vecR(
static struct v_struct __pyx_f_16ElasticCollision_7ec_real_get_momentum_trigonometry_vecR(float __pyx_v_obj1_cx, float __pyx_v_obj1_cy, float __pyx_v_obj2_cx, float __pyx_v_obj2_cy, struct vector2d __pyx_v_obj1_vec, struct vector2d __pyx_v_obj2_vec, float __pyx_v_obj1_mass, float __pyx_v_obj2_mass) {
  float __pyx_v_phi;
  float __pyx_v_theta1;
  float __pyx_v_theta2;
  float __pyx_v_v1_length;
  float __pyx_v_v2_length;
  struct vector2d __pyx_v_v1;
  struct vector2d __pyx_v_v2;
  struct v_struct __pyx_v_collision;
  struct v_struct __pyx_r;
/* … */
  /* function exit code */
  __pyx_L0:;
  return __pyx_r;
}
 212:         float obj1_cx, float obj1_cy,
 213:         float obj2_cx, float obj2_cy,
 214:         vector2d obj1_vec, vector2d obj2_vec,
 215:         float obj1_mass, float obj2_mass
 216: )nogil:
 217:     """
 218:     RETURN VECTORS V1 & V2 OF ORIGINAL OBJECTS AFTER
 219:     COLLISION (TRIGONOMETRY)
 220: 
 221:     :param obj1_cx  : float; Object 1 centre x coordinate
 222:     :param obj1_cy  : float; object 1 centre y coordinate
 223:     :param obj2_cx  : float; object 2 centre x coordinate
 224:     :param obj2_cy  : float; object 2 centre y coordinate
 225:     :param obj1_vec : float; object 1 vector velocity/trajectory
 226:     :param obj2_vec : float; object 2 vector velocity/trajectory
 227:     :param obj1_mass: float; object 1 mass in kilogrammes
 228:     :param obj2_mass: float; object 2 mass in kilogrammes
 229:     :return: return a cython object v_struct (tuple of vector2d v1, v2)
 230:     """
 231: 
 232:     cdef:
+233:         float phi    = get_contact_angle(obj1_cx, obj1_cy, obj2_cx, obj2_cy)
  __pyx_v_phi = __pyx_f_16ElasticCollision_7ec_real_get_contact_angle(__pyx_v_obj1_cx, __pyx_v_obj1_cy, __pyx_v_obj2_cx, __pyx_v_obj2_cy);
+234:         float theta1 = get_theta_angle(obj1_vec)
  __pyx_v_theta1 = __pyx_f_16ElasticCollision_7ec_real_get_theta_angle(__pyx_v_obj1_vec);
+235:         float theta2 = get_theta_angle(obj2_vec)
  __pyx_v_theta2 = __pyx_f_16ElasticCollision_7ec_real_get_theta_angle(__pyx_v_obj2_vec);
 236:         float v1_length, v2_length
 237:         vector2d v1
 238:         vector2d v2
 239:         v_struct collision
 240: 
+241:     v1_length         = vlength(&obj1_vec)
  __pyx_v_v1_length = vlength((&__pyx_v_obj1_vec));
+242:     v2_length         = vlength(&obj2_vec)
  __pyx_v_v2_length = vlength((&__pyx_v_obj2_vec));
 243: 
+244:     v1 = get_v1R(v1_length, v2_length, theta1, theta2, phi, obj1_mass, obj2_mass)
  __pyx_v_v1 = __pyx_f_16ElasticCollision_7ec_real_get_v1R(__pyx_v_v1_length, __pyx_v_v2_length, __pyx_v_theta1, __pyx_v_theta2, __pyx_v_phi, __pyx_v_obj1_mass, __pyx_v_obj2_mass);
+245:     v2 = get_v2R(v1_length, v2_length, theta1, theta2, phi, obj1_mass, obj2_mass)
  __pyx_v_v2 = __pyx_f_16ElasticCollision_7ec_real_get_v2R(__pyx_v_v1_length, __pyx_v_v2_length, __pyx_v_theta1, __pyx_v_theta2, __pyx_v_phi, __pyx_v_obj1_mass, __pyx_v_obj2_mass);
 246: 
+247:     collision.vector1 = v1
  __pyx_v_collision.vector1 = __pyx_v_v1;
+248:     collision.vector2 = v2
  __pyx_v_collision.vector2 = __pyx_v_v2;
 249: 
+250:     return collision
  __pyx_r = __pyx_v_collision;
  goto __pyx_L0;
 251: 
 252: 
+253: cdef vector2d get_v1R(
static struct vector2d __pyx_f_16ElasticCollision_7ec_real_get_v1R(float __pyx_v_v1_, float __pyx_v_v2_, float __pyx_v_theta1_, float __pyx_v_theta2_, float __pyx_v_phi_, float __pyx_v_m1_, float __pyx_v_m2_) {
  float __pyx_v_numerator;
  float __pyx_v_v1x;
  float __pyx_v_v1y;
  float __pyx_v_r1;
  float __pyx_v_r2;
  float __pyx_v_m12;
  struct vector2d __pyx_v_v1_vec;
  struct vector2d __pyx_r;
  #ifdef WITH_THREAD
  PyGILState_STATE __pyx_gilstate_save;
  #endif
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("get_v1R", 1);
/* … */
  /* function exit code */
  __Pyx_pretend_to_initialize(&__pyx_r);
  goto __pyx_L0;
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_WriteUnraisable("ElasticCollision.ec_real.get_v1R", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1);
  __Pyx_pretend_to_initialize(&__pyx_r);
  __pyx_L0:;
  #ifdef WITH_THREAD
  __Pyx_PyGILState_Release(__pyx_gilstate_save);
  #endif
  return __pyx_r;
}
 254:         float v1_, float v2_,
 255:         float theta1_, float theta2_,
 256:         float phi_,
 257:         float m1_, float m2_
 258: )nogil:
+259:     """
  /*try:*/ {
/* … */
  /*finally:*/ {
    __pyx_L3_return: {
      #ifdef WITH_THREAD
      __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
      #endif
      goto __pyx_L0;
    }
    __pyx_L4_error: {
      #ifdef WITH_THREAD
      __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
      #endif
      goto __pyx_L1_error;
    }
  }
 260:     RETURN SCALAR SIZE V1 OF THE ORIGINAL OBJECT
 261:     REPRESENTED BY (V1, THETA1, M1) TRIGONOMETRY
 262: 
 263:     Where v1_ and v2_ are the scalar sizes of the two original speeds of the objects, m1_ and m2_
 264:     are their masses, θ1 and θ2 are their movement angles, that is,v1x = v1_.cos(θ1) , v1y = v1_.sin(θ1)
 265:     (meaning moving directly down to the right is either a -45° angle, or a 315°angle), and lowercase phi_ (φ)
 266:     is the contact angle.
 267: 
 268:     :param v1_     : float; object1 vector_ length
 269:     :param v2_     : float; object2 vector_ length
 270:     :param theta1_ : float; Θ1 angle in radians (object1)
 271:     :param theta2_ : float; Θ2 angle in radians (object2)
 272:     :param phi_    : float; φ contact angle in radians
 273:     :param m1_     : float; Mass in kilograms, must be > 0 (object1)
 274:     :param m2_     : float; Mass in kilograms, must be > 0(object2)
 275:     :return        : Returns a vector2d cython object, vector v1
 276:     :rtype         : vector2d
 277:     """
 278:     cdef:
 279:         float numerator, v1x, v1y
 280:         float r1, r2
+281:         float m12 = m1_ + m2_
    __pyx_v_m12 = (__pyx_v_m1_ + __pyx_v_m2_);
 282:         vector2d v1_vec
 283: 
+284:     if v1_ <=0.0 or v2_ <=0.0:
    __pyx_t_2 = ((__pyx_v_v1_ <= 0.0) != 0);
    if (!__pyx_t_2) {
    } else {
      __pyx_t_1 = __pyx_t_2;
      goto __pyx_L7_bool_binop_done;
    }
    __pyx_t_2 = ((__pyx_v_v2_ <= 0.0) != 0);
    __pyx_t_1 = __pyx_t_2;
    __pyx_L7_bool_binop_done:;
    if (__pyx_t_1) {
/* … */
    }
+285:         with gil:
      {
          #ifdef WITH_THREAD
          PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
          #endif
          /*try:*/ {
/* … */
          /*finally:*/ {
            __pyx_L10_error: {
              #ifdef WITH_THREAD
              __Pyx_PyGILState_Release(__pyx_gilstate_save);
              #endif
              goto __pyx_L4_error;
            }
          }
      }
+286:             raise ValueError(
            __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 286, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
            __Pyx_Raise(__pyx_t_5, 0, 0, 0);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
            __PYX_ERR(0, 286, __pyx_L10_error)
          }
 287:                 '\n|v1_|, |v2_| magnitude must be >= 0.0'
+288:                 '\n|v1|=%s |v2|=%s ' % (v1_, v2_))
            __pyx_t_3 = PyFloat_FromDouble(__pyx_v_v1_); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 288, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_3);
            __pyx_t_4 = PyFloat_FromDouble(__pyx_v_v2_); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 288, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_4);
            __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 288, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_GIVEREF(__pyx_t_3);
            PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3);
            __Pyx_GIVEREF(__pyx_t_4);
            PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_4);
            __pyx_t_3 = 0;
            __pyx_t_4 = 0;
            __pyx_t_4 = __Pyx_PyString_Format(__pyx_kp_s_v1__v2__magnitude_must_be_0_0_v, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 288, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_4);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+289:     if m12 <= 0.0:
    __pyx_t_1 = ((__pyx_v_m12 <= 0.0) != 0);
    if (__pyx_t_1) {
/* … */
    }
+290:         with gil:
      {
          #ifdef WITH_THREAD
          PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
          #endif
          /*try:*/ {
/* … */
          /*finally:*/ {
            __pyx_L14_error: {
              #ifdef WITH_THREAD
              __Pyx_PyGILState_Release(__pyx_gilstate_save);
              #endif
              goto __pyx_L4_error;
            }
          }
      }
+291:             raise ValueError("Object's mass should be > 0.0")
            __pyx_t_5 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 291, __pyx_L14_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_Raise(__pyx_t_5, 0, 0, 0);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
            __PYX_ERR(0, 291, __pyx_L14_error)
          }
/* … */
  __pyx_tuple_ = PyTuple_Pack(1, __pyx_kp_s_Object_s_mass_should_be_0_0); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 291, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple_);
  __Pyx_GIVEREF(__pyx_tuple_);
 292: 
+293:     r1 = theta1_ - phi_
    __pyx_v_r1 = (__pyx_v_theta1_ - __pyx_v_phi_);
+294:     r2 = phi_ + <float>M_PI2
    __pyx_v_r2 = (__pyx_v_phi_ + ((float)1.5707963267948966));
+295:     numerator = v1_ * <float>cos(r1) * (m1_ - m2_) + <float>(2 * m2_) * v2_ * <float>cos(theta2_ - phi_)
    __pyx_v_numerator = (((__pyx_v_v1_ * ((float)cos(__pyx_v_r1))) * (__pyx_v_m1_ - __pyx_v_m2_)) + ((((float)(2.0 * __pyx_v_m2_)) * __pyx_v_v2_) * ((float)cos((__pyx_v_theta2_ - __pyx_v_phi_)))));
+296:     v1x = numerator * <float>cos(phi_) / m12 + v1_ * <float>sin(r1) * <float>cos(r2)
    __pyx_v_v1x = (((__pyx_v_numerator * ((float)cos(__pyx_v_phi_))) / __pyx_v_m12) + ((__pyx_v_v1_ * ((float)sin(__pyx_v_r1))) * ((float)cos(__pyx_v_r2))));
+297:     v1y = numerator * <float>sin(phi_) / m12 + v1_ * <float>sin(r1) * <float>sin(r2)
    __pyx_v_v1y = (((__pyx_v_numerator * ((float)sin(__pyx_v_phi_))) / __pyx_v_m12) + ((__pyx_v_v1_ * ((float)sin(__pyx_v_r1))) * ((float)sin(__pyx_v_r2))));
 298: 
+299:     vecinit(&v1_vec, v1x, v1y)
    vecinit((&__pyx_v_v1_vec), __pyx_v_v1x, __pyx_v_v1y);
+300:     return v1_vec
    __pyx_r = __pyx_v_v1_vec;
    goto __pyx_L3_return;
  }
 301: 
 302: 
 303: @cython.boundscheck(False)
 304: @cython.wraparound(False)
 305: @cython.nonecheck(False)
 306: @cython.cdivision(True)
+307: cdef vector2d get_v2R(
static struct vector2d __pyx_f_16ElasticCollision_7ec_real_get_v2R(float __pyx_v_v1_, float __pyx_v_v2_, float __pyx_v_theta1_, float __pyx_v_theta2_, float __pyx_v_phi_, float __pyx_v_m1_, float __pyx_v_m2_) {
  float __pyx_v_numerator;
  float __pyx_v_v2x;
  float __pyx_v_v2y;
  float __pyx_v_r1;
  float __pyx_v_r2;
  float __pyx_v_m21;
  struct vector2d __pyx_v_v2_vec;
  struct vector2d __pyx_r;
  #ifdef WITH_THREAD
  PyGILState_STATE __pyx_gilstate_save;
  #endif
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("get_v2R", 1);
/* … */
  /* function exit code */
  __Pyx_pretend_to_initialize(&__pyx_r);
  goto __pyx_L0;
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_WriteUnraisable("ElasticCollision.ec_real.get_v2R", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1);
  __Pyx_pretend_to_initialize(&__pyx_r);
  __pyx_L0:;
  #ifdef WITH_THREAD
  __Pyx_PyGILState_Release(__pyx_gilstate_save);
  #endif
  return __pyx_r;
}
 308:         float v1_, float v2_,
 309:         float theta1_, float theta2_,
 310:         float phi_,
 311:         float m1_, float m2_
 312: )nogil:
+313:     """
  /*try:*/ {
/* … */
  /*finally:*/ {
    __pyx_L3_return: {
      #ifdef WITH_THREAD
      __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
      #endif
      goto __pyx_L0;
    }
    __pyx_L4_error: {
      #ifdef WITH_THREAD
      __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
      #endif
      goto __pyx_L1_error;
    }
  }
 314:     RETURN SCALAR SIZE V2_ OF THE ORIGINAL OBJECT
 315:     REPRESENTED BY (V2_, THETA2_, M2_) TRIGONOMETRY
 316: 
 317:     where v1_ and v2_ are the scalar sizes of the two original speeds of the objects, m1_ and m2_
 318:     are their masses, θ1 and θ2 are their movement angles, that is,v1x = v1_.cos(θ1) , v1y = v1_.sin(θ1)
 319:     (meaning moving directly down to the right is either a -45° angle, or a 315°angle), and lowercase phi_ (φ)
 320:     is the contact angle.
 321: 
 322:     :param v1_    : float; object1 vector_ length
 323:     :param v2_    : float; object2 vector_ length
 324:     :param theta1_: float; Θ1 angle in radians (object1)
 325:     :param theta2_: float; Θ2 angle in radians (object2)
 326:     :param phi_   : float; φ contact angle in radians
 327:     :param m1_    : float; Mass in kilograms, must be > 0 (object1)
 328:     :param m2_    : float; Mass in kilograms, must be > 0(object2)
 329:     :return       : float; Returns a direction vector_
 330:     :return       : float; Return a cython object, vector v2
 331:     """
 332:     cdef:
 333:         float numerator, v2x, v2y
 334:         float r1, r2
+335:         float m21 = m2_ + m1_
    __pyx_v_m21 = (__pyx_v_m2_ + __pyx_v_m1_);
 336:         vector2d v2_vec
 337: 
+338:     r1 = (theta2_ - phi_)
    __pyx_v_r1 = (__pyx_v_theta2_ - __pyx_v_phi_);
+339:     r2 = phi_ + <float>M_PI2
    __pyx_v_r2 = (__pyx_v_phi_ + ((float)1.5707963267948966));
 340: 
+341:     if v1_ <=0.0 or v2_ <=0.0:
    __pyx_t_2 = ((__pyx_v_v1_ <= 0.0) != 0);
    if (!__pyx_t_2) {
    } else {
      __pyx_t_1 = __pyx_t_2;
      goto __pyx_L7_bool_binop_done;
    }
    __pyx_t_2 = ((__pyx_v_v2_ <= 0.0) != 0);
    __pyx_t_1 = __pyx_t_2;
    __pyx_L7_bool_binop_done:;
    if (__pyx_t_1) {
/* … */
    }
+342:         with gil:
      {
          #ifdef WITH_THREAD
          PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
          #endif
          /*try:*/ {
/* … */
          /*finally:*/ {
            __pyx_L10_error: {
              #ifdef WITH_THREAD
              __Pyx_PyGILState_Release(__pyx_gilstate_save);
              #endif
              goto __pyx_L4_error;
            }
          }
      }
+343:             raise ValueError(
            __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 343, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
            __Pyx_Raise(__pyx_t_5, 0, 0, 0);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
            __PYX_ERR(0, 343, __pyx_L10_error)
          }
 344:                 "\n|v1_|, |v2_| magnitude must be >= 0.0\n"
+345:                 "|v1|=%s |v2|=%s " % (v1_, v2_))
            __pyx_t_3 = PyFloat_FromDouble(__pyx_v_v1_); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 345, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_3);
            __pyx_t_4 = PyFloat_FromDouble(__pyx_v_v2_); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 345, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_4);
            __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 345, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_GIVEREF(__pyx_t_3);
            PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3);
            __Pyx_GIVEREF(__pyx_t_4);
            PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_4);
            __pyx_t_3 = 0;
            __pyx_t_4 = 0;
            __pyx_t_4 = __Pyx_PyString_Format(__pyx_kp_s_v1__v2__magnitude_must_be_0_0_v, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 345, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_4);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+346:     if m21 <= 0.0:
    __pyx_t_1 = ((__pyx_v_m21 <= 0.0) != 0);
    if (__pyx_t_1) {
/* … */
    }
+347:         with gil:
      {
          #ifdef WITH_THREAD
          PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
          #endif
          /*try:*/ {
/* … */
          /*finally:*/ {
            __pyx_L14_error: {
              #ifdef WITH_THREAD
              __Pyx_PyGILState_Release(__pyx_gilstate_save);
              #endif
              goto __pyx_L4_error;
            }
          }
      }
+348:             raise ValueError("Object's mass should be > 0.0")
            __pyx_t_5 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 348, __pyx_L14_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_Raise(__pyx_t_5, 0, 0, 0);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
            __PYX_ERR(0, 348, __pyx_L14_error)
          }
 349: 
+350:     numerator = v2_ * <float>cos(r1) * <float>(m2_ - m1_) + <float>(2 * m1_) * v1_ * <float>cos(theta1_ - phi_)
    __pyx_v_numerator = (((__pyx_v_v2_ * ((float)cos(__pyx_v_r1))) * ((float)(__pyx_v_m2_ - __pyx_v_m1_))) + ((((float)(2.0 * __pyx_v_m1_)) * __pyx_v_v1_) * ((float)cos((__pyx_v_theta1_ - __pyx_v_phi_)))));
+351:     v2x = numerator * <float>cos(phi_) / m21 + v2_ * <float>sin(r1) * <float>cos(r2)
    __pyx_v_v2x = (((__pyx_v_numerator * ((float)cos(__pyx_v_phi_))) / __pyx_v_m21) + ((__pyx_v_v2_ * ((float)sin(__pyx_v_r1))) * ((float)cos(__pyx_v_r2))));
+352:     v2y = numerator * <float>sin(phi_) / m21 + v2_ * <float>sin(r1) * <float>sin(r2)
    __pyx_v_v2y = (((__pyx_v_numerator * ((float)sin(__pyx_v_phi_))) / __pyx_v_m21) + ((__pyx_v_v2_ * ((float)sin(__pyx_v_r1))) * ((float)sin(__pyx_v_r2))));
 353: 
+354:     vecinit(&v2_vec, v2x, v2y)
    vecinit((&__pyx_v_v2_vec), __pyx_v_v2x, __pyx_v_v2y);
+355:     return v2_vec
    __pyx_r = __pyx_v_v2_vec;
    goto __pyx_L3_return;
  }
 356: 
 357: 
 358: 
 359: # ****************************** ANGLE FREE METHOD *******************************************
 360: 
 361: # ***************************************************************
 362: # Angle free representation, the changed velocities are computed
 363: # using centers x1 and x2 at the time of contact.
 364: # ***************************************************************
 365: @cython.boundscheck(False)
 366: @cython.wraparound(False)
 367: @cython.nonecheck(False)
 368: @cython.cdivision(True)
+369: cdef vector2d get_v1_angle_free_vecR(
static struct vector2d __pyx_f_16ElasticCollision_7ec_real_get_v1_angle_free_vecR(struct vector2d __pyx_v_v1, struct vector2d __pyx_v_v2, float __pyx_v_m1, float __pyx_v_m2, struct vector2d __pyx_v_x1, struct vector2d __pyx_v_x2) {
  float __pyx_v_m12;
  float __pyx_v_mass;
  struct vector2d __pyx_v_v12;
  struct vector2d __pyx_v_x12;
  float __pyx_v_x12_length;
  float __pyx_v_d;
  struct vector2d __pyx_r;
  #ifdef WITH_THREAD
  PyGILState_STATE __pyx_gilstate_save;
  #endif
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("get_v1_angle_free_vecR", 1);
/* … */
  /* function exit code */
  __Pyx_pretend_to_initialize(&__pyx_r);
  goto __pyx_L0;
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_WriteUnraisable("ElasticCollision.ec_real.get_v1_angle_free_vecR", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1);
  __Pyx_pretend_to_initialize(&__pyx_r);
  __pyx_L0:;
  #ifdef WITH_THREAD
  __Pyx_PyGILState_Release(__pyx_gilstate_save);
  #endif
  return __pyx_r;
}
 370:         vector2d v1, vector2d v2,
 371:         float m1, float m2,
 372:         vector2d x1, vector2d x2
 373: )nogil:
+374:     """
  /*try:*/ {
/* … */
  /*finally:*/ {
    __pyx_L3_return: {
      #ifdef WITH_THREAD
      __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
      #endif
      goto __pyx_L0;
    }
    __pyx_L4_error: {
      #ifdef WITH_THREAD
      __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
      #endif
      goto __pyx_L1_error;
    }
  }
 375:     SCALAR SIZE V1_ OF THE ORIGINAL OBJECT SPEED REPRESENTED
 376:     BY (V1_, M1_, X1 ARGUMENTS).
 377: 
 378:     :param v1: vector2d, object1 vector_
 379:     :param v2: vector2d, object2 vector_
 380:     :param m1: float; object1 mass_ in kilograms, must be > 0
 381:     :param m2: float; object2 mass_ in kilograms, must be > 0
 382:     :param x1: vector2d, object1 centre_
 383:     :param x2: vector2d, object2 centre_
 384:     :return: vector2d, resultant vector_ for object1
 385:     """
+386:     cdef float m12 = m1 + m2
    __pyx_v_m12 = (__pyx_v_m1 + __pyx_v_m2);
 387: 
+388:     if vlength(&v1) <=0.0 or vlength(&v2) <= 0.0:
    __pyx_t_2 = ((vlength((&__pyx_v_v1)) <= 0.0) != 0);
    if (!__pyx_t_2) {
    } else {
      __pyx_t_1 = __pyx_t_2;
      goto __pyx_L7_bool_binop_done;
    }
    __pyx_t_2 = ((vlength((&__pyx_v_v2)) <= 0.0) != 0);
    __pyx_t_1 = __pyx_t_2;
    __pyx_L7_bool_binop_done:;
    if (__pyx_t_1) {
/* … */
    }
+389:         with gil:
      {
          #ifdef WITH_THREAD
          PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
          #endif
          /*try:*/ {
/* … */
          /*finally:*/ {
            __pyx_L10_error: {
              #ifdef WITH_THREAD
              __Pyx_PyGILState_Release(__pyx_gilstate_save);
              #endif
              goto __pyx_L4_error;
            }
          }
      }
+390:             raise ValueError("\n|v1|, |v2| magnitude must be >= 0.0\n"
            __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 390, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
            __Pyx_Raise(__pyx_t_5, 0, 0, 0);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
            __PYX_ERR(0, 390, __pyx_L10_error)
          }
+391:                   "|v1|=%s |v2|=%s " % (vlength(&v1), vlength(&v2)))
            __pyx_t_3 = PyFloat_FromDouble(vlength((&__pyx_v_v1))); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 391, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_3);
            __pyx_t_4 = PyFloat_FromDouble(vlength((&__pyx_v_v2))); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 391, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_4);
            __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 391, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_GIVEREF(__pyx_t_3);
            PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3);
            __Pyx_GIVEREF(__pyx_t_4);
            PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_4);
            __pyx_t_3 = 0;
            __pyx_t_4 = 0;
            __pyx_t_4 = __Pyx_PyString_Format(__pyx_kp_s_v1_v2_magnitude_must_be_0_0_v1, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 391, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_4);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+392:     if m12 <= 0.0:
    __pyx_t_1 = ((__pyx_v_m12 <= 0.0) != 0);
    if (__pyx_t_1) {
/* … */
    }
+393:         with gil:
      {
          #ifdef WITH_THREAD
          PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
          #endif
          /*try:*/ {
/* … */
          /*finally:*/ {
            __pyx_L14_error: {
              #ifdef WITH_THREAD
              __Pyx_PyGILState_Release(__pyx_gilstate_save);
              #endif
              goto __pyx_L4_error;
            }
          }
      }
+394:             raise ValueError("Object's mass should be > 0.0")
            __pyx_t_5 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 394, __pyx_L14_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_Raise(__pyx_t_5, 0, 0, 0);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
            __PYX_ERR(0, 394, __pyx_L14_error)
          }
 395: 
+396:     cdef float mass = <float>(2.0 * m2) / m12   # mass coefficient in the equation
    __pyx_v_mass = (((float)(2.0 * __pyx_v_m2)) / __pyx_v_m12);
 397:     cdef vector2d v12, x12		                # 2d vector declaration v12 & x12
 398: 
+399:     v12 = subcomponents(v1, v2)     	        # subtract v1 and v2 (v1 - v2).
    __pyx_v_v12 = subcomponents(__pyx_v_v1, __pyx_v_v2);
 400:                                                 # subcomponents return a new vector v12,
 401:                                                 # original vector v1 & v2 components remain unchanged.
+402:     x12 = subcomponents(x1, x2)             	# Objects centre difference (x1 - x2).
    __pyx_v_x12 = subcomponents(__pyx_v_x1, __pyx_v_x2);
 403:                                                 # subcomponents return a new vector x12
 404:                                                 # x1 & x2 vector components remain unchanged.
+405:     cdef float x12_length = vlength(&x12)       # x12 vector length (scalar)
    __pyx_v_x12_length = vlength((&__pyx_v_x12));
+406:     cdef float d = dot(&v12, &x12)	            # vector dot product v12 & x12, return a scalar value (float)
    __pyx_v_d = dot((&__pyx_v_v12), (&__pyx_v_x12));
 407:     # rescale vector x12
+408:     scale_inplace(<float>(mass * d) / <float>(x12_length * x12_length), &x12)
    scale_inplace((((float)(__pyx_v_mass * __pyx_v_d)) / ((float)(__pyx_v_x12_length * __pyx_v_x12_length))), (&__pyx_v_x12));
+409:     return subcomponents(v1, x12)
    __pyx_r = subcomponents(__pyx_v_v1, __pyx_v_x12);
    goto __pyx_L3_return;
  }
 410: 
 411: 
 412: 
 413: # ***************************************************************
 414: # Angle free representation, the changed velocities are computed
 415: # using centers x1 and x2 at the time of contact.
 416: # ***************************************************************
 417: @cython.boundscheck(False)
 418: @cython.wraparound(False)
 419: @cython.nonecheck(False)
 420: @cython.cdivision(True)
+421: cdef vector2d get_v2_angle_free_vecR(
static struct vector2d __pyx_f_16ElasticCollision_7ec_real_get_v2_angle_free_vecR(struct vector2d __pyx_v_v1, struct vector2d __pyx_v_v2, float __pyx_v_m1, float __pyx_v_m2, struct vector2d __pyx_v_x1, struct vector2d __pyx_v_x2) {
  float __pyx_v_m12;
  float __pyx_v_mass;
  struct vector2d __pyx_v_v21;
  struct vector2d __pyx_v_x21;
  float __pyx_v_x21_length;
  float __pyx_v_d;
  struct vector2d __pyx_r;
  #ifdef WITH_THREAD
  PyGILState_STATE __pyx_gilstate_save;
  #endif
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("get_v2_angle_free_vecR", 1);
/* … */
  /* function exit code */
  __Pyx_pretend_to_initialize(&__pyx_r);
  goto __pyx_L0;
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_WriteUnraisable("ElasticCollision.ec_real.get_v2_angle_free_vecR", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1);
  __Pyx_pretend_to_initialize(&__pyx_r);
  __pyx_L0:;
  #ifdef WITH_THREAD
  __Pyx_PyGILState_Release(__pyx_gilstate_save);
  #endif
  return __pyx_r;
}
 422:         vector2d v1, vector2d v2,
 423:         float m1, float m2,
 424:         vector2d x1, vector2d x2
 425: )nogil:
+426:     """
  /*try:*/ {
/* … */
  /*finally:*/ {
    __pyx_L3_return: {
      #ifdef WITH_THREAD
      __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
      #endif
      goto __pyx_L0;
    }
    __pyx_L4_error: {
      #ifdef WITH_THREAD
      __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
      #endif
      goto __pyx_L1_error;
    }
  }
 427:     SCALAR SIZE V2_ OF THE ORIGINAL OBJECT SPEED REPRESENTED
 428:     BY (V2_, M2_, X2 ARGUMENTS).
 429: 
 430:     :param v1: vector2d, object1 vector_
 431:     :param v2: vector2d, object2 vector_
 432:     :param m1: float; object1 mass_ in kilograms, must be > 0
 433:     :param m2: float; object2 mass_ in kilograms, must be > 0
 434:     :param x1: vector2d, object1 centre_
 435:     :param x2: vector2d, object2 centre_
 436:     :return: pygame.math.Vector2, resultant vector_ for object1
 437:     """
+438:     cdef float m12 = (m1 + m2)
    __pyx_v_m12 = (__pyx_v_m1 + __pyx_v_m2);
 439: 
 440:     # AT LEAST ONE OBJECT MUST BE IN MOTION
+441:     if vlength(&v1) <=0.0 or vlength(&v2) <= 0.0:
    __pyx_t_2 = ((vlength((&__pyx_v_v1)) <= 0.0) != 0);
    if (!__pyx_t_2) {
    } else {
      __pyx_t_1 = __pyx_t_2;
      goto __pyx_L7_bool_binop_done;
    }
    __pyx_t_2 = ((vlength((&__pyx_v_v2)) <= 0.0) != 0);
    __pyx_t_1 = __pyx_t_2;
    __pyx_L7_bool_binop_done:;
    if (__pyx_t_1) {
/* … */
    }
+442:         with gil:
      {
          #ifdef WITH_THREAD
          PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
          #endif
          /*try:*/ {
/* … */
          /*finally:*/ {
            __pyx_L10_error: {
              #ifdef WITH_THREAD
              __Pyx_PyGILState_Release(__pyx_gilstate_save);
              #endif
              goto __pyx_L4_error;
            }
          }
      }
+443:             raise ValueError("\n|v1|, |v2| magnitude must be >= 0.0"
            __pyx_t_5 = __Pyx_PyObject_CallOneArg(__pyx_builtin_ValueError, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 443, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
            __Pyx_Raise(__pyx_t_5, 0, 0, 0);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
            __PYX_ERR(0, 443, __pyx_L10_error)
          }
+444:                   "\n|v1|=%s |v2|=%s " % (vlength(&v1), vlength(&v2)))
            __pyx_t_3 = PyFloat_FromDouble(vlength((&__pyx_v_v1))); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 444, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_3);
            __pyx_t_4 = PyFloat_FromDouble(vlength((&__pyx_v_v2))); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 444, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_4);
            __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 444, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_GIVEREF(__pyx_t_3);
            PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_3);
            __Pyx_GIVEREF(__pyx_t_4);
            PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_4);
            __pyx_t_3 = 0;
            __pyx_t_4 = 0;
            __pyx_t_4 = __Pyx_PyString_Format(__pyx_kp_s_v1_v2_magnitude_must_be_0_0_v1, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 444, __pyx_L10_error)
            __Pyx_GOTREF(__pyx_t_4);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
+445:     if m12 <= 0.0:
    __pyx_t_1 = ((__pyx_v_m12 <= 0.0) != 0);
    if (__pyx_t_1) {
/* … */
    }
+446:         with gil:
      {
          #ifdef WITH_THREAD
          PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
          #endif
          /*try:*/ {
/* … */
          /*finally:*/ {
            __pyx_L14_error: {
              #ifdef WITH_THREAD
              __Pyx_PyGILState_Release(__pyx_gilstate_save);
              #endif
              goto __pyx_L4_error;
            }
          }
      }
+447:             raise ValueError("Object's mass should be > 0.0")
            __pyx_t_5 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 447, __pyx_L14_error)
            __Pyx_GOTREF(__pyx_t_5);
            __Pyx_Raise(__pyx_t_5, 0, 0, 0);
            __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
            __PYX_ERR(0, 447, __pyx_L14_error)
          }
 448: 
+449:     cdef float mass = <float>(2.0 * m1) / m12   # mass coefficient in the equation
    __pyx_v_mass = (((float)(2.0 * __pyx_v_m1)) / __pyx_v_m12);
 450:     cdef vector2d v21, x21		                # 2d vector declaration v21 & x21
 451: 
+452:     v21 = subcomponents(v2, v1)		            # subtract v2 and v1 (v2 - v1).
    __pyx_v_v21 = subcomponents(__pyx_v_v2, __pyx_v_v1);
 453:                                                 # subcomponents return a new vector v21,
 454:                                                 # original vector v2 & v1 components remain unchanged.
+455:     x21 = subcomponents(x2, x1)             	# Objects centre difference (x2 - x1).
    __pyx_v_x21 = subcomponents(__pyx_v_x2, __pyx_v_x1);
 456:                                                 # subcomponents return a new vector x21
 457:                                                 # x2 & x1 vector components remain unchanged.
+458:     cdef float x21_length = vlength(&x21)	    # x21 vector length (scalar)
    __pyx_v_x21_length = vlength((&__pyx_v_x21));
+459:     cdef float d = dot(&v21, &x21)	            # vector dot product v21 & x21, return a scalar value (float)
    __pyx_v_d = dot((&__pyx_v_v21), (&__pyx_v_x21));
 460:     # rescale vector x21
+461:     scale_inplace(<float>(mass * d) / <float>(x21_length * x21_length), &x21)
    scale_inplace((((float)(__pyx_v_mass * __pyx_v_d)) / ((float)(__pyx_v_x21_length * __pyx_v_x21_length))), (&__pyx_v_x21));
+462:     return subcomponents(v2, x21)
    __pyx_r = subcomponents(__pyx_v_v2, __pyx_v_x21);
    goto __pyx_L3_return;
  }
 463: 
 464: 
 465: # ************************************************************************
 466: # Angle free calculation, return V1 and V2
 467: # ************************************************************************
 468: @cython.boundscheck(False)
 469: @cython.wraparound(False)
 470: @cython.nonecheck(False)
 471: @cython.cdivision(True)
+472: cdef v_struct get_angle_free_vecR(
static struct v_struct __pyx_f_16ElasticCollision_7ec_real_get_angle_free_vecR(struct vector2d __pyx_v_v1, struct vector2d __pyx_v_v2, float __pyx_v_m1, float __pyx_v_m2, struct vector2d __pyx_v_x1, struct vector2d __pyx_v_x2) {
  struct vector2d __pyx_v_v11;
  struct vector2d __pyx_v_v22;
  struct v_struct __pyx_v_collision;
  struct v_struct __pyx_r;
/* … */
  /* function exit code */
  __pyx_L0:;
  return __pyx_r;
}
 473:         vector2d v1, vector2d v2,
 474:         float m1, float m2,
 475:         vector2d x1, vector2d x2
 476: )nogil:
 477:     """
 478:     RETURN BOTH FINAL VELOCITIES VECTORS V1 & V2
 479: 
 480:     :param v1: vector2d, object1 vector_
 481:     :param v2: vector2d, object2 vector_
 482:     :param m1: float; object1 mass_ in kilograms, must be > 0
 483:     :param m2: float; object2 mass_ in kilograms, must be > 0
 484:     :param x1: vector2d, object1 centre_
 485:     :param x2: vector2d, object2 centre_
 486:     :return: tuple, (object1 resultant vector_, object2 resultant vector_)
 487:     """
 488:     cdef vector2d v11, v22
+489:     v11 = get_v1_angle_free_vecR(v1, v2, m1, m2, x1, x2)
  __pyx_v_v11 = __pyx_f_16ElasticCollision_7ec_real_get_v1_angle_free_vecR(__pyx_v_v1, __pyx_v_v2, __pyx_v_m1, __pyx_v_m2, __pyx_v_x1, __pyx_v_x2);
+490:     v22 = get_v2_angle_free_vecR(v1, v2, m1, m2, x1, x2)
  __pyx_v_v22 = __pyx_f_16ElasticCollision_7ec_real_get_v2_angle_free_vecR(__pyx_v_v1, __pyx_v_v2, __pyx_v_m1, __pyx_v_m2, __pyx_v_x1, __pyx_v_x2);
 491:     cdef v_struct collision
+492:     collision.vector1 = v11
  __pyx_v_collision.vector1 = __pyx_v_v11;
+493:     collision.vector2 = v22
  __pyx_v_collision.vector2 = __pyx_v_v22;
+494:     return collision
  __pyx_r = __pyx_v_collision;
  goto __pyx_L0;
 495: 
 496: 
 497: # # ***************************************************************************************************
 498: 
 499: @cython.boundscheck(False)
 500: @cython.wraparound(False)
 501: @cython.nonecheck(False)
 502: @cython.cdivision(True)
+503: cdef float vector_length(float x, float y)nogil:
static float __pyx_f_16ElasticCollision_7ec_real_vector_length(float __pyx_v_x, float __pyx_v_y) {
  float __pyx_r;
/* … */
  /* function exit code */
  __pyx_L0:;
  return __pyx_r;
}
 504:     """
 505:     CALCULATE A VECTOR LENGTH GIVEN ITS COMPONENTS (SCALAR VALUES)
 506: 
 507:     :param x: float; x coordinate
 508:     :param y: float; y coordinate
 509:     :return: float; vector length
 510:     """
+511:     return <float>sqrt(x * x + y * y)
  __pyx_r = ((float)sqrt(((__pyx_v_x * __pyx_v_x) + (__pyx_v_y * __pyx_v_y))));
  goto __pyx_L0;
 512: 
 513: @cython.boundscheck(False)
 514: @cython.wraparound(False)
 515: @cython.nonecheck(False)
 516: @cython.cdivision(True)
+517: cdef float get_contact_angle(
static float __pyx_f_16ElasticCollision_7ec_real_get_contact_angle(float __pyx_v_v1x, float __pyx_v_v1y, float __pyx_v_v2x, float __pyx_v_v2y) {
  float __pyx_v_dx;
  float __pyx_v_dy;
  float __pyx_v_phi;
  float __pyx_r;
/* … */
  /* function exit code */
  __pyx_L0:;
  return __pyx_r;
}
 518:         float v1x, float v1y,
 519:         float v2x, float v2y
 520: )nogil:
 521:     """
 522:     RETURN THE CONTACT ANGLE Φ [0, -2Π] IN RADIANS BETWEEN OBJ1 AND
 523:     OBJ2 OR [0 ... -360 degrees].
 524: 
 525:     The distance dx & dy between both objects is determine by
 526:     dx = v2x - v1x & dy = v2y - v1y.
 527: 
 528:     * Angle φ between the two objects at the point of collision
 529:       This function returns the angle φ at the time of the contact.
 530: 
 531:     * atan2(y, x) returns value of atan(y/x) in radians. The atan2() method returns
 532:       a numeric value between –pi and pi representing the angle theta of a (x, y)
 533:       point and positive x-axis.
 534: 
 535:     :param v1x : object 1 centre value (x component) at time of contact.
 536:     :param v1y : object 1 centre value (y component) at time of contact.
 537:     :param v2x : object 2 centre value (x component) at time of contact.
 538:     :param v2y : object 2 centre value (y component) at time of contact.
 539:     :return    : float; contact angle in radians [0, -2π]
 540:     :rtype     : float (angle φ radians)
 541:     """
 542:     cdef:
 543:         float dx, dy
 544:         float phi
 545: 
+546:     dx = v2x - v1x
  __pyx_v_dx = (__pyx_v_v2x - __pyx_v_v1x);
+547:     dy = v2y - v1y
  __pyx_v_dy = (__pyx_v_v2y - __pyx_v_v1y);
 548: 
+549:     phi = <float> atan2(dy, dx)
  __pyx_v_phi = ((float)atan2(__pyx_v_dy, __pyx_v_dx));
+550:     if phi > 0.0:
  __pyx_t_1 = ((__pyx_v_phi > 0.0) != 0);
  if (__pyx_t_1) {
/* … */
  }
+551:         phi -= <float>(2.0 * M_PI)
    __pyx_v_phi = (__pyx_v_phi - ((float)(2.0 * 3.141592653589793)));
 552:     # phi *= -1.0
+553:     return <float> phi
  __pyx_r = ((float)__pyx_v_phi);
  goto __pyx_L0;
 554: 
 555: @cython.boundscheck(False)
 556: @cython.wraparound(False)
 557: @cython.nonecheck(False)
 558: @cython.cdivision(True)
+559: cdef float get_theta_angle(vector2d vector_)nogil:
static float __pyx_f_16ElasticCollision_7ec_real_get_theta_angle(struct vector2d __pyx_v_vector_) {
  float __pyx_v_theta;
  float __pyx_v_vl;
  float __pyx_r;
/* … */
  /* function exit code */
  __pyx_L0:;
  return __pyx_r;
}
 560:     """
 561:     RETURN THETA ANGLE Θ IN RADIANS [Π, -Π]
 562: 
 563:     Angle theta at point of collision.
 564: 
 565:     * vector_ correspond to the initial angle for an object, similar
 566:       to the object direction at time of contact. The vector must be normalized range [-1.0 ... 1.0]
 567:       vector_ contains the vector components (x, y) describing the object velocity and direction
 568:       (angle) at time of contact.
 569:       when the vector component (vector_.y) is > 0, the acos value is in range [0 ... pi]
 570:       When the vector component (vector_.y) is < 0, the acos value is multiply by -1 to
 571:       get an angle in range [0 ... -pi]
 572: 
 573:     * acos (angle domain) is be definition in range y [0 ... +pi] and x values [-1 ... +1]
 574:       y [0 ... 180] degrees
 575: 
 576:     :param vector_: vector2d
 577:     :return       : float (angle Θ in radians)
 578:     """
 579:     cdef:
 580:         float theta
+581:         float vl = vlength(&vector_)
  __pyx_v_vl = vlength((&__pyx_v_vector_));
 582: 
+583:     if vl != <float>0.0:
  __pyx_t_1 = ((__pyx_v_vl != ((float)0.0)) != 0);
  if (__pyx_t_1) {
/* … */
    goto __pyx_L3;
  }
+584:         theta = <float> acos(vector_.x / vl)
    __pyx_v_theta = ((float)acos((__pyx_v_vector_.x / __pyx_v_vl)));
 585:     else:
 586:         # AT CONTACT TIME, OBJECT SHOULD BE MOVING.
 587:         # IDEALLY PROGRAM SHOULD RAISE AN ERROR MSG.
+588:         return <float>0.0
  /*else*/ {
    __pyx_r = ((float)0.0);
    goto __pyx_L0;
  }
  __pyx_L3:;
+589:     if vector_.y < 0.0:
  __pyx_t_1 = ((__pyx_v_vector_.y < 0.0) != 0);
  if (__pyx_t_1) {
/* … */
  }
+590:         theta *= -<float>1.0
    __pyx_v_theta = (__pyx_v_theta * (-((float)1.0)));
 591: 
+592:     theta = <float> min(theta, M_PI)
  __pyx_t_2 = 3.141592653589793;
  __pyx_t_3 = __pyx_v_theta;
  if (((__pyx_t_2 < __pyx_t_3) != 0)) {
    __pyx_t_4 = __pyx_t_2;
  } else {
    __pyx_t_4 = __pyx_t_3;
  }
  __pyx_v_theta = ((float)__pyx_t_4);
+593:     theta = <float> max(theta, -M_PI)
  __pyx_t_4 = -3.141592653589793;
  __pyx_t_3 = __pyx_v_theta;
  if (((__pyx_t_4 > __pyx_t_3) != 0)) {
    __pyx_t_2 = __pyx_t_4;
  } else {
    __pyx_t_2 = __pyx_t_3;
  }
  __pyx_v_theta = ((float)__pyx_t_2);
+594:     return <float> theta
  __pyx_r = ((float)__pyx_v_theta);
  goto __pyx_L0;