Generated by Cython 0.29.23
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: find_minpoints.c
+001: # -*- coding: utf-8 -*-
__pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_t_1, __pyx_kp_u_find_minpoints_line_69, __pyx_kp_u_Compute_the_minimum_distance_poi) < 0) __PYX_ERR(0, 1, __pyx_L1_error) if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
002:
003:
004: # pept is a Python library that unifies Positron Emission Particle
005: # Tracking (PEPT) research, including tracking, simulation, data analysis
006: # and visualisation tools.
007: #
008: # If you used this codebase or any software making use of it in a scientific
009: # publication, you must cite the following paper:
010: # Nicuşan AL, Windows-Yule CR. Positron emission particle tracking
011: # using machine learning. Review of Scientific Instruments.
012: # 2020 Jan 1;91(1):013329.
013: # https://doi.org/10.1063/1.5129251
014: #
015: # Copyright (C) 2019-2021 the pept developers
016: #
017: # This program is free software: you can redistribute it and/or modify
018: # it under the terms of the GNU General Public License as published by
019: # the Free Software Foundation, either version 3 of the License, or
020: # (at your option) any later version.
021: #
022: # This program is distributed in the hope that it will be useful,
023: # but WITHOUT ANY WARRANTY; without even the implied warranty of
024: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
025: # GNU General Public License for more details.
026: #
027: # You should have received a copy of the GNU General Public License
028: # along with this program. If not, see <https://www.gnu.org/licenses/>.
029: # pept is a Python library that unifies Positron Emission Particle
030: # Tracking (PEPT) research, including tracking, simulation, data analysis
031: # and visualisation tools
032:
033:
034: # File : find_minpoints.pyx
035: # License : GNU v3.0
036: # Author : Andrei Leonard Nicusan <a.l.nicusan@bham.ac.uk>
037: # Date : 20.10.2020
038:
039:
040: # cython: language_level=3
041: # cython: boundscheck=False
042: # cython: wraparound=False
043: # cython: initializedcheck=False
044: # cython: nonecheck=False
045: # cython: embedsignature=True
046: # cython: cdivision=True
047:
048:
+049: import numpy as np # import numpy for Python functions
__pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 49, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) __PYX_ERR(0, 49, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
050: cimport numpy as np # import numpy for C functions (numpy's C API)
051:
052:
+053: np.import_array()
__pyx_t_2 = __pyx_f_5numpy_import_array(); if (unlikely(__pyx_t_2 == ((int)-1))) __PYX_ERR(0, 53, __pyx_L1_error)
054:
055:
056: cdef extern from "find_minpoints_ext.c":
057: # C is included here so that it doesn't need to be compiled externally
058: pass
059:
060:
061: cdef extern from "find_minpoints_ext.h":
062: double* find_minpoints_ext(
063: const double *, const Py_ssize_t, const Py_ssize_t, const Py_ssize_t,
064: const double, const double *, const int, Py_ssize_t *, Py_ssize_t *
065: ) nogil
066:
067:
068:
+069: cpdef find_minpoints(
static PyObject *__pyx_pw_4pept_9utilities_9cutpoints_14find_minpoints_1find_minpoints(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ static PyObject *__pyx_f_4pept_9utilities_9cutpoints_14find_minpoints_find_minpoints(__Pyx_memviewslice __pyx_v_sample_lines, Py_ssize_t __pyx_v_num_lines, double __pyx_v_max_distance, __Pyx_memviewslice __pyx_v_cutoffs, CYTHON_UNUSED int __pyx_skip_dispatch, struct __pyx_opt_args_4pept_9utilities_9cutpoints_14find_minpoints_find_minpoints *__pyx_optional_args) { int __pyx_v_append_indices = ((int)0); Py_ssize_t __pyx_v_nrows; Py_ssize_t __pyx_v_ncols; Py_ssize_t __pyx_v_mpts_nrows; Py_ssize_t __pyx_v_mpts_ncols; double *__pyx_v_minpoints; npy_intp __pyx_v_size[2]; PyArrayObject *__pyx_v_mpts_arr = 0; __Pyx_LocalBuf_ND __pyx_pybuffernd_mpts_arr; __Pyx_Buffer __pyx_pybuffer_mpts_arr; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("find_minpoints", 0); if (__pyx_optional_args) { if (__pyx_optional_args->__pyx_n > 0) { __pyx_v_append_indices = __pyx_optional_args->append_indices; } } __pyx_pybuffer_mpts_arr.pybuffer.buf = NULL; __pyx_pybuffer_mpts_arr.refcount = 0; __pyx_pybuffernd_mpts_arr.data = NULL; __pyx_pybuffernd_mpts_arr.rcbuffer = &__pyx_pybuffer_mpts_arr; /* … */ /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_4); __Pyx_XDECREF(__pyx_t_6); __Pyx_XDECREF(__pyx_t_7); { PyObject *__pyx_type, *__pyx_value, *__pyx_tb; __Pyx_PyThreadState_declare __Pyx_PyThreadState_assign __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb); __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer); __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);} __Pyx_AddTraceback("pept.utilities.cutpoints.find_minpoints.find_minpoints", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = 0; goto __pyx_L2; __pyx_L0:; __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer); __pyx_L2:; __Pyx_XDECREF((PyObject *)__pyx_v_mpts_arr); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* Python wrapper */ static PyObject *__pyx_pw_4pept_9utilities_9cutpoints_14find_minpoints_1find_minpoints(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ static char __pyx_doc_4pept_9utilities_9cutpoints_14find_minpoints_find_minpoints[] = "find_minpoints(double[:, :] sample_lines, Py_ssize_t num_lines, double max_distance, double[:] cutoffs, bool append_indices=0)\nCompute the minimum distance points (MDPs) from all combinations of\n `num_lines` lines given in an array of lines `sample_lines`.\n\n ::\n\n Function signature:\n find_minpoints(\n double[:, :] sample_lines, # LoRs in sample\n Py_ssize_t num_lines, # Number of LoRs in combinations\n double max_distance, # Max distance from MDP to LoRs\n double[:] cutoffs, # Spatial cutoff for minpoints\n bool append_indices = 0 # Append LoR indices used\n )\n\n Given a sample of lines, this functions computes the minimum distance\n points (MDPs) for every possible combination of `num_lines` lines. The\n returned numpy array contains all MDPs that satisfy the following:\n\n 1. Are within the `cutoffs`.\n 2. Are closer to all the constituent LoRs than `max_distance`.\n\n Parameters\n ----------\n sample_lines: (M, N) numpy.ndarray\n A 2D array of lines, where each line is defined by two points such that\n every row is formatted as `[t, x1, y1, z1, x2, y2, z2, etc.]`. It\n *must* have at least 2 lines and the combination size `num_lines`\n *must* be smaller or equal to the number of lines. Put differently:\n 2 <= num_lines <= len(sample_lines).\n\n num_lines: int\n The number of lines in each combination of LoRs used to compute the\n MDP. This function considers every combination of `numlines` from the\n input `sample_lines`. It must be smaller or equal to the number of input\n lines `sample_lines`.\n\n max_distance: float\n The maximum allowed distance between an MDP and its constituent lines.\n If any distance from the MDP to one of its lines is larger than\n `max_distance`, the MDP is thrown away.\n\n cutof""fs: (6,) numpy.ndarray\n An array of spatial cutoff coordinates with *exactly 6 elements* as\n [x_min, x_max, y_min, y_max, z_min, z_max]. If any MDP lies outside\n this region, it is thrown away.\n\n append_indices: bool\n A boolean specifying whether to include the indices of the lines used\n to compute each MDP. If `False`, the output array will only contain the\n [time, x, y, z] of the MDPs. If `True`, the output array will have\n extra columns [time, x, y, z, line_idx(1), ..., line_idx(n)] where\n n = `num_lines`.\n\n Returns\n -------\n minpoints: (M, N) numpy.ndarray\n A 2D array of `float`s containing the time and coordinates of the MDPs\n [time, x, y, z]. The time is computed as the average of the constituent\n lines. If `append_indices` is `True`, then `num_lines` indices of the\n constituent lines are appended as extra columns:\n [time, x, y, z, line_idx1, line_idx2, ..].\n\n Notes\n -----\n There must be at least two lines in `sample_lines` and `num_lines` must be\n greater or equal to the number of lines (i.e. `len(sample_lines)`).\n Put another way: 2 <= num_lines <= len(sample_lines).\n\n This is a low-level Cython function that does not do any checks on the\n input data - it is meant to be used in other modules / libraries. For a\n normal user, the `pept.tracking.peptml` function `find_minpoints` and\n class `Minpoints` are recommended as higher-level APIs. They do check the\n input data and are easier to use (for example, they automatically compute\n the cutoffs).\n\n Examples\n --------\n\n >>> import numpy as np\n >>> from pept.utilities import find_minpoints\n >>>\n >>> lines = np.random.random((500, 7)) * 500\n >>> num_lines = 3\n >>> max_distance = 0.1\n >>> cutoffs = np.array([0, 500, 0, 500, 0, 500], dtype = float)\n >>>\n >>> minpoints = find_minpoints(lines, num_lines, max_d""istance, cutoffs)\n\n "; static PyObject *__pyx_pw_4pept_9utilities_9cutpoints_14find_minpoints_1find_minpoints(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { __Pyx_memviewslice __pyx_v_sample_lines = { 0, 0, { 0 }, { 0 }, { 0 } }; Py_ssize_t __pyx_v_num_lines; double __pyx_v_max_distance; __Pyx_memviewslice __pyx_v_cutoffs = { 0, 0, { 0 }, { 0 }, { 0 } }; int __pyx_v_append_indices; PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("find_minpoints (wrapper)", 0); { static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_sample_lines,&__pyx_n_s_num_lines,&__pyx_n_s_max_distance,&__pyx_n_s_cutoffs,&__pyx_n_s_append_indices,0}; PyObject* values[5] = {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 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_sample_lines)) != 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_num_lines)) != 0)) kw_args--; else { __Pyx_RaiseArgtupleInvalid("find_minpoints", 0, 4, 5, 1); __PYX_ERR(0, 69, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 2: if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_max_distance)) != 0)) kw_args--; else { __Pyx_RaiseArgtupleInvalid("find_minpoints", 0, 4, 5, 2); __PYX_ERR(0, 69, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 3: if (likely((values[3] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_cutoffs)) != 0)) kw_args--; else { __Pyx_RaiseArgtupleInvalid("find_minpoints", 0, 4, 5, 3); __PYX_ERR(0, 69, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 4: if (kw_args > 0) { PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_append_indices); if (value) { values[4] = value; kw_args--; } } } if (unlikely(kw_args > 0)) { if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "find_minpoints") < 0)) __PYX_ERR(0, 69, __pyx_L3_error) } } else { switch (PyTuple_GET_SIZE(__pyx_args)) { case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4); CYTHON_FALLTHROUGH; case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); values[2] = PyTuple_GET_ITEM(__pyx_args, 2); values[1] = PyTuple_GET_ITEM(__pyx_args, 1); values[0] = PyTuple_GET_ITEM(__pyx_args, 0); break; default: goto __pyx_L5_argtuple_error; } } __pyx_v_sample_lines = __Pyx_PyObject_to_MemoryviewSlice_dsds_double(values[0], PyBUF_WRITABLE); if (unlikely(!__pyx_v_sample_lines.memview)) __PYX_ERR(0, 70, __pyx_L3_error) __pyx_v_num_lines = __Pyx_PyIndex_AsSsize_t(values[1]); if (unlikely((__pyx_v_num_lines == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 71, __pyx_L3_error) __pyx_v_max_distance = __pyx_PyFloat_AsDouble(values[2]); if (unlikely((__pyx_v_max_distance == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 72, __pyx_L3_error) __pyx_v_cutoffs = __Pyx_PyObject_to_MemoryviewSlice_ds_double(values[3], PyBUF_WRITABLE); if (unlikely(!__pyx_v_cutoffs.memview)) __PYX_ERR(0, 73, __pyx_L3_error) if (values[4]) { __pyx_v_append_indices = __Pyx_PyObject_IsTrue(values[4]); if (unlikely((__pyx_v_append_indices == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 74, __pyx_L3_error) } else { __pyx_v_append_indices = ((int)0); } } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; __Pyx_RaiseArgtupleInvalid("find_minpoints", 0, 4, 5, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 69, __pyx_L3_error) __pyx_L3_error:; __Pyx_AddTraceback("pept.utilities.cutpoints.find_minpoints.find_minpoints", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; __pyx_r = __pyx_pf_4pept_9utilities_9cutpoints_14find_minpoints_find_minpoints(__pyx_self, __pyx_v_sample_lines, __pyx_v_num_lines, __pyx_v_max_distance, __pyx_v_cutoffs, __pyx_v_append_indices); 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_4pept_9utilities_9cutpoints_14find_minpoints_find_minpoints(CYTHON_UNUSED PyObject *__pyx_self, __Pyx_memviewslice __pyx_v_sample_lines, Py_ssize_t __pyx_v_num_lines, double __pyx_v_max_distance, __Pyx_memviewslice __pyx_v_cutoffs, int __pyx_v_append_indices) { PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("find_minpoints", 0); __Pyx_XDECREF(__pyx_r); __pyx_t_2.__pyx_n = 1; __pyx_t_2.append_indices = __pyx_v_append_indices; __pyx_t_1 = __pyx_f_4pept_9utilities_9cutpoints_14find_minpoints_find_minpoints(__pyx_v_sample_lines, __pyx_v_num_lines, __pyx_v_max_distance, __pyx_v_cutoffs, 0, &__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 69, __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("pept.utilities.cutpoints.find_minpoints.find_minpoints", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __PYX_XDEC_MEMVIEW(&__pyx_v_sample_lines, 1); __PYX_XDEC_MEMVIEW(&__pyx_v_cutoffs, 1); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; }
+070: double[:, :] sample_lines, # LoRs in sample
struct __pyx_opt_args_4pept_9utilities_9cutpoints_14find_minpoints_find_minpoints { int __pyx_n; int append_indices; };
071: Py_ssize_t num_lines, # Number of LoRs in groups for computing MDP
072: double max_distance, # Max allowed distance between two LoRs
073: double[:] cutoffs, # Spatial cutoff for cutpoints
074: bint append_indices = 0 # Append LoR indices used for each cutpoint
075: ):
076: '''Compute the minimum distance points (MDPs) from all combinations of
077: `num_lines` lines given in an array of lines `sample_lines`.
078:
079: ::
080:
081: Function signature:
082: find_minpoints(
083: double[:, :] sample_lines, # LoRs in sample
084: Py_ssize_t num_lines, # Number of LoRs in combinations
085: double max_distance, # Max distance from MDP to LoRs
086: double[:] cutoffs, # Spatial cutoff for minpoints
087: bool append_indices = 0 # Append LoR indices used
088: )
089:
090: Given a sample of lines, this functions computes the minimum distance
091: points (MDPs) for every possible combination of `num_lines` lines. The
092: returned numpy array contains all MDPs that satisfy the following:
093:
094: 1. Are within the `cutoffs`.
095: 2. Are closer to all the constituent LoRs than `max_distance`.
096:
097: Parameters
098: ----------
099: sample_lines: (M, N) numpy.ndarray
100: A 2D array of lines, where each line is defined by two points such that
101: every row is formatted as `[t, x1, y1, z1, x2, y2, z2, etc.]`. It
102: *must* have at least 2 lines and the combination size `num_lines`
103: *must* be smaller or equal to the number of lines. Put differently:
104: 2 <= num_lines <= len(sample_lines).
105:
106: num_lines: int
107: The number of lines in each combination of LoRs used to compute the
108: MDP. This function considers every combination of `numlines` from the
109: input `sample_lines`. It must be smaller or equal to the number of input
110: lines `sample_lines`.
111:
112: max_distance: float
113: The maximum allowed distance between an MDP and its constituent lines.
114: If any distance from the MDP to one of its lines is larger than
115: `max_distance`, the MDP is thrown away.
116:
117: cutoffs: (6,) numpy.ndarray
118: An array of spatial cutoff coordinates with *exactly 6 elements* as
119: [x_min, x_max, y_min, y_max, z_min, z_max]. If any MDP lies outside
120: this region, it is thrown away.
121:
122: append_indices: bool
123: A boolean specifying whether to include the indices of the lines used
124: to compute each MDP. If `False`, the output array will only contain the
125: [time, x, y, z] of the MDPs. If `True`, the output array will have
126: extra columns [time, x, y, z, line_idx(1), ..., line_idx(n)] where
127: n = `num_lines`.
128:
129: Returns
130: -------
131: minpoints: (M, N) numpy.ndarray
132: A 2D array of `float`s containing the time and coordinates of the MDPs
133: [time, x, y, z]. The time is computed as the average of the constituent
134: lines. If `append_indices` is `True`, then `num_lines` indices of the
135: constituent lines are appended as extra columns:
136: [time, x, y, z, line_idx1, line_idx2, ..].
137:
138: Notes
139: -----
140: There must be at least two lines in `sample_lines` and `num_lines` must be
141: greater or equal to the number of lines (i.e. `len(sample_lines)`).
142: Put another way: 2 <= num_lines <= len(sample_lines).
143:
144: This is a low-level Cython function that does not do any checks on the
145: input data - it is meant to be used in other modules / libraries. For a
146: normal user, the `pept.tracking.peptml` function `find_minpoints` and
147: class `Minpoints` are recommended as higher-level APIs. They do check the
148: input data and are easier to use (for example, they automatically compute
149: the cutoffs).
150:
151: Examples
152: --------
153:
154: >>> import numpy as np
155: >>> from pept.utilities import find_minpoints
156: >>>
157: >>> lines = np.random.random((500, 7)) * 500
158: >>> num_lines = 3
159: >>> max_distance = 0.1
160: >>> cutoffs = np.array([0, 500, 0, 500, 0, 500], dtype = float)
161: >>>
162: >>> minpoints = find_minpoints(lines, num_lines, max_distance, cutoffs)
163:
164: '''
165:
166: # Lines for a single sample => (m, n >= 7) array
167: # sample_lines row: [time X1 Y1 Z1 X2 Y2 Z2 etc.]
+168: cdef Py_ssize_t nrows = sample_lines.shape[0]
__pyx_v_nrows = (__pyx_v_sample_lines.shape[0]);
+169: cdef Py_ssize_t ncols = sample_lines.shape[1]
__pyx_v_ncols = (__pyx_v_sample_lines.shape[1]);
170:
+171: cdef Py_ssize_t mpts_nrows = 0
__pyx_v_mpts_nrows = 0;
+172: cdef Py_ssize_t mpts_ncols = 0
__pyx_v_mpts_ncols = 0;
173:
174: cdef double *minpoints
175: cdef np.npy_intp[2] size
176:
+177: 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:; } }
+178: minpoints = find_minpoints_ext(
__pyx_v_minpoints = find_minpoints_ext((&(*((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_sample_lines.data + __pyx_t_1 * __pyx_v_sample_lines.strides[0]) ) + __pyx_t_2 * __pyx_v_sample_lines.strides[1]) )))), __pyx_v_nrows, __pyx_v_ncols, __pyx_v_num_lines, __pyx_v_max_distance, (&(*((double *) ( /* dim=0 */ (__pyx_v_cutoffs.data + __pyx_t_3 * __pyx_v_cutoffs.strides[0]) )))), __pyx_v_append_indices, (&__pyx_v_mpts_nrows), (&__pyx_v_mpts_ncols)); }
+179: &sample_lines[0, 0],
__pyx_t_1 = 0; __pyx_t_2 = 0;
180: nrows,
181: ncols,
182: num_lines,
183: max_distance,
+184: &cutoffs[0],
__pyx_t_3 = 0;
185: append_indices,
186: &mpts_nrows,
187: &mpts_ncols
188: )
189:
+190: size[0] = mpts_nrows
(__pyx_v_size[0]) = __pyx_v_mpts_nrows;
+191: size[1] = mpts_ncols
(__pyx_v_size[1]) = __pyx_v_mpts_ncols;
192:
193: # Use the `minpoints` pointer as the internal data of a numpy array
194: cdef extern from "numpy/arrayobject.h":
195: void PyArray_ENABLEFLAGS(np.ndarray arr, int flags)
196:
+197: cdef np.ndarray[double, ndim=2] mpts_arr = np.PyArray_SimpleNewFromData(
__pyx_t_4 = PyArray_SimpleNewFromData(2, __pyx_v_size, NPY_FLOAT64, __pyx_v_minpoints); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 197, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); if (!(likely(((__pyx_t_4) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_4, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 197, __pyx_L1_error) __pyx_t_5 = ((PyArrayObject *)__pyx_t_4); { __Pyx_BufFmt_StackElem __pyx_stack[1]; if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer, (PyObject*)__pyx_t_5, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 2, 0, __pyx_stack) == -1)) { __pyx_v_mpts_arr = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer.buf = NULL; __PYX_ERR(0, 197, __pyx_L1_error) } else {__pyx_pybuffernd_mpts_arr.diminfo[0].strides = __pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_mpts_arr.diminfo[0].shape = __pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_mpts_arr.diminfo[1].strides = __pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_mpts_arr.diminfo[1].shape = __pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer.shape[1]; } } __pyx_t_5 = 0; __pyx_v_mpts_arr = ((PyArrayObject *)__pyx_t_4); __pyx_t_4 = 0;
198: 2, size, np.NPY_FLOAT64, minpoints
199: )
+200: PyArray_ENABLEFLAGS(mpts_arr, np.NPY_OWNDATA)
PyArray_ENABLEFLAGS(((PyArrayObject *)__pyx_v_mpts_arr), NPY_OWNDATA);
201:
202: # Sort rows based on time (column 0)
+203: mpts_arr = mpts_arr[mpts_arr[:, 0].argsort()]
__pyx_slice_ = PySlice_New(Py_None, Py_None, Py_None); if (unlikely(!__pyx_slice_)) __PYX_ERR(0, 203, __pyx_L1_error) __Pyx_GOTREF(__pyx_slice_); __Pyx_GIVEREF(__pyx_slice_); /* … */ __pyx_t_6 = __Pyx_PyObject_GetItem(((PyObject *)__pyx_v_mpts_arr), __pyx_tuple__2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 203, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_6); __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_argsort); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 203, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_7); __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; __pyx_t_6 = NULL; if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) { __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_7); if (likely(__pyx_t_6)) { PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); __Pyx_INCREF(__pyx_t_6); __Pyx_INCREF(function); __Pyx_DECREF_SET(__pyx_t_7, function); } } __pyx_t_4 = (__pyx_t_6) ? __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6) : __Pyx_PyObject_CallNoArg(__pyx_t_7); __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 203, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; __pyx_t_7 = __Pyx_PyObject_GetItem(((PyObject *)__pyx_v_mpts_arr), __pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 203, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_7); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; if (!(likely(((__pyx_t_7) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_7, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 203, __pyx_L1_error) __pyx_t_5 = ((PyArrayObject *)__pyx_t_7); { __Pyx_BufFmt_StackElem __pyx_stack[1]; __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer); __pyx_t_8 = __Pyx_GetBufferAndValidate(&__pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer, (PyObject*)__pyx_t_5, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 2, 0, __pyx_stack); if (unlikely(__pyx_t_8 < 0)) { PyErr_Fetch(&__pyx_t_9, &__pyx_t_10, &__pyx_t_11); if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer, (PyObject*)__pyx_v_mpts_arr, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 2, 0, __pyx_stack) == -1)) { Py_XDECREF(__pyx_t_9); Py_XDECREF(__pyx_t_10); Py_XDECREF(__pyx_t_11); __Pyx_RaiseBufferFallbackError(); } else { PyErr_Restore(__pyx_t_9, __pyx_t_10, __pyx_t_11); } __pyx_t_9 = __pyx_t_10 = __pyx_t_11 = 0; } __pyx_pybuffernd_mpts_arr.diminfo[0].strides = __pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_mpts_arr.diminfo[0].shape = __pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_mpts_arr.diminfo[1].strides = __pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_mpts_arr.diminfo[1].shape = __pyx_pybuffernd_mpts_arr.rcbuffer->pybuffer.shape[1]; if (unlikely(__pyx_t_8 < 0)) __PYX_ERR(0, 203, __pyx_L1_error) } __pyx_t_5 = 0; __Pyx_DECREF_SET(__pyx_v_mpts_arr, ((PyArrayObject *)__pyx_t_7)); __pyx_t_7 = 0; __pyx_tuple__2 = PyTuple_Pack(2, __pyx_slice_, __pyx_int_0); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 203, __pyx_L1_error) __Pyx_GOTREF(__pyx_tuple__2); __Pyx_GIVEREF(__pyx_tuple__2);
204:
+205: return mpts_arr
__Pyx_XDECREF(__pyx_r); __Pyx_INCREF(((PyObject *)__pyx_v_mpts_arr)); __pyx_r = ((PyObject *)__pyx_v_mpts_arr); goto __pyx_L0;