diff --git a/Makefile b/Makefile index 12375c4..94c66fe 100644 --- a/Makefile +++ b/Makefile @@ -52,14 +52,15 @@ $(tmpdirbuild)/package_creation: $(tmpdirbuild) @echo "********" @echo "********" @echo "\033[0m" - @virtualenv --system-site-packages $(venv_dir) + @virtualenv --system-site-packages $(venv_dir) -p python3 @ . $(activate) && pip install --upgrade pip @ . $(activate) && pip install --upgrade virtualenv @ . $(activate) && pip install nose2 @ . $(activate) && echo `which pip` && pip -V @ . $(activate) && pip install --upgrade setuptools && echo `which pip` && pip -V @ . $(activate) && pip install --upgrade wheel && echo `which pip` && pip -V - @ . $(activate) && pip install numpy scipy pyopengl pillow pyzmq pyyaml && echo `which pip` && pip -V + @ . $(activate) && pip install numpy + @ . $(activate) && pip install scipy pyopengl pillow pyzmq pyyaml && echo `which pip` && pip -V ####### PACKAGE: creating SDIST target @echo "\033[0;33m----- [" ${package_name} "] Creating the source distribution\033[0m" @ . $(activate) && python setup.py sdist diff --git a/mesh/colors.py b/mesh/colors.py index c456b63..281d86b 100644 --- a/mesh/colors.py +++ b/mesh/colors.py @@ -28,7 +28,7 @@ def main(): g = int(reg.group(2)) / 255. b = int(reg.group(3)) / 255. d = reg.group(4) - print "'%s': np.array([%.2f, %.2f, %.2f])," % (d, r, g, b) + print("'%s': np.array([%.2f, %.2f, %.2f])," % (d, r, g, b)) line = fp.readline() diff --git a/mesh/landmarks.py b/mesh/landmarks.py index 0847d1e..ba812cc 100644 --- a/mesh/landmarks.py +++ b/mesh/landmarks.py @@ -47,7 +47,7 @@ def landm_xyz(self, ordering=None): def recompute_landmark_indices(self, landmark_fname=None, safe_mode=True): filtered_landmarks = dict(filter(lambda e, : e[1] != [0.0, 0.0, 0.0], self.landm_raw_xyz.items()) if (landmark_fname and safe_mode) else self.landm_raw_xyz.items()) if len(filtered_landmarks) != len(self.landm_raw_xyz): - print "WARNING: %d landmarks in file %s are positioned at (0.0, 0.0, 0.0) and were ignored" % (len(self.landm_raw_xyz) - len(filtered_landmarks), landmark_fname) + print("WARNING: %d landmarks in file %s are positioned at (0.0, 0.0, 0.0) and were ignored" % (len(self.landm_raw_xyz) - len(filtered_landmarks), landmark_fname)) self.landm = {} self.landm_regressors = {} @@ -85,7 +85,7 @@ def set_landmarks_from_raw(self, landmarks): if np.all(map(lambda x: hasattr(x, "__iter__") and len(x) == 3, landmarks.values())): landmarks = dict((i, np.array(l)) for i, l in landmarks.items()) self.set_landmarks_from_xyz(landmarks) - elif np.all(map(lambda x: isinstance(x, (int, long)), landmarks.values())): + elif np.all(map(lambda x: isinstance(x, int), landmarks.values())): self.landm = landmarks self.recompute_landmark_xyz() else: diff --git a/mesh/lines.py b/mesh/lines.py index 5a51a6e..20ea9a5 100644 --- a/mesh/lines.py +++ b/mesh/lines.py @@ -5,7 +5,7 @@ # See file LICENSE.txt for full license details. import numpy as np -import colors +from . import colors class Lines(object): diff --git a/mesh/mesh.py b/mesh/mesh.py index bada11a..56859ca 100755 --- a/mesh/mesh.py +++ b/mesh/mesh.py @@ -13,10 +13,12 @@ import os +from functools import reduce + import numpy as np -import colors -import search +from . import colors +from . import search try: from .serialization import serialization @@ -153,7 +155,7 @@ def jet(v): result[result < 0.0] = 0.0 return row(result) color = col(color) - color = np.concatenate([jet(color[i]) for i in xrange(color.size)], axis=0) + color = np.concatenate([jet(color[i]) for i in range(color.size)], axis=0) return np.ones_like(arr) * color diff --git a/mesh/meshviewer.py b/mesh/meshviewer.py index d44a522..0c57891 100755 --- a/mesh/meshviewer.py +++ b/mesh/meshviewer.py @@ -90,8 +90,8 @@ # this block is below the previous one to make my linter happy if __package__ is None: - print "this file cannot be executed as a standalone python module" - print "python -m psbody.mesh.%s arguments" % (os.path.splitext(os.path.basename(__file__))[0]) + print("this file cannot be executed as a standalone python module") + print("python -m psbody.mesh.%s arguments" % (os.path.splitext(os.path.basename(__file__))[0])) sys.exit(-1) @@ -110,10 +110,10 @@ def _test_for_opengl(): # from OpenGL.GLUT import glutInit glutInit() except Exception as e: - print >> sys.stderr, e - print 'failure' + print(e, file=sys.stderr) + print('failure') else: - print 'success' + print('success') test_for_opengl_cached = None @@ -129,12 +129,12 @@ def test_for_opengl(): if test_for_opengl_cached is None: p = _run_self(["TEST_FOR_OPENGL"], stderr=subprocess.PIPE) p.wait() - line = '\n'.join(p.stdout.readlines()) + line = ''.join(str(p.stdout.readlines())) test_for_opengl_cached = 'success' in line if not test_for_opengl_cached: - print 'OpenGL test failed: ' - print '\tstdout:', line - print '\tstderr:', '\n'.join(p.stderr.readlines()) + print('OpenGL test failed: ') + print('\tstdout:', line) + print('\tstderr:', '\n'.join(p.stderr.readlines())) return test_for_opengl_cached @@ -311,7 +311,7 @@ class MeshViewerLocal(object): managed = {} def __new__(cls, titlebar, uid, shape, keepalive, window_width, window_height): - assert(uid is None or isinstance(uid, str) or isinstance(uid, unicode)) + assert(uid is None or isinstance(uid, str)) if uid == 'stack': uid = ''.join(traceback.format_list(traceback.extract_stack())) @@ -325,7 +325,7 @@ def __new__(cls, titlebar, uid, shape, keepalive, window_width, window_height): result.p = _run_self([titlebar, str(shape[0]), str(shape[1]), str(window_width), str(window_height)]) line = result.p.stdout.readline() - current_port = re.match('(.*?)', line) + current_port = re.match('(.*?)', line.decode(sys.stdout.encoding)) if not current_port: raise Exception("MeshViewer remote appears to have failed to launch") current_port = int(current_port.group(1)) @@ -870,7 +870,7 @@ def __init__(self, # Print out our port so that our client can connect to us with it. Flush stdout immediately; otherwise # our client could wait forever. - print '%d\n' % (port,) + print('%d\n' % (port,)) sys.stdout.flush() self.arcball = ArcBallT(width, height) @@ -1109,7 +1109,7 @@ def handle_request(self, request): mv.autorecenter = obj self.need_redraw = True elif label == 'titlebar': - assert(isinstance(obj, str) or isinstance(obj, unicode)) + assert(isinstance(obj, str)) self.titlebar = obj glutSetWindowTitle(obj) elif label == 'lighting_on': @@ -1119,7 +1119,7 @@ def handle_request(self, request): glClearColor(obj[0], obj[1], obj[2], 1.0) self.need_redraw = True elif label == 'save_snapshot': # redraws for itself - assert(isinstance(obj, str) or isinstance(obj, unicode)) + assert(isinstance(obj, str)) self.snapshot(obj) elif label == 'get_keypress': self.keypress_port = obj @@ -1213,7 +1213,7 @@ def init_opengl(self): height=int(sys.argv[5])) else: - print "#" * 10 - print 'Usage:' - print "python -m %s.%s arguments" % (__package__, os.path.splitext(os.path.basename(__file__))[0]) + print("#" * 10) + print('Usage:') + print("python -m %s.%s arguments" % (__package__, os.path.splitext(os.path.basename(__file__))[0])) sys.exit(-1) diff --git a/mesh/search.py b/mesh/search.py index 7d682ad..be85520 100644 --- a/mesh/search.py +++ b/mesh/search.py @@ -21,17 +21,18 @@ class AabbTree(object): """Encapsulates an AABB (Axis Aligned Bounding Box) Tree""" def __init__(self, m): - import spatialsearch + from . import spatialsearch + # this shit return NULL self.cpp_handle = spatialsearch.aabbtree_compute(m.v.astype(np.float64).copy(order='C'), m.f.astype(np.uint32).copy(order='C')) def nearest(self, v_samples, nearest_part=False): "nearest_part tells you whether the closest point in triangle abc is in the interior (0), on an edge (ab:1,bc:2,ca:3), or a vertex (a:4,b:5,c:6)" - import spatialsearch + from . import spatialsearch f_idxs, f_part, v = spatialsearch.aabbtree_nearest(self.cpp_handle, np.array(v_samples, dtype=np.float64, order='C')) return (f_idxs, f_part, v) if nearest_part else (f_idxs, v) def nearest_alongnormal(self, points, normals): - import spatialsearch + from . import spatialsearch distances, f_idxs, v = spatialsearch.aabbtree_nearest_alongnormal(self.cpp_handle, points.astype(np.float64), normals.astype(np.float64)) @@ -57,7 +58,7 @@ def nearest_vertices(self, v_samples): class CGALClosestPointTree(object): """Encapsulates an AABB (Axis Aligned Bounding Box) Tree """ def __init__(self, m): - import spatialsearch + from . import spatialsearch self.v = m.v n = m.v.shape[0] faces = np.vstack([np.array(range(n)), np.array(range(n)) + n, np.array(range(n)) + 2 * n]).T @@ -65,12 +66,12 @@ def __init__(self, m): self.cpp_handle = spatialsearch.aabbtree_compute(np.vstack([m.v + eps * np.array([1.0, 0.0, 0.0]), m.v + eps * np.array([0.0, 1.0, 0.0]), m.v - eps * np.array([1.0, 1.0, 0.0])]).astype(np.float64).copy(order='C'), faces.astype(np.uint32).copy(order='C')) def nearest(self, v_samples): - import spatialsearch + from . import spatialsearch f_idxs, f_part, v = spatialsearch.aabbtree_nearest(self.cpp_handle, np.array(v_samples, dtype=np.float64, order='C')) return (f_idxs.flatten(), (np.sum(((self.v[f_idxs.flatten()] - v_samples) ** 2.0), axis=1) ** 0.5).flatten()) def nearest_vertices(self, v_samples): - import spatialsearch + from . import spatialsearch f_idxs, f_part, v = spatialsearch.aabbtree_nearest(self.cpp_handle, np.array(v_samples, dtype=np.float64, order='C')) return self.v[f_idxs.flatten()] @@ -79,11 +80,11 @@ class AabbNormalsTree(object): def __init__(self, m): # the weight of the normals cosine is proportional to the std of the vertices # the best point can be translated up to 2*eps because of the normals - import aabb_normals + from . import aabb_normals eps = 0.1 # np.std(m.v)#0 self.tree_handle = aabb_normals.aabbtree_n_compute(m.v, m.f.astype(np.uint32).copy(), eps) def nearest(self, v_samples, n_samples): - import aabb_normals + from . import aabb_normals closest_tri, closest_p = aabb_normals.aabbtree_n_nearest(self.tree_handle, v_samples, n_samples) return (closest_tri, closest_p) diff --git a/mesh/serialization/serialization.py b/mesh/serialization/serialization.py index 034db53..9503f6e 100755 --- a/mesh/serialization/serialization.py +++ b/mesh/serialization/serialization.py @@ -14,7 +14,6 @@ from ..errors import SerializationError - """ serialization.py @@ -26,6 +25,7 @@ 'set_landmark_indices_from_ppfile', 'set_landmark_indices_from_lmrkfile', 'load_from_ply', 'load_from_file'] + # import os.path @@ -74,7 +74,7 @@ def load_from_obj(self, filename): currLandm = line[1] elif line[0] == 'mtllib': self.materials_filepath = os.path.join(os.path.dirname(filename), line[1]) - self.materials_file = file(self.materials_filepath, 'r').readlines() + self.materials_file = open(self.materials_filepath, 'r').readlines() self.v = np.array(v) self.f = np.array(f) - 1 @@ -149,7 +149,8 @@ def write_face_to_obj_file(face_index, obj_file): if not hasattr(self, 'fn'): self.reset_face_normals() normal_indices = self.fn[face_index][::ff] + 1 - obj_file.write('f %d/%d/%d %d/%d/%d %d/%d/%d\n' % tuple(np.array([vertex_indices, texture_indices, normal_indices]).T.flatten())) + obj_file.write('f %d/%d/%d %d/%d/%d %d/%d/%d\n' % tuple( + np.array([vertex_indices, texture_indices, normal_indices]).T.flatten())) elif hasattr(self, 'fn'): normal_indices = self.fn[face_index][::ff] + 1 obj_file.write('f %d//%d %d//%d %d//%d\n' % tuple(np.array([vertex_indices, normal_indices]).T.flatten())) @@ -272,7 +273,9 @@ def write_three_json(self, filename, name=""): mesh_data["vertices"] = self.v.flatten().tolist() mesh_data["normals"] = self.vn.flatten().tolist() mesh_data["uvs"] = [np.array([[vt[0], vt[1]] for vt in self.vt]).flatten().tolist()] - mesh_data["faces"] = np.array([[42, self.f[i][0], self.f[i][1], self.f[i][2], 0, self.ft[i][0], self.ft[i][1], self.ft[i][2], self.fn[i][0], self.fn[i][1], self.fn[i][2]] for i in range(len(self.f))]).flatten().tolist() + mesh_data["faces"] = np.array([[42, self.f[i][0], self.f[i][1], self.f[i][2], 0, self.ft[i][0], self.ft[i][1], + self.ft[i][2], self.fn[i][0], self.fn[i][1], self.fn[i][2]] for i in + range(len(self.f))]).flatten().tolist() json_or_js_file = open(filename, 'w') json_or_js_file.write(json.dumps(mesh_data, indent=4)) @@ -422,13 +425,19 @@ def load_from_file(self, filename, use_cpp=True): def load_from_ply(self, filename): - import plyutils + from os.path import abspath, dirname, join + + test_data_folder = abspath(join(dirname(__file__), '..', 'data', 'unittest')) + + from psbody.mesh.serialization import plyutils try: res = plyutils.read(filename) - except plyutils.error, e: - raise SerializationError(e.message) + except plyutils.error as e: + raise SerializationError(e) + self.v = np.array(res['pts']).T.copy() self.f = np.array(res['tri']).T.copy() + if 'color' in res: self.set_vertex_colors(np.array(res['color']).T.copy() / 255) if 'normals' in res: diff --git a/mesh/src/aabb_normals.cpp b/mesh/src/aabb_normals.cpp index f0431f8..4005269 100644 --- a/mesh/src/aabb_normals.cpp +++ b/mesh/src/aabb_normals.cpp @@ -35,18 +35,27 @@ static PyMethodDef SpatialsearchMethods[] = { {NULL, NULL, 0, NULL} /* Sentinel */ }; +static struct PyModuleDef moduleDef = +{ + PyModuleDef_HEAD_INIT, + "aabb_normals", /* name of module */ + "", /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ + SpatialsearchMethods +}; - -PyMODINIT_FUNC -initaabb_normals(void) +PyMODINIT_FUNC PyInit_aabb_normals(void) { - (void) Py_InitModule("aabb_normals", SpatialsearchMethods); + PyObject *module = PyModule_Create(&moduleDef); + import_array(); + + return module; } -void aabb_tree_destructor(void *ptr) +void aabb_tree_destructor(PyObject *ptr) { - TreeAndTri* search = (TreeAndTri*)ptr; + TreeAndTri* search = (TreeAndTri*) PyCapsule_GetPointer(ptr, NULL); delete search; } @@ -90,8 +99,8 @@ aabbtree_normals_compute(PyObject *self, PyObject *args) { TreeAndTri* search = new TreeAndTri(m_mesh_tri,m_mesh_points,eps,T,P); - PyObject* result = PyCObject_FromVoidPtr((void*)search, aabb_tree_destructor); - return Py_BuildValue("N", result); + PyObject* result = PyCapsule_New((void*)search, NULL, aabb_tree_destructor); + return result; } catch (mesh_aabb_tree_error&) { @@ -107,7 +116,7 @@ aabbtree_normals_nearest(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "OOO", &py_tree, &py_v, &py_n)) return NULL; - TreeAndTri *search = (TreeAndTri *)PyCObject_AsVoidPtr(py_tree); + TreeAndTri *search = (TreeAndTri *) PyCapsule_GetPointer(py_tree, NULL); npy_intp* v_dims = PyArray_DIMS(py_v); npy_intp* n_dims = PyArray_DIMS(py_n); @@ -174,7 +183,7 @@ aabbtree_normals_selfintersects(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "O", &py_tree)) return NULL; - TreeAndTri *search = (TreeAndTri *)PyCObject_AsVoidPtr(py_tree); + TreeAndTri *search = (TreeAndTri *) PyCapsule_GetPointer(py_tree, NULL); for(Iterator it=search->triangles.begin();it!=search->triangles.end();++it) if(search->tree.do_intersect(*it)) diff --git a/mesh/src/plyutils.c b/mesh/src/plyutils.c index 7d3e17b..4d008d1 100644 --- a/mesh/src/plyutils.c +++ b/mesh/src/plyutils.c @@ -10,17 +10,27 @@ static PyMethodDef PlyutilsMethods[] = { {NULL, NULL, 0, NULL} }; +static struct PyModuleDef moduleDef = +{ + PyModuleDef_HEAD_INIT, + "serialization.plyutils", /* name of module */ + "", /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ + PlyutilsMethods +}; + static PyObject *PlyutilsError; -PyMODINIT_FUNC initplyutils(void) { - PyObject *m; - m = Py_InitModule("plyutils", PlyutilsMethods); +PyMODINIT_FUNC PyInit_plyutils(void) { + PyObject *m = PyModule_Create(&moduleDef); if (m == NULL) - return; + return NULL; PlyutilsError = PyErr_NewException("plyutils.error", NULL, NULL); Py_INCREF(PlyutilsError); PyModule_AddObject(m, "error", PlyutilsError); + + return m; } int has_color(p_ply ply) { @@ -109,8 +119,15 @@ static PyObject * plyutils_read(PyObject *self, PyObject *args) tri = Py_BuildValue("[N,N,N]", PyList_New(n_faces), PyList_New(n_faces), PyList_New(n_faces)); if (!ply_read(ply)) { - PyErr_SetString(PlyutilsError, "Read failed."); - return NULL; + char * msg = "Read failed. "; + char* catString = malloc(strlen(msg)+strlen(filename)+1); + strcpy(catString, msg); + strcat(catString, filename); + + PyErr_SetString(PlyutilsError, catString); + // use the string then delete it when you're done. + free(catString); + return NULL; } ply_close(ply); @@ -160,7 +177,7 @@ static PyObject * plyutils_write(PyObject *self, PyObject *args) res = 1; for (ii = 0; ii < PyList_Size(comments); ++ii) { - comment = PyString_AsString(PyObject_Str(PyList_GetItem(comments, ii))); + comment = PyBytes_AsString(PyObject_Str(PyList_GetItem(comments, ii))); res &= ply_add_comment(ply, comment); } @@ -205,9 +222,9 @@ static PyObject * plyutils_write(PyObject *self, PyObject *args) } if(use_color){ row = PyList_GetItem(color, ii); - res &= ply_write(ply, (unsigned char)PyInt_AsUnsignedLongMask(PyList_GetItem(row, 0))); - res &= ply_write(ply, (unsigned char)PyInt_AsUnsignedLongMask(PyList_GetItem(row, 1))); - res &= ply_write(ply, (unsigned char)PyInt_AsUnsignedLongMask(PyList_GetItem(row, 2))); + res &= ply_write(ply, (unsigned char)PyLong_AsUnsignedLongMask(PyList_GetItem(row, 0))); + res &= ply_write(ply, (unsigned char)PyLong_AsUnsignedLongMask(PyList_GetItem(row, 1))); + res &= ply_write(ply, (unsigned char)PyLong_AsUnsignedLongMask(PyList_GetItem(row, 2))); } } if (!res) { diff --git a/mesh/src/py_loadobj.cpp b/mesh/src/py_loadobj.cpp index 69fa262..5ed2b46 100644 --- a/mesh/src/py_loadobj.cpp +++ b/mesh/src/py_loadobj.cpp @@ -39,17 +39,26 @@ static PyMethodDef loadobj_methods[] = { {NULL, NULL, 0, NULL} /* Sentinel */ }; -PyMODINIT_FUNC -initloadobj(void) +static struct PyModuleDef moduleDef = { - PyObject *m = Py_InitModule("loadobj", loadobj_methods); + PyModuleDef_HEAD_INIT, + "serialization.loadobj", /* name of module */ + "", /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ + loadobj_methods +}; + +PyMODINIT_FUNC PyInit_loadobj(void) { + PyObject *m = PyModule_Create(&moduleDef); if (m == NULL) - return; + return NULL; import_array(); LoadObjError = PyErr_NewException(const_cast("loadobj.LoadObjError"), NULL, NULL); Py_INCREF(LoadObjError); PyModule_AddObject(m, "LoadObjError", LoadObjError); + + return m; } static PyObject * diff --git a/mesh/src/py_visibility.cpp b/mesh/src/py_visibility.cpp index 1fdeecb..6c5ac0f 100644 --- a/mesh/src/py_visibility.cpp +++ b/mesh/src/py_visibility.cpp @@ -24,22 +24,34 @@ static PyMethodDef visibility_methods[] = { {NULL, NULL, 0, NULL} /* Sentinel */ }; -PyMODINIT_FUNC -initvisibility(void) + + +static struct PyModuleDef moduleDef = { - PyObject *m = Py_InitModule("visibility", visibility_methods); + PyModuleDef_HEAD_INIT, + "psbody.mesh.visibility", /* name of module */ + "", /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ + visibility_methods +}; + +PyMODINIT_FUNC PyInit_visibility(void) +{ + PyObject *m = PyModule_Create(&moduleDef); if (m == NULL) - return; + return NULL; import_array(); VisibilityError = PyErr_NewException(const_cast("visibility.VisibilityError"), NULL, NULL); Py_INCREF(VisibilityError); PyModule_AddObject(m, "VisibilityError", VisibilityError); + + return m; } -void visibility_destructor(void *ptr) +void visibility_destructor(PyObject *ptr) { - TreeAndTri* search = (TreeAndTri*)ptr; + TreeAndTri* search = (TreeAndTri*) PyCapsule_GetPointer(ptr, NULL); delete search; } @@ -90,7 +102,7 @@ visibility_compute(PyObject *self, PyObject *args, PyObject *keywds) TreeAndTri* search; if(py_tree != NULL){ - search = (TreeAndTri *)PyCObject_AsVoidPtr(py_tree); + search = (TreeAndTri *)PyCapsule_GetPointer(py_tree, NULL); } else{ @@ -187,8 +199,8 @@ visibility_compute(PyObject *self, PyObject *args, PyObject *keywds) pSensors, min_dist, visibility, normal_dot_cam); if(py_tree == NULL){ - PyObject* py_bin_visibility = PyCObject_FromVoidPtr((void*)search, visibility_destructor); - PyObject* py_normal_dot_cam = PyCObject_FromVoidPtr((void*)search, visibility_destructor); + PyObject* py_bin_visibility = PyCapsule_New((void*)search, NULL, visibility_destructor); + PyObject* py_normal_dot_cam = PyCapsule_New((void*)search, NULL, visibility_destructor); } return Py_BuildValue("NN",py_bin_visibility, py_normal_dot_cam); diff --git a/mesh/src/spatialsearchmodule.cpp b/mesh/src/spatialsearchmodule.cpp index ec982b8..dde2918 100644 --- a/mesh/src/spatialsearchmodule.cpp +++ b/mesh/src/spatialsearchmodule.cpp @@ -21,35 +21,34 @@ using namespace tbb; typedef uint32_t Index; -static PyObject * -spatialsearch_aabbtree_compute(PyObject *self, PyObject *args); +static PyObject* spatialsearch_aabbtree_compute(PyObject *self, PyObject *args); -static PyObject * -spatialsearch_aabbtree_nearest(PyObject *self, PyObject *args); +static PyObject* spatialsearch_aabbtree_nearest(PyObject *self, PyObject *args); -static PyObject * -spatialsearch_aabbtree_nearest_alongnormal(PyObject *self, PyObject *args); +static PyObject* spatialsearch_aabbtree_nearest_alongnormal(PyObject *self, PyObject *args); static PyObject *Mesh_IntersectionsError; static PyMethodDef SpatialsearchMethods[] = { - {"aabbtree_compute", spatialsearch_aabbtree_compute, METH_VARARGS, - "aabbtree_compute."}, - {"aabbtree_nearest", spatialsearch_aabbtree_nearest, METH_VARARGS, - "aabbtree_nearest."}, - {"aabbtree_nearest_alongnormal", spatialsearch_aabbtree_nearest_alongnormal, METH_VARARGS, - "aabbtree_nearest."}, + {"aabbtree_compute", spatialsearch_aabbtree_compute, METH_VARARGS, "aabbtree_compute."}, + {"aabbtree_nearest", spatialsearch_aabbtree_nearest, METH_VARARGS, "aabbtree_nearest."}, + {"aabbtree_nearest_alongnormal", spatialsearch_aabbtree_nearest_alongnormal, METH_VARARGS, "aabbtree_nearest."}, {NULL, NULL, 0} /* Sentinel */ }; +static struct PyModuleDef moduleDef = { + PyModuleDef_HEAD_INIT, + "spatialsearch", /* name of module */ + "", /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ + SpatialsearchMethods +}; +PyMODINIT_FUNC PyInit_spatialsearch(void) { -PyMODINIT_FUNC -initspatialsearch(void) -{ - PyObject *m = Py_InitModule("spatialsearch", SpatialsearchMethods); + PyObject *m = PyModule_Create(&moduleDef); if (m == NULL) { - return; + return NULL; } import_array(); @@ -58,19 +57,21 @@ initspatialsearch(void) Mesh_IntersectionsError = PyErr_NewException(const_cast("spatialsearch.Mesh_IntersectionsError"), NULL, NULL); Py_INCREF(Mesh_IntersectionsError); PyModule_AddObject(m, "Mesh_IntersectionsError", Mesh_IntersectionsError); + + return m; } -void aabb_tree_destructor(void *ptr) +void aabb_tree_destructor(PyObject *ptr) { - TreeAndTri* search = (TreeAndTri*)ptr; + TreeAndTri* search = (TreeAndTri*) PyCapsule_GetPointer(ptr, NULL); delete search; } static PyObject * spatialsearch_aabbtree_compute(PyObject *self, PyObject *args) { - PyArrayObject *py_v = NULL, *py_f = NULL; + PyArrayObject *py_v = NULL, *py_f = NULL; // numpy memory copy, probably managed by python if (!PyArg_ParseTuple(args, "O!O!", &PyArray_Type, &py_v,&PyArray_Type, &py_f)) return NULL; @@ -118,8 +119,8 @@ spatialsearch_aabbtree_compute(PyObject *self, PyObject *args) search->tree.rebuild(search->triangles.begin(), search->triangles.end()); search->tree.accelerate_distance_queries(); - PyObject* result = PyCObject_FromVoidPtr((void*)search, aabb_tree_destructor); - return Py_BuildValue("N", result); + PyObject* result = PyCapsule_New((void*)search, NULL, aabb_tree_destructor); + return result; } void spatialsearch_aabbtree_nearest_one(int ss, TreeAndTri * search, std::vector &sample_points, @@ -144,8 +145,8 @@ class AaBbTreeNearestTbb { uint32_t* closest_part; array* closest_point; public: - void operator()( const blocked_range& r ) const { - for( size_t i=r.begin(); i!=r.end(); ++i ) + void operator()(const blocked_range& r) const { + for (size_t i=r.begin(); i!=r.end(); ++i) spatialsearch_aabbtree_nearest_one(i, search, *sample_points, closest_triangles, closest_part, closest_point); } AaBbTreeNearestTbb( TreeAndTri * search, std::vector *sample_points, @@ -158,13 +159,12 @@ class AaBbTreeNearestTbb { #endif -static PyObject * -spatialsearch_aabbtree_nearest(PyObject *self, PyObject *args) +static PyObject* spatialsearch_aabbtree_nearest(PyObject *self, PyObject *args) { PyObject *py_tree, *py_v; if (!PyArg_ParseTuple(args, "OO!", &py_tree, &PyArray_Type, &py_v)) return NULL; - TreeAndTri *search = (TreeAndTri *)PyCObject_AsVoidPtr(py_tree); + TreeAndTri *search = (TreeAndTri *) PyCapsule_GetPointer(py_tree, NULL); npy_intp* v_dims = PyArray_DIMS(py_v); @@ -201,25 +201,24 @@ spatialsearch_aabbtree_nearest(PyObject *self, PyObject *args) #ifdef HAVE_TBB - parallel_for(blocked_range(0,S), AaBbTreeNearestTbb(search, &sample_points, closest_triangles, closest_part, closest_point)); + parallel_for(blocked_range(0,S), AaBbTreieNearestTbb(search, &sample_points, closest_triangles, closest_part, closest_point)); #else #ifdef HAVE_OPENMP #pragma omp parallel for #endif - for(size_t ss=0; ss* p_arr=reinterpret_cast*>(PyArray_DATA(py_p)); - array* n_arr=reinterpret_cast*>(PyArray_DATA(py_n)); + array* p_arr = reinterpret_cast*>(PyArray_DATA(py_p)); + array* n_arr = reinterpret_cast*>(PyArray_DATA(py_n)); #ifdef _OPENMP omp_set_num_threads(8); @@ -242,7 +241,7 @@ spatialsearch_aabbtree_nearest_alongnormal(PyObject *self, PyObject *args) std::vector n_v; p_v.reserve(S); n_v.reserve(S); - for(size_t ss=0; ss(PyArray_DATA(result1)); + double* distance = reinterpret_cast(PyArray_DATA(result1)); PyObject *result2 = PyArray_SimpleNew(1, result1_dims, NPY_UINT32); - uint32_t* closest_triangles=reinterpret_cast(PyArray_DATA(result2)); + uint32_t* closest_triangles = reinterpret_cast(PyArray_DATA(result2)); npy_intp result3_dims[] = {S, 3}; PyObject *result3 = PyArray_SimpleNew(2, result3_dims, NPY_DOUBLE); diff --git a/mesh/topology/decimation.py b/mesh/topology/decimation.py index 3f7b9bf..fe4cfb3 100644 --- a/mesh/topology/decimation.py +++ b/mesh/topology/decimation.py @@ -144,7 +144,7 @@ def collapse_cost(Qv, r, c, v): cost = collapse_cost(Qv, r, c, mesh.v) if cost['collapse_cost'] > e[0]: heapq.heappush(queue, (cost['collapse_cost'], e[1])) - # print 'found outdated cost, %.2f < %.2f' % (e[0], cost['collapse_cost']) + # print('found outdated cost, %.2f < %.2f' % (e[0], cost['collapse_cost'])) continue else: diff --git a/setup.py b/setup.py index d311efb..3b45793 100644 --- a/setup.py +++ b/setup.py @@ -92,7 +92,7 @@ def finalize_options(self): self.set_undefined_options('install', ('boost_location', 'boost_location'),) if self.boost_location is not None and self.boost_location.strip(): - # avoid empty folder name as it may happen and mess the compiler + # avoid empty folder name as it may happen and mess with the compiler # # we cannot assert that boost_location exist here, because we are # running this code for targets that do not require compilation @@ -113,8 +113,13 @@ def build_extension(self, ext): ext.include_dirs += [os.path.join(os.path.abspath(self.build_temp), 'CGAL-4.7', 'include')] if self.boost_location is not None: ext.include_dirs += [self.boost_location] + # Remove empty paths - ext.include_dirs = filter(None, ext.include_dirs) + filtered = [] + for in_dir in filter(None, ext.include_dirs): + filtered.append(in_dir) + ext.include_dirs = filtered + return _build_ext.build_extension(self, ext) def run(self): diff --git a/tests/test_meshviewer.py b/tests/test_meshviewer.py index f815bdd..0373f69 100644 --- a/tests/test_meshviewer.py +++ b/tests/test_meshviewer.py @@ -22,7 +22,7 @@ class TestMeshViewer(unittest.TestCase): def setUp(self): fnames = [os.path.join(test_data_folder, i) for i in os.listdir(test_data_folder) if os.path.splitext(i)[1].lower() == '.ply'] - self.meshes = [Mesh(filename=fnames[i]) for i in range(4)] + self.meshes = [Mesh(filename=fname) for fname in fnames] def test_launch_smoke_test(self): """this test just opens a mesh window, waits, and kills the window""" @@ -36,9 +36,9 @@ def test_launch_smoke_test(self): sphere = Mesh(filename=os.path.join(test_data_folder, 'sphere.ply')) sphere.v = sphere.v / 10. - print 'keeping MeshViewer alive for 10 seconds..' + print('keeping MeshViewer alive for 10 seconds..') time.sleep(10) - print 'killing MeshViewer and exiting...' + print('killing MeshViewer and exiting...') if 0: # this cannot be unit tested @@ -49,8 +49,8 @@ def test_launch_smoke_test(self): sphere.v = sphere.v - row(np.mean(sphere.v, axis=0)) + row(np.array([click['x'], click['y'], click['z']])) mvs[subwin_row][subwin_col].set_dynamic_meshes([sphere]) - print 'items in mouseclick dict are as follows:' - print click + print('items in mouseclick dict are as follows:') + print(click) @unittest.skipUnless(has_pil, "skipping test that requires Pillow") def test_snapshot(self):