diff --git a/.gitignore b/.gitignore index 700162d..d9266ea 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,27 @@ doc/build .eggs .idea .noseids + +# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode \ No newline at end of file diff --git a/Makefile b/Makefile index f89aaf9..326ecc8 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ package_name := mesh_package all: @echo "\033[0;36m----- [" ${package_name} "] Installing with the interpreter `which python` (version `python --version | cut -d' ' -f2`)\033[0m" @pip install --upgrade -r requirements.txt && pip list - @pip install --no-deps --install-option="--boost-location=$$BOOST_INCLUDE_DIRS" --verbose --no-cache-dir . + @pip install --no-deps --config-settings="--boost-location=$$BOOST_INCLUDE_DIRS" --verbose --no-cache-dir . import_tests: @echo "\033[0;33m----- [" ${package_name} "] Performing import tests\033[0m" diff --git a/README.md b/README.md index 72103d9..8f71a33 100644 --- a/README.md +++ b/README.md @@ -21,18 +21,20 @@ The ``Mesh`` processing libraries support several of our projects such as Requirements ------------ -You first need to install the `Boost `_ -libraries. You can compile your own local version or simply do on -Linux +This package requires the `Boost ` libraries in order to work. -``` +You can either create a dedicated Conda virtual environment and install [Boost from Anaconda](https://anaconda.org/anaconda/boost) (see **Installation with Conda**), or compile your own local version and install it globally on Linux with + +```bash $ sudo apt-get install libboost-dev +# the default BOOST_INCLUDE_DIRS path is /usr/include ``` or on macOS -``` +```bash $ brew install boost +$ brew --prefix boost # show BOOST_INCLUDE_DIRS path ``` Installation @@ -40,7 +42,7 @@ Installation First, create a dedicated Python virtual environment and activate it: -``` +```bash $ python3 -m venv --copies my_venv $ source my_venv/bin/activate ``` @@ -48,16 +50,50 @@ $ source my_venv/bin/activate You should then compile and install the ``psbody-mesh`` package easily using the Makefile: -``` +```bash $ BOOST_INCLUDE_DIRS=/path/to/boost/include make all ``` + +Installation with Conda +------------ + +*Note: This guide has been written for and tested on Linux Ubuntu 18.04; however, given its dependence on Conda, it should be (easily) adaptable to other operative systems.* + +1. First, create a dedicated Python 3 virtual environment and activate it; note that you can replace ``my_venv`` with another string (in all of the following commands) in order to give the virtual environment a custom name: + + ```bash + $ conda create --name my_venv python=3.8 + $ conda activate my_venv + ``` + +2. Install the Boost libraries through an Anaconda package: + + ```bash + $ conda install -c anaconda boost + ``` + +3. Clone into the ``psbody-mesh`` repository: + + ```bash + $ git clone https://github.com/MPI-IS/mesh + ``` + +4. Install the ``psbody-mesh`` package easily with ``pip``: + + ```bash + $ pip install --upgrade -r mesh/requirements.txt + $ pip install --no-deps --install-option="--boost-location=$$BOOST_INCLUDE_DIRS" --verbose --no-cache-dir mesh/. + ``` + +5. Done! Now you can add ``import psbody.mesh`` to any of your Python 3 scripts and execute them in the virtual environment thus created. + Testing ------- To run the tests, simply do: -``` +```bash $ make tests ``` @@ -66,7 +102,7 @@ Documentation A detailed documentation can be compiled using the Makefile: -``` +```bash $ make documentation ``` @@ -82,7 +118,7 @@ package. The most straightforward use-case is viewing the mesh on the same machine where it is stored. To do this simply run -``` +```bash $ meshviewer view sphere.obj ``` @@ -90,14 +126,14 @@ This will create an interactive window with your mesh rendering. You can render more than one mesh in the same window by passing several paths to `view` command -``` +```bash $ meshviewer view sphere.obj cylinder.obj ``` This will arrange the subplots horizontally in a row. If you want a grid arrangement, you can specify the grid parameters explicitly -``` +```bash $ meshviewer view -nx 2 -ny 2 *.obj ``` @@ -108,7 +144,7 @@ this you need mesh to be installed on both the local and the remote machines. You start by opening an empty viewer window listening on a network port -``` +```bash (local) $ meshviewer open --port 3000 ``` @@ -116,14 +152,14 @@ To stream a shape to this viewer you have to either pick a port that is visible from the remote machine or by manually exposing the port when connecting. For example, through SSH port forwarding -``` +```bash (local) $ ssh -R 3000:127.0.0.1:3000 user@host ``` Then on a remote machine you use `view` command pointing to the locally forwarded port -``` +```bash (remote) $ meshviewer view -p 3000 sphere.obj ``` @@ -132,13 +168,13 @@ does not it might be caused by the network connection being closed before the mesh could be sent. To work around this one can try increasing the timeout up to 1 second -``` +```bash (remote) $ meshviewer view -p 3000 --timeout 1 sphere.obj ``` To take a snapshot you should locally run a `snap` command -``` +```bash (local) $ meshviewer snap -p 3000 sphere.png ``` diff --git a/mesh/src/aabb_normals.cpp b/mesh/src/aabb_normals.cpp index 758ec4e..d122eff 100644 --- a/mesh/src/aabb_normals.cpp +++ b/mesh/src/aabb_normals.cpp @@ -1,4 +1,3 @@ - // needed to avoid the link to debug "_d.lib" libraries #include "hijack_python_headers.hpp" #include @@ -66,17 +65,17 @@ aabbtree_normals_compute(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "O!O!d", &PyArray_Type, &py_v, &PyArray_Type, &py_f, &eps)) return NULL; - if (py_v->descr->type_num != NPY_DOUBLE || py_v->nd != 2) { + if (PyArray_TYPE((PyArrayObject *)py_v) != NPY_DOUBLE || PyArray_NDIM((PyArrayObject *)py_v) != 2) { PyErr_SetString(PyExc_ValueError, "Vertices must be of type double, and 2 dimensional"); return NULL; } - if (py_f->descr->type_num != NPY_UINT32 || py_f->nd != 2) { + if (PyArray_TYPE((PyArrayObject *)py_f) != NPY_UINT32 || PyArray_NDIM((PyArrayObject *)py_f) != 2) { PyErr_SetString(PyExc_ValueError, "Faces must be of type uint32, and 2 dimensional"); return NULL; } - npy_intp* v_dims = PyArray_DIMS(py_v); - npy_intp* f_dims = PyArray_DIMS(py_f); + npy_intp* v_dims = PyArray_DIMS((PyArrayObject *)py_v); + npy_intp* f_dims = PyArray_DIMS((PyArrayObject *)py_f); if (v_dims[1] != 3 || f_dims[1] != 3) { PyErr_SetString(PyExc_ValueError, "Input must be Nx3"); @@ -129,8 +128,8 @@ aabbtree_normals_nearest(PyObject *self, PyObject *args) size_t S=v_dims[0]; - array* m_sample_points=reinterpret_cast*>(PyArray_DATA(py_v)); - array* m_sample_n=reinterpret_cast*>(PyArray_DATA(py_n)); + array* m_sample_points=reinterpret_cast*>(PyArray_DATA((PyArrayObject *)py_v)); + array* m_sample_n=reinterpret_cast*>(PyArray_DATA((PyArrayObject *)py_n)); #ifdef _OPENMP omp_set_num_threads(8); @@ -147,14 +146,14 @@ aabbtree_normals_nearest(PyObject *self, PyObject *args) m_sample_n[ss][2]))); } - npy_intp result1_dims[] = {1, S}; + npy_intp result1_dims[] = {1, static_cast(S)}; PyObject *result1 = PyArray_SimpleNew(2, result1_dims, NPY_UINT32); uint32_t* closest_triangles=reinterpret_cast(PyArray_DATA(result1)); array* closest_point=NULL; //if(1) { //nlhs > 1) { - npy_intp result2_dims[] = {S, 3}; + npy_intp result2_dims[] = {static_cast(S), 3}; PyObject *result2 = PyArray_SimpleNew(2, result2_dims, NPY_DOUBLE); closest_point=reinterpret_cast*>(PyArray_DATA(result2)); //} diff --git a/mesh/src/py_visibility.cpp b/mesh/src/py_visibility.cpp index 6ffd4da..41778da 100644 --- a/mesh/src/py_visibility.cpp +++ b/mesh/src/py_visibility.cpp @@ -192,7 +192,7 @@ visibility_compute(PyObject *self, PyObject *args, PyObject *keywds) size_t C = cam_dims[0]; - npy_intp result_dims[] = {C,search->points.size()}; + npy_intp result_dims[] = {static_cast(C), static_cast(search->points.size())}; PyObject *py_bin_visibility = PyArray_SimpleNew(2, result_dims, NPY_UINT32); PyObject *py_normal_dot_cam = PyArray_SimpleNew(2, result_dims, NPY_DOUBLE); uint32_t* visibility = reinterpret_cast(PyArray_DATA(py_bin_visibility)); diff --git a/mesh/src/spatialsearchmodule.cpp b/mesh/src/spatialsearchmodule.cpp index d452204..e26bdf0 100644 --- a/mesh/src/spatialsearchmodule.cpp +++ b/mesh/src/spatialsearchmodule.cpp @@ -187,7 +187,7 @@ static PyObject* spatialsearch_aabbtree_nearest(PyObject *self, PyObject *args) sample_points.push_back(K::Point_3(m_sample_points[ss][0], m_sample_points[ss][1], m_sample_points[ss][2])); } - npy_intp result1_dims[] = {1, S}; + npy_intp result1_dims[] = {1, static_cast(S)}; PyObject *result1 = PyArray_SimpleNew(2, result1_dims, NPY_UINT32); PyObject *result2 = PyArray_SimpleNew(2, result1_dims, NPY_UINT32); @@ -195,7 +195,7 @@ static PyObject* spatialsearch_aabbtree_nearest(PyObject *self, PyObject *args) uint32_t* closest_triangles=reinterpret_cast(PyArray_DATA(result1)); uint32_t* closest_part=reinterpret_cast(PyArray_DATA(result2)); - npy_intp result3_dims[] = {S, 3}; + npy_intp result3_dims[] = {static_cast(S), 3}; PyObject *result3 = PyArray_SimpleNew(2, result3_dims, NPY_DOUBLE); array* closest_point = reinterpret_cast*>(PyArray_DATA(result3)); @@ -246,7 +246,7 @@ static PyObject* spatialsearch_aabbtree_nearest_alongnormal(PyObject *self, PyOb n_v.push_back(K::Vector_3(n_arr[ss][0], n_arr[ss][1], n_arr[ss][2])); } - npy_intp result1_dims[] = {S}; + npy_intp result1_dims[] = {static_cast(S)}; PyObject *result1 = PyArray_SimpleNew(1, result1_dims, NPY_DOUBLE); @@ -255,7 +255,7 @@ static PyObject* spatialsearch_aabbtree_nearest_alongnormal(PyObject *self, PyOb PyObject *result2 = PyArray_SimpleNew(1, result1_dims, NPY_UINT32); uint32_t* closest_triangles = reinterpret_cast(PyArray_DATA(result2)); - npy_intp result3_dims[] = {S, 3}; + npy_intp result3_dims[] = {static_cast(S), 3}; PyObject *result3 = PyArray_SimpleNew(2, result3_dims, NPY_DOUBLE); array* closest_point = reinterpret_cast*>(PyArray_DATA(result3)); @@ -393,7 +393,7 @@ static PyObject * spatialsearch_aabbtree_intersections_indices(PyObject *self, P } // GET RESULT BACK - npy_intp result_dims[] = {mesh_intersections.size()}; + npy_intp result_dims[] = {static_cast(mesh_intersections.size())}; PyObject *result = PyArray_SimpleNew(1, result_dims, NPY_UINT32); uint32_t* mesh_intersections_arr = reinterpret_cast(PyArray_DATA(result)); diff --git a/requirements.txt b/requirements.txt index 1759429..0834e17 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ setuptools -numpy +numpy==1.23.5 matplotlib scipy pyopengl diff --git a/setup.py b/setup.py index 0da199e..eedbfa8 100644 --- a/setup.py +++ b/setup.py @@ -113,6 +113,11 @@ def build_extension(self, ext): if self.boost_location is not None: ext.include_dirs += [self.boost_location] + ext.include_dirs += [ + '/usr/local/include', + '/opt/homebrew/opt/boost/include' + ] + # Remove empty paths filtered = [] for in_dir in filter(None, ext.include_dirs):