heremaps / pptk

The Point Processing Toolkit (pptk) is a Python package for visualizing and processing 2-d/3-d point clouds.
https://heremaps.github.io/pptk
MIT License
610 stars 112 forks source link

Connecting to Existing Viewer #19

Open mwil opened 5 years ago

mwil commented 5 years ago

I would like to connect to an already existing viewer (for example by providing its port) and use it the same way as pptk.viewer(points). While developing I have to restart the whole script, so at the moment I'm pointlessly loading the point cloud again and again.

Adrianordp commented 4 years ago

I'm probably late to help you, but i'll share the solution anyway.

You need to connect to the socket server port displayed at the pptk viewer's top-right corner. This port was created by the QTCPSocket and you can connect to it via python, for example, using:

import socket
portNumber = <insert server port number here>
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', portNumber)).

From now on you need to define a message to send to this port. You may check the function def __send(self, msg) in $ROOT/pptk/pptk/viewer/viewer.py and its calls to understand how it works. I'll append a sample code based on existing functions of viewer.py:

#!/bin/python3.8
import struct
import socket
import numpy

def __load(positions):
    numPoints = int(positions.size /3)
    msg = struct.pack('b',1) + struct.pack('i',numPoints) + positions.tobytes()
    __send(msg)

def __send(msg):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('localhost', portNumber))
    totalSent = 0
    while totalSent < len(msg):
        sent = s.send(msg)
        if sent == 0:
            raise RuntimeError("socket connection broken")
        totalSent = totalSent + sent
    s.close()

portNumber = <insert server port number here>
args = [[0,0,0],[2,2,2],[1,1,1]] # Points to print in pptk viewer display
positions = numpy.asarray(args, dtype=numpy.float32)
__load(positions)
bradylowe commented 3 years ago

In the init method of pptk/viewer/viewer.py, you can make the following changes:

Add the line self._portNumber = kwargs.get('port') to grab a port number from the user.

Then, if the user doesn't send in a port number, default to normal behavior like so:

if self._portNumber is None:
    # start up viewer in separate process
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('localhost', 0))
    s.listen(0)
    self._process = subprocess.Popen(
        [os.path.join(_viewer_dir, 'viewer'), str(s.getsockname()[1])],
        stdout=subprocess.PIPE,
        stderr=(None if debug else subprocess.PIPE))
    if debug:
        print ('Started viewer process: %s' \
            % os.path.join(_viewer_dir, 'viewer'))
    x = s.accept()
    self._portNumber = struct.unpack('H', self._process.stdout.read(2))[0]
    # self._portNumber = struct.unpack('H',x[0].recv(2))[0]

After you make these changes, you can use the following line to connect to the existing viewer and use it like normal:

v = pptk.viewer(points, port=1729)
v.attributes(points[:, 2])
jiapei100 commented 2 years ago

@bradylowe

Exception has occurred: ConnectionRefusedError
[Errno 111] Connection refused
  File "mypptk.py", line 24, in <module>
    v = pptk.viewer(xyz, port=36521)