~mrol-dev/mrol/trunk

« back to all changes in this revision

Viewing changes to mrol_mapping/visualiser/mayaviclient.py

  • Committer: Vikas Dhiman
  • Date: 2012-11-16 19:59:46 UTC
  • Revision ID: vikasdhi@buffalo.edu-20121116195946-fwfdqevt3h3eqoyg
Manually added julians changes after merge failed. "Added function to save point cloud in the .ply format"; "Got speed_test working again after API changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Launch a mayavi server and execute plotting methods on the server by passing
 
3
data over the network
 
4
 
 
5
Usage:
 
6
    t = np.linspace(0, 2*np.pi, 50)
 
7
    u = np.cos(t) * np.pi
 
8
    x, y, z = np.sin(u), np.cos(u), np.sin(t)
 
9
    mlabproxy = RemoteMlab()
 
10
    mlabproxy.points3d(x, y, z, z, scale_mode='none')
 
11
    mlabproxy.clf()
 
12
    mlabproxy.plot3d(x, y, z, z)
 
13
"""
 
14
import subprocess
 
15
import socket
 
16
import signal
 
17
import sys
 
18
import tempfile
 
19
import numpy as np
 
20
import cPickle
 
21
import cStringIO
 
22
import base64
 
23
import os
 
24
import errno
 
25
import time
 
26
 
 
27
HOST = 'localhost' # changing this won't suffice
 
28
PORT = 8007
 
29
devnull = open(os.devnull, 'wb')
 
30
 
 
31
def launch_server(port, log_stdout, log_stderr):
 
32
    dir = os.path.dirname(__file__)
 
33
    serverscript = os.path.join(dir, "mayaviserver.py")
 
34
    cmd = ['python', serverscript, str(port)]
 
35
    print("Launching " + " ".join(cmd))
 
36
    return subprocess.Popen(cmd,
 
37
                            stdout=log_stdout,
 
38
                            stderr=log_stderr)
 
39
 
 
40
 
 
41
class RemoteMlab(object):
 
42
    def __init__(self, port=PORT, log_stdout=sys.stdout, log_stderr=sys.stderr):
 
43
        # Don't launch the server if already running
 
44
        try:
 
45
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
46
            sock.connect((HOST, PORT))
 
47
        except socket.error, e:
 
48
            if e.errno != errno.ECONNREFUSED:
 
49
                raise
 
50
            # server not running, let's launch
 
51
            self.subprocess = launch_server(port, log_stdout, log_stderr)
 
52
            # Wait for server to start
 
53
            print("Waiting for server")
 
54
            time.sleep(4)
 
55
 
 
56
        # keep trying 
 
57
        for i in range(5):
 
58
            try:
 
59
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
60
                sock.connect((HOST, PORT))
 
61
                break
 
62
            except socket.error, e:
 
63
                if e.errno != errno.ECONNREFUSED:
 
64
                    raise
 
65
                # Wait for server to start
 
66
                print("Waiting for server")
 
67
                time.sleep(2)
 
68
        sockfile = sock.makefile()
 
69
        sock.send("""import numpy as np\n""")
 
70
        sock.send("""import cPickle\n""")
 
71
        sock.send("""import base64\n""")
 
72
        sock.send("""import cStringIO\n""")
 
73
        sock.send("""args = []\n""")
 
74
        sock.send("""kwargs = {}\n""")
 
75
        self.sock = sock
 
76
        self.sockfile = sockfile
 
77
        self.tempfiles = []
 
78
        self.returnnumber = 0
 
79
 
 
80
    def pass_numpy_args(self, *args):
 
81
        """
 
82
        Pass numpy arrays by using numpy.ndarray.tostring() instead of
 
83
        cPickle.
 
84
        """
 
85
        nargs = len(args)
 
86
        names = ['a%d' % i for i in range(nargs)]
 
87
        tf = tempfile.NamedTemporaryFile(delete=False)
 
88
        np.savez(tf, **dict(zip(names, args)))
 
89
        tf.close()
 
90
        self.sock.send("""tf = open('{0}', 'rb')\n""".format(tf.name))
 
91
        self.sock.send("""arguments = np.load(tf)\n""")
 
92
        for n, a in zip(names, args):
 
93
            self.sock.send("""{n} = arguments['{n}']\n""".format(n=n))
 
94
        return names
 
95
 
 
96
    def pass_args(self, *args, **kwargs):
 
97
        """
 
98
        Pass arbitrary Python arguments and kwargs by using cPickle and base64
 
99
        encoding.
 
100
        """
 
101
        tf = tempfile.NamedTemporaryFile(delete=False)
 
102
        cPickle.dump(dict(args=args, kwargs=kwargs), tf)
 
103
        tf.close()
 
104
        self.sock.send("""tf = open('{0}', 'rb')\n""".format(tf.name))
 
105
        self.sock.send("""arguments = cPickle.load(tf)\n""")
 
106
        self.sock.send("""args = arguments['args']\n""")
 
107
        self.sock.send("""kwargs = arguments['kwargs']\n""")
 
108
        self.tempfiles.append(tf.name)
 
109
 
 
110
    def _set_args(self, *args, **kwargs):
 
111
        if 'numpyargs' in kwargs:
 
112
            numpyargs = kwargs['numpyargs']
 
113
            del kwargs['numpyargs']
 
114
        else:
 
115
            numpyargs = 0
 
116
        if numpyargs:
 
117
            numpynames = self.pass_numpy_args(*args[:numpyargs])
 
118
        nonnumpyargs = args[numpyargs:]
 
119
        self.pass_args(*nonnumpyargs, **kwargs)
 
120
        return numpynames if (numpyargs) else None
 
121
 
 
122
    def exec_func(self, funcname, *args, **kwargs):
 
123
        numpynames = 0
 
124
        if 'numpyargs' in kwargs:
 
125
            numpyargs = kwargs['numpyargs']
 
126
            del kwargs['numpyargs']
 
127
        else:
 
128
            numpyargs = 0
 
129
 
 
130
        self.pass_args(*args, **kwargs)
 
131
        if numpynames:
 
132
            self.sock.send(
 
133
                """ret{rn} = mlab.{func}({numpyargs}, *args,**kwargs)\n""".format(
 
134
                    rn=self.returnnumber, func=funcname, numpyargs=(', '.join(numpynames))))
 
135
        else:
 
136
            self.sock.send(
 
137
                """ret{rn} = mlab.{func}(*args,**kwargs)\n""".format(
 
138
                    rn=self.returnnumber, func=funcname))
 
139
 
 
140
    def getreturnvar(self):
 
141
        r = self.returnnumber
 
142
        self.returnnumber += 1
 
143
        return "ret{rn}".format(rn=r)
 
144
 
 
145
    def ex(self, statement, *args, **kwargs):
 
146
        """
 
147
        Execute the given statement assuming the args are
 
148
        """
 
149
        self._set_args(*args, **kwargs)
 
150
        self.sock.send(statement + "\n")
 
151
 
 
152
    def points3d(self, x, y, z, t, **kwargs):
 
153
        self.exec_func("points3d", x, y, z, t, numpyargs=4, **kwargs)
 
154
 
 
155
    def __getattr__(self, name):
 
156
        def func(*args, **kwargs):
 
157
            self.exec_func(name, *args, **kwargs)
 
158
        return func
 
159
 
 
160
    def close(self, client_only=False):
 
161
        self.sock.shutdown(socket.SHUT_WR)
 
162
        self.sock.close()
 
163
        for tf in self.tempfiles:
 
164
            os.remove(tf)
 
165
        if not client_only:
 
166
            self.subprocess.kill()
 
167
            os.wait()