Skip to content

Commit

Permalink
Merge pull request #8 from Dawars/python3
Browse files Browse the repository at this point in the history
Merging the PR onto develop instead of master because some extra work is needed to complete this feature.
  • Loading branch information
jcpassy authored Oct 16, 2019
2 parents 1761d54 + 87499d9 commit b8cb50b
Show file tree
Hide file tree
Showing 16 changed files with 183 additions and 119 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion mesh/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()


Expand Down
4 changes: 2 additions & 2 deletions mesh/landmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion mesh/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# See file LICENSE.txt for full license details.

import numpy as np
import colors
from . import colors


class Lines(object):
Expand Down
8 changes: 5 additions & 3 deletions mesh/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
34 changes: 17 additions & 17 deletions mesh/meshviewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)


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


Expand Down Expand Up @@ -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()))
Expand All @@ -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('<PORT>(.*?)</PORT>', line)
current_port = re.match('<PORT>(.*?)</PORT>', 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))
Expand Down Expand Up @@ -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 '<PORT>%d</PORT>\n' % (port,)
print('<PORT>%d</PORT>\n' % (port,))
sys.stdout.flush()

self.arcball = ArcBallT(width, height)
Expand Down Expand Up @@ -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':
Expand All @@ -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
Expand Down Expand Up @@ -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)
17 changes: 9 additions & 8 deletions mesh/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -57,20 +58,20 @@ 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
eps = 0.000000000001
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()]

Expand All @@ -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)
23 changes: 16 additions & 7 deletions mesh/serialization/serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from ..errors import SerializationError


"""
serialization.py
Expand All @@ -26,6 +25,7 @@
'set_landmark_indices_from_ppfile', 'set_landmark_indices_from_lmrkfile',
'load_from_ply', 'load_from_file']


# import os.path


Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()))
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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:
Expand Down
29 changes: 19 additions & 10 deletions mesh/src/aabb_normals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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&)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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))
Expand Down
Loading

0 comments on commit b8cb50b

Please sign in to comment.