Viz developer page

Since Viz uses a well-defined message format and set of messages between the server and the clients, the users can write their own client, in order to integrate Viz into the rest of their application. Furthermore, we provide a full Python or C++ API supporting all available messages and Viz communication layer. VizMsgsQuickRef

Client example

Here is an easy C++ and Python example of a Viz client to add a Cube to the scene:


#include <iostream.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <sys/socket.h>         // AF_INET, SOCK_DGRAM, ...
#include <string.h>

#include <sock_func.h>
#include "add.h"

main () {
    struct sockaddr_in name;    // Internet socket name (addr)
    int sd = sock_init("localhost",50008,AF_INET,SOCK_STREAM,
                          (struct sockaddr *)&name, 0);
    if (sd<0) printf("Couldn't open socket\n");

    if (connect (sd,&name, sizeof(name)) <0) {
        perror("Error when connecting:");
        return -1;
    }

    float pos[3],dir[3];
    for (int i=0; i<3; pos[i] = dir[i] =0.0, i++);

    printf("written:%d\n",add_send(sd,"cube","world","shape:cube",pos,dir,1));

    close(sd);
}



#!/usr/bin/env python
import add, comUtil
sd = comUtil.connect('localhost',50008)
add.send(sd, 'cube','world','shape:cube',(0,0,0),(0,0,0),1)


Communication

Input messages

In order to allow the clients to modify the scene, the Viz server will accept input messages on the service port of the following format:
<bytes count><message name><message body>

The message must be XDR-encoded. As long as the messages written to the socket port follow this format (and are XDR encoded), then any client that is capable of doing TCP-sockets and XDR can connect to Viz. For convenience, we provide a C++ or Python API.
 

Output messages

The Viz server can also output messages, typically when the user performs an action such as object selection or polyline drawing. The Viz server will only output messages to interested clients that have subscribed to the message type. For example, client1 and client2 are connected to Viz. Client1 subscribes to the object_added message. Everytime an object is added (by client1 or client2), Viz will send an object_added message to client1 only.

Client must use the outputControl message to subscribed/unsubscribe to messages. Queries are special messages that don't require the client to subscribe. These queries allow the client to query Viz and get an answer (output message) without having to subscribe before and unsubscribe after sending the query.

Output message format:
<bytes count>,<message name>,<message body>\n

<bytes count> is a 6-digits integer.
<message name> is a string containing no ','.
<message body> is a string and depends on the message.

Note that the byte count only includes "<message name>,<message body>" and doesn't include the 1st "," (between <bytes count>,<message name>).

The output message is NOT XDR-encoded.
 

List of output messages

Message name Description Message body (data) Output when:
polyline Polyline points coordinates + normals. <number of points>,<x1>,<y1>,<z1>, <nx1>,<ny1>,<x2>,<y2>,... Polyline is closed or queryPolyline
all By subscribing to all, the client receives all possible messages. <message name> and <message body> are sent unchanged. When any message is output.
object_added New object <object name>,<URL> (source of the object) An object is added
object_removed Object removed <object name> An object is removed
selection Objects selected by user <number of objects selected>, <object name>, <object name>, ... An object is selected 
Middle button pressed in selection mode.
ray_pick Ray picked performed <name>, <x>,<y>,<z>,<nx>, <ny>, <nz> 
Note: <name> is "None" if no intersection.
Ray pick query
scene_objects Objects in the scene <name>,<name>,... queryScene is sent.
viewer_param Viewer parameters <viewer number>,<param1>,<param2>,... queryVParam
state Viz state <viz mode>,<viewer mode number> queryState
pose Object pose <object name>,<x>,<y>,<z>, <thetaX>, <thetaY>, <thetaZ> queryPose

 

Multiple connections per clients (how to best handle output from the Viz server)

It is totally allowed (and even recommended) to have a Viz client with several connections to the Viz server. For example, one connection can be used to add objects. The client can send add commands at a high rate. These commands will be processed, queued and executed by the Viz server in the order they were received. Now suppose adding objects take a long time, and your client wants to change the window layout by adding a new viewer using the changeViewerMode command. If the client is using only one connection, then all the objects will have to be added, before the changeViewerMode command can be executed by Viz. In this case, the client can have another connection dedicated to this type of command. Since Viz is multi-threaded and checks all connection in parallel, the changeViewerMode will be executed while objects are added.

Interactive clients such as measurement tools are heavily based on two-way communication with Viz. For instance, they generally issue a setPolyline command to allow the user to draw a polyline in Viz. Then they wait for the polyline to be finished, and use the polyline information to compute the measurement value. Depending on how flexible and versatile the user intends the client to be, communication can be synchronous (using blocking read on socket ports), asynchronous (by polling ports) and one client can integrate multiple measurement capabilities.

Should then the client use one separate connection for each tool or output message ? The general rule of thumb is:
Keep the number of socket connections low (ideally one) unless:
- you have concurrent operations using the same output message type (overlapping in time and on the same socket).
- you intend to read blocking for output messages on some connections and poll other connections.
- you need have messages executed  in parallel by the Viz server.
 

Viz comm API

The Viz API consists of a communication API for input messages into Viz. It essentially provides a way to put together and send Viz messages without requiring the user to manually assemble an XDR encoded message according to the message specification.
The user only needs to know about the message parameters and can use the Viz API routines to initiate a socket connection to the Viz server and obtain a socket descriptor.

In addition, the Python API provides extended comm capabilities:
- parsers: a set of parsers for different output messages will return a dictionary of parsed information.
- the MessageHandler class for non-blocking reads.

The MessageHandler class allows the client to attach/detach callbacks to specific output message types. Suppose you have a client that integrates two modules m1 and m2 which are interested in the same output message 'polyline'. You want m1, respectively m2, to react and call a callback f1, respectively f2, whenever a polyline message arrives from the server on the socket. If you're not careful, you will have m1 then m2 poll the socket. Whenever a message arrives when m1 is polling, m1 will read that message and call f1. However, when it's m2's turn to check that socket, no more message is there (since it's been "consumed" by m2) and f2 will not be called as it should be.

This situation can be avoided with minimal developing effort by using the MessageHandler. The MessageHandler should be instantiated once for each socket connection that needs to be polled. The client can then attach all callbacks to specific message types and detach them at any time. Whenever a message arrives on the socket, the MessageHandler calls every callbacks attached to the message type in the order they were attached. The MessageHandler can also parse the message if needed. If no callback is attached, the MessageHandler will not poll.