| 74 | |
| 75 | |
| 76 | PyObject* marching_cubes(PyArrayObject* arr, double isovalue) |
| 77 | { |
| 78 | if(PyArray_NDIM(arr) != 3) |
| 79 | throw std::runtime_error("Only three-dimensional arrays are supported."); |
| 80 | |
| 81 | // Prepare data. |
| 82 | npy_intp* shape = PyArray_DIMS(arr); |
| 83 | std::array<long, 3> lower{0, 0, 0}; |
| 84 | std::array<long, 3> upper{shape[0]-1, shape[1]-1, shape[2]-1}; |
| 85 | long numx = upper[0] - lower[0] + 1; |
| 86 | long numy = upper[1] - lower[1] + 1; |
| 87 | long numz = upper[2] - lower[2] + 1; |
| 88 | std::vector<double> vertices; |
| 89 | std::vector<size_t> polygons; |
| 90 | |
| 91 | auto pyarray_to_cfunc = [&](long x, long y, long z) -> double { |
| 92 | const npy_intp c[3] = {x, y, z}; |
| 93 | return PyArray_SafeGet<double>(arr, c); |
| 94 | }; |
| 95 | |
| 96 | // Marching cubes. |
| 97 | mc::marching_cubes(lower, upper, numx, numy, numz, pyarray_to_cfunc, isovalue, |
| 98 | vertices, polygons); |
| 99 | |
| 100 | // Copy the result to two Python ndarrays. |
| 101 | npy_intp size_vertices = vertices.size(); |
| 102 | npy_intp size_polygons = polygons.size(); |
| 103 | PyArrayObject* verticesarr = reinterpret_cast<PyArrayObject*>(PyArray_SimpleNew(1, &size_vertices, NPY_DOUBLE)); |
| 104 | PyArrayObject* polygonsarr = reinterpret_cast<PyArrayObject*>(PyArray_SimpleNew(1, &size_polygons, NPY_ULONG)); |
| 105 | |
| 106 | std::vector<double>::const_iterator it = vertices.begin(); |
| 107 | for(int i=0; it!=vertices.end(); ++i, ++it) |
| 108 | *reinterpret_cast<double*>(PyArray_GETPTR1(verticesarr, i)) = *it; |
| 109 | std::vector<size_t>::const_iterator it2 = polygons.begin(); |
| 110 | for(int i=0; it2!=polygons.end(); ++i, ++it2) |
| 111 | *reinterpret_cast<unsigned long*>(PyArray_GETPTR1(polygonsarr, i)) = *it2; |
| 112 | |
| 113 | PyObject* res = Py_BuildValue("(O,O)", verticesarr, polygonsarr); |
| 114 | Py_XDECREF(verticesarr); |
| 115 | Py_XDECREF(polygonsarr); |
| 116 | |
| 117 | return res; |
| 118 | } |
no outgoing calls
no test coverage detected