How to Receive and Visualize PolyData from IGTLink

Operating system: Windows 10
Slicer version:5.0.3

I’ve written a program that sends a polydata message over IGTLink to Slicer. As a demo run, I just want to create a line between two points and add it to the 3D widget. I was wondering how to add the line to the scene once the message is sent. The program is able to establish a connection with Slicer using the OpenIGTLinkIF module just fine, and I think it is successfully sending the polydata in each loop. The device name I specified appears in the Models modules but I’m not sure what to do from here.

Here is the code I’m using to send the OpenIGTLink messages:

// include basic libraries
#include <iostream>
#include <thread>

// include igtlink headers 
#include "igtlOSUtil.h"
#include "igtlMessageHeader.h"
#include "igtlServerSocket.h"
#include "igtlPolyDataMessage.h"

std::atomic_bool StopFlag = false;

int SendPolyData(igtl::Socket::Pointer& socket)
{   
    // Allocate Status Message Class
    igtl::PolyDataMessage::Pointer polyDataMsg;
    polyDataMsg = igtl::PolyDataMessage::New();
    // NOTE: the server should send a message with the same device name
    // as the received query message. 
    polyDataMsg->SetDeviceName("Fake Shapes");

    // Define points connected by line
    static igtlFloat32 pointsData[2][3] = { {0,0,0}, {100,100,100} };

    // Create point array
    igtl::PolyDataPointArray::Pointer pointArray;
    pointArray = igtl::PolyDataPointArray::New();

    // Add point data to point array
    for (unsigned int i = 0; i < 2; i++)
    {
        pointArray->AddPoint(pointsData[i]);
    }

    // Add pointArray to PolyDataMessage
    polyDataMsg->SetPoints(pointArray);

    // Add lines
    static igtlUint32 lineData[2][3] = { {0,0,0}, {100,100,100} };


    // Add PolyDataCellArray and add lines
    igtl::PolyDataCellArray::Pointer cellArray;
    cellArray = igtl::PolyDataCellArray::New();
    for (unsigned int i = 0; i < 2; i++)
    {
        cellArray->AddCell(3, lineData[i]);
    }

    // Add PolyDataCellArray to PolyDataMessage
    polyDataMsg->SetLines(cellArray);

    // Pack polyDataMsg and send via OpenIGTLink socket
    polyDataMsg->Pack();
    socket->Send(polyDataMsg->GetPackPointer(), polyDataMsg->GetPackSize());
    std::cout << "Message sent" << std::endl;
    return 1;
}

int LoopFunction() {
    // Create server socket
    igtl::ServerSocket::Pointer ServerSocket;
    ServerSocket = igtl::ServerSocket::New();
    int r = ServerSocket->CreateServer(18944);

    if (r < 0)
    {
        std::cerr << "Cannot create a server socket" << std::endl;
        exit(0);
    }

    igtl::Socket::Pointer socket;

    // Wait for Connection
    socket = ServerSocket->WaitForConnection(10000); // Wait ten seconds for connection

    if (socket.IsNotNull()) // if client connected
    {
        std::cerr << "Client connected." << std::endl;

        while (!StopFlag)
        {
            //socket->Skip(HeaderMsg->GetPodySizeToRead(),0);
            SendPolyData(socket);
            igtl::Sleep(500);
        }

    }
    else
    {
        std::cerr << "Client could not connect." << std::endl;
    }
    // Close connect
    socket->CloseSocket();
    return 1;
}

int main() {
    // Create thread for loopFunction
    std::thread MessageThread(LoopFunction);

    // main function stops to listen for keyboard input. When input is detected,
    // loop in LoopFunction is broken, and the function quickly returns
    std::cout << "Press any key to stop loop" << std::endl;
    std::cin.get();
    StopFlag = true;
    MessageThread.join();

    // Send message when all threads are joined
    std::cout << "All threads joined" << std::endl;

    return EXIT_SUCCESS;
}

If the polydata appears in the Models module then it should work.

Have you recentered the 3D view so that the polydata is in the middle of the view?

Also can check that the data in the “Information” section of the Models module is correct for your polydata?

I’m guessing I just formatted my lines incorrectly, since there should only be one line connecting two points. This is what I see with the server active:

I think your line cell is not composed correctly. You should only call AddCell once, and it should contain 2 values, {0, 1}.

Got it, thanks! Here is the fixed code for future reference:

// include basic libraries
#include <iostream>
#include <thread>

// include igtlink headers 
#include "igtlOSUtil.h"
#include "igtlMessageHeader.h"
#include "igtlServerSocket.h"
#include "igtlPolyDataMessage.h"

std::atomic_bool StopFlag = false;

int SendPolyData(igtl::Socket::Pointer& socket)
{   
    // Allocate Status Message Class
    igtl::PolyDataMessage::Pointer polyDataMsg;
    polyDataMsg = igtl::PolyDataMessage::New();
    // NOTE: the server should send a message with the same device name
    // as the received query message. 
    polyDataMsg->SetDeviceName("Fake Shapes");

    // Define points connected by line
    static igtlFloat32 pointsData[2][3] = { {0,0,0}, {100,100,100} };

    // Create point array
    igtl::PolyDataPointArray::Pointer pointArray;
    pointArray = igtl::PolyDataPointArray::New();

    // Add point data to point array
    for (unsigned int i = 0; i < 2; i++)
    {
        pointArray->AddPoint(pointsData[i]);
    }

    // Add pointArray to PolyDataMessage
    polyDataMsg->SetPoints(pointArray);


    // Add lines
    static igtlUint32 lineData[2] = {0,1}; // equivalent to SetId with vtk's PolyLine

    // Create PolyDataCellArray and add lines
    igtl::PolyDataCellArray::Pointer cellArray;
    cellArray = igtl::PolyDataCellArray::New();
    cellArray->AddCell(2, lineData);

    // Add PolyDataCellArray to PolyDataMessage
    polyDataMsg->SetLines(cellArray);

    // Pack polyDataMsg and send via OpenIGTLink socket
    polyDataMsg->Pack();
    socket->Send(polyDataMsg->GetPackPointer(), polyDataMsg->GetPackSize());
    std::cout << "Message sent" << std::endl;
    return 1;
}

int LoopFunction() {
    // Create server socket
    igtl::ServerSocket::Pointer ServerSocket;
    ServerSocket = igtl::ServerSocket::New();
    int r = ServerSocket->CreateServer(18944);

    if (r < 0)
    {
        std::cerr << "Cannot create a server socket" << std::endl;
        exit(0);
    }

    igtl::Socket::Pointer socket;

    // Wait for Connection
    socket = ServerSocket->WaitForConnection(10000); // Wait ten seconds for connection

    if (socket.IsNotNull()) // if client connected
    {
        std::cerr << "Client connected." << std::endl;

        while (!StopFlag)
        {
            //socket->Skip(HeaderMsg->GetPodySizeToRead(),0);
            SendPolyData(socket);
            igtl::Sleep(500);
        }

    }
    else
    {
        std::cerr << "Client could not connect." << std::endl;
    }
    // Close connect
    socket->CloseSocket();
    return 1;
}

int main() {
    // Create thread for loopFunction
    std::thread MessageThread(LoopFunction);

    // main function stops to listen for keyboard input. When input is detected,
    // loop in LoopFunction is broken, and the function quickly returns
    std::cout << "Press any key to stop loop" << std::endl;
    std::cin.get();
    StopFlag = true;
    MessageThread.join();

    // Send message when all threads are joined
    std::cout << "All threads joined" << std::endl;

    return EXIT_SUCCESS;
}