diff --git a/python/matlab/CurvatureDirections.m b/python/matlab/CurvatureDirections.m deleted file mode 100755 index db6279f0a..000000000 --- a/python/matlab/CurvatureDirections.m +++ /dev/null @@ -1,59 +0,0 @@ -V = py.igl.eigen.MatrixXd(); -F = py.igl.eigen.MatrixXi(); -py.igl.read_triangle_mesh('../tutorial/shared/fertility.off', V, F); - -% Alternative discrete mean curvature -HN = py.igl.eigen.MatrixXd(); -L = py.igl.eigen.SparseMatrixd(); -M = py.igl.eigen.SparseMatrixd(); -Minv = py.igl.eigen.SparseMatrixd(); - - -py.igl.cotmatrix(V,F,L) -py.igl.massmatrix(V,F,py.igl.MASSMATRIX_TYPE_VORONOI,M) - -py.igl.invert_diag(M,Minv) - -% Laplace-Beltrami of position -HN = -Minv*(L*V) - -% Extract magnitude as mean curvature -H = HN.rowwiseNorm() - -% Compute curvature directions via quadric fitting -PD1 = py.igl.eigen.MatrixXd() -PD2 = py.igl.eigen.MatrixXd() - -PV1 = py.igl.eigen.MatrixXd() -PV2 = py.igl.eigen.MatrixXd() - -py.igl.principal_curvature(V,F,PD1,PD2,PV1,PV2) - -% Mean curvature -H = 0.5*(PV1+PV2) - -viewer = py.igl.viewer.Viewer() -viewer.data.set_mesh(V, F) - -% Compute pseudocolor -C = py.igl.eigen.MatrixXd() -py.igl.parula(H,true,C) - -viewer.data.set_colors(C) - -% Average edge length for sizing -avg = py.igl.avg_edge_length(V,F) - -% Draw a blue segment parallel to the minimal curvature direction -red = py.iglhelpers.p2e(py.numpy.array([[0.8,0.2,0.2]])) -blue = py.iglhelpers.p2e(py.numpy.array([[0.2,0.2,0.8]])) - -viewer.data.add_edges(V + PD1*avg, V - PD1*avg, blue) - -% Draw a red segment parallel to the maximal curvature direction -viewer.data.add_edges(V + PD2*avg, V - PD2*avg, red) - -% Hide wireframe -viewer.core.show_lines = false - -viewer.launch() diff --git a/python/matlab/example1.m b/python/matlab/example1.m new file mode 100644 index 000000000..ce66343f1 --- /dev/null +++ b/python/matlab/example1.m @@ -0,0 +1,18 @@ +%% Launch the external viewer +launch_viewer; + +%% Load a mesh in OFF format +V = py.igl.eigen.MatrixXd(); +F = py.igl.eigen.MatrixXi(); +py.igl.readOFF('../tutorial/shared/beetle.off', V, F); + +%% Scale the x coordinate in matlab +V = p2m(V); +V(:,1) = V(:,1) * 2; +V = m2p(V); + +%% Plot the mesh +viewer = py.tcpviewer_single.TCPViewer(); +viewer.data.set_mesh(V, F); +viewer.launch(); + diff --git a/python/matlab/example2.m b/python/matlab/example2.m new file mode 100644 index 000000000..5be77cf22 --- /dev/null +++ b/python/matlab/example2.m @@ -0,0 +1,60 @@ +% Launch the external viewer +launch_viewer; + +V = py.igl.eigen.MatrixXd(); +F = py.igl.eigen.MatrixXi(); +py.igl.read_triangle_mesh('../tutorial/shared/fertility.off', V, F); + +% Alternative discrete mean curvature +HN = py.igl.eigen.MatrixXd(); +L = py.igl.eigen.SparseMatrixd(); +M = py.igl.eigen.SparseMatrixd(); +Minv = py.igl.eigen.SparseMatrixd(); + + +py.igl.cotmatrix(V,F,L); +py.igl.massmatrix(V,F,py.igl.MASSMATRIX_TYPE_VORONOI,M); + +py.igl.invert_diag(M,Minv); + +% Laplace-Beltrami of position +HN = -Minv*(L*V); + +% Extract magnitude as mean curvature +H = HN.rowwiseNorm(); + +% Compute curvature directions via quadric fitting +PD1 = py.igl.eigen.MatrixXd(); +PD2 = py.igl.eigen.MatrixXd(); + +PV1 = py.igl.eigen.MatrixXd(); +PV2 = py.igl.eigen.MatrixXd(); + +py.igl.principal_curvature(V,F,PD1,PD2,PV1,PV2); + +% Mean curvature +H = 0.5*(PV1+PV2); + +viewer = py.tcpviewer_single.TCPViewer(); +viewer.data.set_mesh(V, F); + +% Compute pseudocolor +C = py.igl.eigen.MatrixXd(); +py.igl.parula(H,true,C); + +viewer.data.set_colors(C); + +% Average edge length for sizing +avg = py.igl.avg_edge_length(V,F); + +% Draw a blue segment parallel to the minimal curvature direction +red = m2p([0.8,0.2,0.2]); +blue = m2p([0.2,0.2,0.8]); + +viewer.data.add_edges(V + PD1*avg, V - PD1*avg, blue); + +% Draw a red segment parallel to the maximal curvature direction +viewer.data.add_edges(V + PD2*avg, V - PD2*avg, red); + +% Plot +viewer.launch() diff --git a/python/matlab/launch_viewer.m b/python/matlab/launch_viewer.m new file mode 100644 index 000000000..b76e1e176 --- /dev/null +++ b/python/matlab/launch_viewer.m @@ -0,0 +1,3 @@ +system('python tcpviewer_single.py&'); + +pause(0.1) % Wait a bit for the viewer to start \ No newline at end of file diff --git a/python/matlab/m2p.m b/python/matlab/m2p.m new file mode 100644 index 000000000..e76548533 --- /dev/null +++ b/python/matlab/m2p.m @@ -0,0 +1,19 @@ +% Converts a Matlab matrix to a python-wrapped Eigen Matrix +function [ P ] = m2p( M ) + if (isa(M, 'double')) + % Convert the matrix to a python 1D array + a = py.array.array('d',reshape(M,1,numel(M))); + % Then convert it to a eigen type + t = py.igl.eigen.MatrixXd(a.tolist()); + % Finally reshape it back + P = t.MapMatrix(uint16(size(M,1)),uint16(size(M,2))); + elseif (isa(M, 'integer')) + % Convert the matrix to a python 1D array + a = py.array.array('i',reshape(M,1,numel(M))); + % Then convert it to a eigen type + t = py.igl.eigen.MatrixXi(a.tolist()); + % Finally reshape it back + P = t.MapMatrix(uint16(size(M,1)),uint16(size(M,2))); + else + error('Unsupported numerical type.'); + end diff --git a/python/matlab/p2m.m b/python/matlab/p2m.m new file mode 100644 index 000000000..bfaf79f15 --- /dev/null +++ b/python/matlab/p2m.m @@ -0,0 +1,17 @@ +% Converts a python-wrapped Eigen Matrix to a Matlab matrix +function [ M ] = p2m( P ) + if py.repr(py.type(P)) == '' + % Convert it to a python array first + t = py.array.array('d',P); + % Reshape it + M = reshape(double(t),P.rows(),P.cols()); + elseif py.repr(py.type(P)) == '' + % Convert it to a python array first + t = py.array.array('i',P); + % Reshape it + M = reshape(int32(t),P.rows(),P.cols()); + else + error('Unsupported numerical type.'); + end +end + diff --git a/python/matlab/t102DrawMesh.m b/python/matlab/t102DrawMesh.m deleted file mode 100644 index 015ecccc8..000000000 --- a/python/matlab/t102DrawMesh.m +++ /dev/null @@ -1,12 +0,0 @@ -% Load a mesh in OFF format -V = py.igl.eigen.MatrixXd(); -F = py.igl.eigen.MatrixXi(); -py.igl.readOFF('../tutorial/shared/beetle.off', V, F); - -V - -% Plot the mesh -viewer = py.tcpviewer.TCPViewer() -viewer.data.set_mesh(V, F) -viewer.launch() - diff --git a/python/py_vector.cpp b/python/py_vector.cpp index 5434b2285..b4932fbe7 100644 --- a/python/py_vector.cpp +++ b/python/py_vector.cpp @@ -47,6 +47,25 @@ py::class_ bind_eigen_2(py::module &m, const char *name, return; }) + .def("__init__", [](Type &m, std::vector& b) { + if (b.size() == 0) + { + new (&m) Type(0, 0); + return; + } + + // Size checks + unsigned rows = b.size(); + unsigned cols = 1; + + new (&m) Type(rows, cols); + + m.resize(rows,cols); + for (unsigned i=0;i::value()) diff --git a/python/tcpviewer.py b/python/tcpviewer.py index 8847e3cb7..b89ec536c 100644 --- a/python/tcpviewer.py +++ b/python/tcpviewer.py @@ -1,45 +1,80 @@ import socket -import multiprocessing +import threading import igl import array +import time HOST = 'localhost' # Symbolic name meaning all available interfaces PORT = 50008 # Arbitrary non-privileged port -def worker(data): - viewer = igl.viewer.Viewer() - temp = list(data) - viewer.deserialize(temp) - viewer.launch(True,False) - return +def worker(viewer,lock,s): -class TCPViewer(igl.viewer.Viewer): - def launch(self): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((HOST, PORT)) - a = array.array('u',self.serialize()) - s.sendall(a) - s.close() - -if __name__ == "__main__": # The main script is a server - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.bind((HOST, PORT)) - s.listen(1) print("TCP iglviewer server listening on port " + str(PORT)) try: while True: conn, addr = s.accept() + lock.acquire() slist = [] while True: - buf = conn.recv(4096) + buf = conn.recv(10000000) if not buf: break slist.append(buf.decode('unicode_internal','ignore')) conn.close() data = ''.join(slist) + temp = list(data) + + isempty = viewer.data.V.rows() == 0 + viewer.data.deserialize(temp) + if isempty and viewer.data.V.rows() != 0: + viewer.core.align_camera_center(viewer.data.V,viewer.data.F) + + lock.release() - t = multiprocessing.Process(target=worker, args=(data,)) - t.start() except: s.close() + return + +class TCPViewer(igl.viewer.Viewer): + def launch(self): + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((HOST, PORT)) + a = array.array('u',self.data.serialize()) + s.sendall(a) + s.close() + except: + print("Failed to open socket, is tcpviewer running?") + +if __name__ == "__main__": # The main script is a server + + ## Try to open the socket first + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.bind((HOST, PORT)) + except: + print("Failed to bind, port already used.") + exit(1) + s.listen(1) + + viewer = igl.viewer.Viewer() + + lock = threading.Lock() + t = threading.Thread(target=worker, args=(viewer,lock,s,)) + t.setDaemon(True) + t.start() + + viewer.core.is_animating = True + # viewer.data.dirty = int(0x03FF) + + viewer.launch_init(True,False) + done = False + while not done: + lock.acquire() + done = not viewer.launch_rendering(False) + lock.release() + + time.sleep(0.000001) # DO NOT REMOVE ME + + viewer.launch_shut() diff --git a/python/tcpviewer_single.py b/python/tcpviewer_single.py deleted file mode 100644 index 43fd4fd1a..000000000 --- a/python/tcpviewer_single.py +++ /dev/null @@ -1,69 +0,0 @@ -import socket -import threading -import igl -import array -import time - -HOST = 'localhost' # Symbolic name meaning all available interfaces -PORT = 50008 # Arbitrary non-privileged port - -def worker(viewer,lock): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.bind((HOST, PORT)) - s.listen(1) - print("TCP iglviewer server listening on port " + str(PORT)) - try: - while True: - conn, addr = s.accept() - lock.acquire() - slist = [] - while True: - buf = conn.recv(4096) - if not buf: - break - slist.append(buf.decode('unicode_internal','ignore')) - conn.close() - - data = ''.join(slist) - temp = list(data) - - isempty = viewer.data.V.rows() == 0 - viewer.data.deserialize(temp) - if isempty and viewer.data.V.rows() != 0: - viewer.core.align_camera_center(viewer.data.V,viewer.data.F) - - lock.release() - - except: - s.close() - return - -class TCPViewer(igl.viewer.Viewer): - def launch(self): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((HOST, PORT)) - a = array.array('u',self.data.serialize()) - s.sendall(a) - s.close() - -if __name__ == "__main__": # The main script is a server - viewer = igl.viewer.Viewer() - - lock = threading.Lock() - t = threading.Thread(target=worker, args=(viewer,lock,)) - t.setDaemon(True) - t.start() - - viewer.core.is_animating = True - # viewer.data.dirty = int(0x03FF) - - viewer.launch_init(True,False) - done = False - while not done: - lock.acquire() - done = not viewer.launch_rendering(False) - lock.release() - - time.sleep(0.000001) # DO NOT REMOVE ME - - viewer.launch_shut() diff --git a/python/tutorial/102_DrawMeshTCP.py b/python/tutorial/102_DrawMeshTCP.py deleted file mode 100755 index efd4a9abf..000000000 --- a/python/tutorial/102_DrawMeshTCP.py +++ /dev/null @@ -1,24 +0,0 @@ -import igl -import tcpviewer -import time - -# Load a mesh in OFF format -V = igl.eigen.MatrixXd() -F = igl.eigen.MatrixXi() -time1 = time.time() -# igl.read_triangle_mesh("../tutorial/shared/armadillo.obj", V, F) -igl.readOFF("../tutorial/shared/beetle.off", V, F) -time2 = time.time() - - -print('Loading mesh (%d vertices) %0.3f ms' % (V.rows(),(time2-time1)*1000.0)) - - -# Plot the mesh -viewer = tcpviewer.TCPViewer() -viewer.data.set_mesh(V, F) -viewer.core.align_camera_center(V,F) -viewer.launch() -time3 = time.time() - -print('Sending to TCP viewer took %0.3f ms' % ((time3-time2)*1000.0)) diff --git a/python/tutorial/102_DrawMesh_TCP.py b/python/tutorial/102_DrawMesh_TCP.py new file mode 100644 index 000000000..e63987d54 --- /dev/null +++ b/python/tutorial/102_DrawMesh_TCP.py @@ -0,0 +1,27 @@ +## This is a test application for the TCPViewer + +# Add the igl library to the modules search path +import sys, os +sys.path.insert(0, os.getcwd() + "/../") + +import os +import time + +# Launch the tcp viewer +os.system("python ../tcpviewer.py&") + +# Wait for it to set up the socket +time.sleep(1) + +import igl +import tcpviewer + +# Read a mesh +V = igl.eigen.MatrixXd() +F = igl.eigen.MatrixXi() +igl.readOFF('../../tutorial/shared/beetle.off', V, F) + +# Send it to the viewer +viewer = tcpviewer.TCPViewer() +viewer.data.set_mesh(V, F) +viewer.launch()