Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
70 changes: 53 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,43 +21,79 @@ The ``Mesh`` processing libraries support several of our projects such as
Requirements
------------

You first need to install the `Boost <http://www.boost.org>`_
libraries. You can compile your own local version or simply do on
Linux
This package requires the `Boost <http://www.boost.org>` 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
------------

First, create a dedicated Python virtual environment and activate it:

```
```bash
$ python3 -m venv --copies my_venv
$ 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
```

Expand All @@ -66,7 +102,7 @@ Documentation

A detailed documentation can be compiled using the Makefile:

```
```bash
$ make documentation
```

Expand All @@ -82,22 +118,22 @@ 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
```

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
```

Expand All @@ -108,22 +144,22 @@ 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
```

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
```

Expand All @@ -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
```

Expand Down
17 changes: 8 additions & 9 deletions mesh/src/aabb_normals.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

// needed to avoid the link to debug "_d.lib" libraries
#include "hijack_python_headers.hpp"
#include <numpy/arrayobject.h>
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -129,8 +128,8 @@ aabbtree_normals_nearest(PyObject *self, PyObject *args)

size_t S=v_dims[0];

array<double, 3>* m_sample_points=reinterpret_cast<array<double,3>*>(PyArray_DATA(py_v));
array<double, 3>* m_sample_n=reinterpret_cast<array<double,3>*>(PyArray_DATA(py_n));
array<double, 3>* m_sample_points=reinterpret_cast<array<double,3>*>(PyArray_DATA((PyArrayObject *)py_v));
array<double, 3>* m_sample_n=reinterpret_cast<array<double,3>*>(PyArray_DATA((PyArrayObject *)py_n));

#ifdef _OPENMP
omp_set_num_threads(8);
Expand All @@ -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<npy_intp>(S)};

PyObject *result1 = PyArray_SimpleNew(2, result1_dims, NPY_UINT32);

uint32_t* closest_triangles=reinterpret_cast<uint32_t*>(PyArray_DATA(result1));
array<double,3>* closest_point=NULL;
//if(1) { //nlhs > 1) {
npy_intp result2_dims[] = {S, 3};
npy_intp result2_dims[] = {static_cast<npy_intp>(S), 3};
PyObject *result2 = PyArray_SimpleNew(2, result2_dims, NPY_DOUBLE);
closest_point=reinterpret_cast<array<double,3>*>(PyArray_DATA(result2));
//}
Expand Down
2 changes: 1 addition & 1 deletion mesh/src/py_visibility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<npy_intp>(C), static_cast<npy_intp>(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<uint32_t*>(PyArray_DATA(py_bin_visibility));
Expand Down
10 changes: 5 additions & 5 deletions mesh/src/spatialsearchmodule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,15 @@ 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<npy_intp>(S)};

PyObject *result1 = PyArray_SimpleNew(2, result1_dims, NPY_UINT32);
PyObject *result2 = PyArray_SimpleNew(2, result1_dims, NPY_UINT32);

uint32_t* closest_triangles=reinterpret_cast<uint32_t*>(PyArray_DATA(result1));
uint32_t* closest_part=reinterpret_cast<uint32_t*>(PyArray_DATA(result2));

npy_intp result3_dims[] = {S, 3};
npy_intp result3_dims[] = {static_cast<npy_intp>(S), 3};
PyObject *result3 = PyArray_SimpleNew(2, result3_dims, NPY_DOUBLE);
array<double,3>* closest_point = reinterpret_cast<array<double,3>*>(PyArray_DATA(result3));

Expand Down Expand Up @@ -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<npy_intp>(S)};

PyObject *result1 = PyArray_SimpleNew(1, result1_dims, NPY_DOUBLE);

Expand All @@ -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<uint32_t*>(PyArray_DATA(result2));

npy_intp result3_dims[] = {S, 3};
npy_intp result3_dims[] = {static_cast<npy_intp>(S), 3};
PyObject *result3 = PyArray_SimpleNew(2, result3_dims, NPY_DOUBLE);
array<double,3>* closest_point = reinterpret_cast<array<double,3>*>(PyArray_DATA(result3));

Expand Down Expand Up @@ -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<npy_intp>(mesh_intersections.size())};
PyObject *result = PyArray_SimpleNew(1, result_dims, NPY_UINT32);

uint32_t* mesh_intersections_arr = reinterpret_cast<uint32_t*>(PyArray_DATA(result));
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
setuptools
numpy
numpy==1.23.5
matplotlib
scipy
pyopengl
Expand Down
5 changes: 5 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down