Commit 9acbd973 authored by Ricardo Ortiz's avatar Ricardo Ortiz
Browse files

Merge branch 'improve-vrpn-device-api' into 'master'

Refactor VRPN Server/Client API + VTKViewer window management

**VRPN:** Allows for the following workflow :
1) Create a VRPNDeviceClient by specifying its URL (name@ipadress)
and its type (see `DeviceType` class). The subclass VRPNForceDevice
is setting the style to `PHANTOM_OMNI` by default for now.
2) Create a VRPNDeviceServer
3) Call `VRPNDeviceServer::addDeviceClient()` to add the client created
on step 1). This will analyse the IP, name, and type of the device
client to instantiate a VRPN device connection. The added devices are
then stored in three std:map so the `mainloop()` can be called during
the execution.

Updated their use in `FEMSimulator` and `LaparoscopicCamera` examples.

**VTKViewer**: implementing `setVtkRenderWindow`
- This calls `VTKRenderer::setRenderWindow`. Needed to use a
vtkRenderWindow from another instance (example : for a QT
application, use QVTKWidget renderwindow)
- Rename `VTKViewer::getRenderWindow` to `getVtkRenderWindow`
- Use internal functions in `getVtkCamera` and `getVtkRenderer`

See merge request !72
parents f5bfeb74 113ce0a8
......@@ -378,7 +378,7 @@ void SurfaceTree<CellType>::translateRot()
template<typename CellType>
void SurfaceTree<CellType>::getIntersectingNodes(const std::shared_ptr<CellType> left,
const std::shared_ptr<CellType> right,
std::vector<SurfaceTree<CellType>::CellPairType> &result)
std::vector<CellPairType> &result)
{
if(left->getAabb().intersection(right->getAabb()).isEmpty())
{
......
......@@ -21,8 +21,9 @@
#include <vrpn_Tracker.h>
#include <vrpn_Analog.h>
VRPNDeviceClient::VRPNDeviceClient()
: deviceURL("Device0@localhost")
VRPNDeviceClient::VRPNDeviceClient(DeviceType deviceType, std::string deviceURL)
: deviceType(deviceType),
deviceURL(deviceURL)
{
this->name = "VRPNDeviceClient";
}
......@@ -70,6 +71,18 @@ void VRPNDeviceClient::exec()
this->terminationCompleted = true;
}
//---------------------------------------------------------------------------
void VRPNDeviceClient::setDeviceType(const DeviceType t)
{
this->deviceType = t;
}
//---------------------------------------------------------------------------
const DeviceType &VRPNDeviceClient::getDeviceType() const
{
return this->deviceType;
}
//---------------------------------------------------------------------------
void VRPNDeviceClient::setDeviceURL(const std::string s)
{
......@@ -87,12 +100,15 @@ void VRPNDeviceClient::processChanges()
{
this->vrpnButton->mainloop();
this->vrpnTracker->mainloop();
this->vrpnAnalog->mainloop();
}
//---------------------------------------------------------------------------
void VRPN_CALLBACK
VRPNDeviceClient::buttonChangeHandler(void *userData, const vrpn_BUTTONCB b)
{
//std::cout<<"- Button "<< b.button << " : " << b.state << std::endl;
auto handler = reinterpret_cast<VRPNDeviceClient*>(userData);
if (b.button < vrpn_int32(handler->buttons.size()))
......@@ -106,6 +122,8 @@ VRPNDeviceClient::buttonChangeHandler(void *userData, const vrpn_BUTTONCB b)
void VRPN_CALLBACK
VRPNDeviceClient::velocityChangeHandler(void *userData, const vrpn_TRACKERVELCB v)
{
//std::cout<<"- Velocity : ["<< v.vel[0] <<", "<< v.vel[1]<<", "<< v.vel[2] <<"]"<< std::endl;
auto handler = reinterpret_cast<VRPNDeviceClient*>(userData);
handler->velocity << v.vel[0], v.vel[1], v.vel[2];
......@@ -116,6 +134,9 @@ VRPNDeviceClient::velocityChangeHandler(void *userData, const vrpn_TRACKERVELCB
void VRPN_CALLBACK
VRPNDeviceClient::trackerChangeHandler(void *userData, const vrpn_TRACKERCB t)
{
//std::cout<<"Position : ["<< t.pos[0] <<", "<< t.pos[1] <<", "<< t.pos[2] <<"]"<< std::endl;
//std::cout<<"Orientation : ["<< t.quat <<", "<< t.quat <<", "<< t.quat <<"]"<< std::endl;
auto handler = reinterpret_cast<VRPNDeviceClient*>(userData);
handler->position << t.pos[0], t.pos[1], t.pos[2];
......@@ -132,6 +153,10 @@ VRPNDeviceClient::trackerChangeHandler(void *userData, const vrpn_TRACKERCB t)
void VRPN_CALLBACK
VRPNDeviceClient::analogChangeHandler(void* userData, const vrpn_ANALOGCB a)
{
//std::cout << "Analog : ";
//for( int i=0; i < a.num_channel; i++ ) std::cout << a.channel[i] << " ";
//std::cout << std::endl;
auto handler = reinterpret_cast< VRPNDeviceClient * >( userData );
if(a.num_channel > 0)
......
......@@ -49,13 +49,23 @@ typedef struct _vrpn_TRACKERVELCB vrpn_TRACKERVELCB;
typedef struct _vrpn_TRACKERCB vrpn_TRACKERCB;
typedef struct _vrpn_ANALOGCB vrpn_ANALOGCB;
// Add support for VRPN devices by adding a DeviceType
// here and constructing the connection in VRPNDeviceServer.cpp
enum class DeviceType { SPACE_EXPLORER_3DCONNEXION,
NAVIGATOR_3DCONNEXION,
RAZER_HYDRA,
XKEYS_XK3,
PHANTOM_OMNI,
OSVR_HDK
};
class VRPNDeviceClient: public DeviceInterface
{
public:
///
/// \brief Constructor/Destructor
///
VRPNDeviceClient();
VRPNDeviceClient(DeviceType deviceType, std::string deviceURL);
virtual ~VRPNDeviceClient();
///
......@@ -72,6 +82,19 @@ public:
///
virtual DeviceInterface::Message closeDevice() override;
///
/// \brief Set the type used to instantiate the VRPN device
/// \detail Check DeviceType enumeration for more information
/// \param t The new device type to use.
///
void setDeviceType(const DeviceType t);
///
/// \brief Get the phantom's device type
/// \return The current device type used to instantiate the VRPN device
///
const DeviceType &getDeviceType() const;
///
/// \brief Set the url used to connect to the VRPN server
/// \detail Example URLs: Phantom0@localhost, PHANToM2@10.0.0.13
......@@ -135,12 +158,13 @@ private:
static void VRPN_CALLBACK analogChangeHandler(void *userData, const vrpn_ANALOGCB a);
protected:
DeviceType deviceType; //!< Device type
std::string deviceURL; //!< Connection device URL
private:
std::shared_ptr<vrpn_Button_Remote> vrpnButton; //!< VRPN button interface
std::shared_ptr<vrpn_Tracker_Remote> vrpnTracker; //!< VRPN position/orientation interface
std::shared_ptr<vrpn_Analog_Remote> vrpnAnalog; //!< VRPN position/orientation interface
std::shared_ptr<vrpn_Analog_Remote> vrpnAnalog; //!< VRPN analog interface
};
#endif // VRPNDEVICE_H
......@@ -21,76 +21,152 @@
// VRPN includes
#include <vrpn_Connection.h>
#include <vrpn_3DConnexion.h>
#include <vrpn_Tracker_Filter.h>
#include <vrpn_3DConnexion.h>
#include <vrpn_Tracker_RazerHydra.h>
#include <vrpn_Xkeys.h>
#include <vrpn_Tracker_OSVRHackerDevKit.h>
#ifdef VRPN_USE_PHANTOM_SERVER
#include <server_src/vrpn_Phantom.h>
#endif
VRPNDeviceServer::VRPNDeviceServer() : connection(nullptr)
VRPNDeviceServer::VRPNDeviceServer()
{
this->name = "VRPNDeviceServer";
this->connection = vrpn_create_server_connection();
}
//---------------------------------------------------------------------------
void VRPNDeviceServer::exec()
bool VRPNDeviceServer::addDeviceClient(
const std::shared_ptr<VRPNDeviceClient> newDeviceClient,
const bool addFiltering)
{
connection = vrpn_create_server_connection();
std::string newDeviceURL = newDeviceClient->getDeviceURL();
if(!connection)
// Check that it is localhost
std::string newDeviceIP = newDeviceURL.substr(newDeviceURL.find_last_of("@") + 1);
if (newDeviceIP != "localhost")
{
this->terminateExecution = true;
this->terminationCompleted = true;
return;
std::cerr<< "addDeviceClient error: VRPNDeviceServer can only communicate "
<< "with devices connected locally (devicename@localhost)." << std::endl;
return EXIT_FAILURE;
}
// Create the various device objects
std::shared_ptr<vrpn_3DConnexion_SpaceExplorer> explorer =
std::make_shared<vrpn_3DConnexion_SpaceExplorer>("explorer",
this->connection);
std::shared_ptr<vrpn_3DConnexion_Navigator> navigator =
std::make_shared<vrpn_3DConnexion_Navigator>("navigator",
this->connection);
std::shared_ptr<vrpn_Tracker_RazerHydra> razer =
std::make_shared<vrpn_Tracker_RazerHydra>("razer", this->connection);
std::shared_ptr<vrpn_Tracker_FilterOneEuro> razerFiltered =
std::make_shared<vrpn_Tracker_FilterOneEuro>("razer_filtered",
this->connection,
"*razer",
7);
std::shared_ptr<vrpn_Xkeys_XK3> xkeys =
std::make_shared<vrpn_Xkeys_XK3>("xkeys", this->connection);
// Check that name not already use by a deviceClient
std::string newDeviceName = newDeviceURL.substr(0, newDeviceURL.find_last_of("@"));
if( this->analogDevicesList.find(newDeviceName) != this->analogDevicesList.end()
&& this->trackerDevicesList.find(newDeviceName) != this->trackerDevicesList.end()
&& this->buttonDevicesList.find(newDeviceName) != this->buttonDevicesList.end()
)
{
std::cerr<< "addDeviceClient error: name already use by another client ("
<< newDeviceName << ")" << std::endl;
return EXIT_FAILURE;
}
// Instantiate a VRPN device depending on the device type
std::shared_ptr<vrpn_Analog> vrpnAnalogDevice;
std::shared_ptr<vrpn_Tracker> vrpnTrackerDevice;
std::shared_ptr<vrpn_Button> vrpnButtonDevice;
switch( newDeviceClient->getDeviceType() )
{
case DeviceType::SPACE_EXPLORER_3DCONNEXION:
vrpnAnalogDevice = std::make_shared<vrpn_3DConnexion_SpaceExplorer>
(newDeviceName.c_str(), this->connection);
break;
case DeviceType::NAVIGATOR_3DCONNEXION:
vrpnAnalogDevice = std::make_shared<vrpn_3DConnexion_Navigator>
(newDeviceName.c_str(), this->connection);
break;
case DeviceType::RAZER_HYDRA:
vrpnTrackerDevice = std::make_shared<vrpn_Tracker_RazerHydra>
(newDeviceName.c_str(), this->connection);
break;
case DeviceType::XKEYS_XK3:
vrpnButtonDevice = std::make_shared<vrpn_Xkeys_XK3>
(newDeviceName.c_str(), this->connection);
break;
case DeviceType::OSVR_HDK:
vrpnTrackerDevice = std::make_shared<vrpn_Tracker_OSVRHackerDevKit>
(newDeviceName.c_str(), this->connection);
break;
case DeviceType::PHANTOM_OMNI:
#ifdef VRPN_USE_PHANTOM_SERVER
std::shared_ptr<vrpn_Phantom> phantom =
std::make_shared<vrpn_Phantom>("Phantom0",
this->connection,
60.0f,
"Default PHANToM");
std::shared_ptr<vrpn_Tracker_FilterOneEuro> phantomFiltered =
std::make_shared<vrpn_Tracker_FilterOneEuro>("phantom_filtered",
this->connection,
"*phantom",
7);
vrpnDevice = std::make_shared<vrpn_Phantom> // TODO
(newDeviceName.c_str(), this->connection, 60.0f, "Default PHANToM");
#else
std::cerr<< "addDeviceClient error: needs VRPN_USE_PHANTOM_SERVER to be true "
<< "to connect a Panthom omni device." << std::endl;
return EXIT_FAILURE;
#endif
break;
default:
std::cerr<< "addDeviceClient error: unknown device type."
<< std::endl;
return EXIT_FAILURE;
}
while(!this->terminateExecution)
// Add vrpn device in list
if(vrpnAnalogDevice != nullptr)
{
this->analogDevicesList[newDeviceName] = vrpnAnalogDevice;
std::cout<<newDeviceName<<" successfully added."<<std::endl;
}
else if(vrpnTrackerDevice != nullptr)
{
this->trackerDevicesList[newDeviceName] = vrpnTrackerDevice;
std::cout<<newDeviceName<<" successfully added."<<std::endl;
}
else if(vrpnButtonDevice != nullptr)
{
this->buttonDevicesList[newDeviceName] = vrpnButtonDevice;
std::cout<<newDeviceName<<" successfully added."<<std::endl;
}
else
{
explorer->mainloop();
navigator->mainloop();
razer->mainloop();
razerFiltered->mainloop();
xkeys->mainloop();
std::cerr<< "addDeviceClient error: could not instantiate VRPN device."
<< std::endl;
return EXIT_FAILURE;
}
#ifdef VRPN_USE_PHANTOM_SERVER
phantom->mainloop();
phantomFiltered->mainloop();
#endif
// Add One Euro Filter
if( addFiltering && vrpnTrackerDevice != nullptr)
{
std::string filterName = newDeviceName +"_Filter";
std::shared_ptr<vrpn_Tracker_FilterOneEuro> filter =
std::make_shared<vrpn_Tracker_FilterOneEuro>
(filterName.c_str(), this->connection, newDeviceName.c_str(), 7);
this->trackerDevicesList[filterName] = filter;
std::cout<<filterName<<" successfully added."<<std::endl;
}
else if( addFiltering )
{
std::cerr<< "addDeviceClient warning: can not filter device which is not a tracker."
<< std::endl;
}
return EXIT_SUCCESS;
}
//---------------------------------------------------------------------------
void VRPNDeviceServer::exec()
{
while(!this->terminateExecution)
{
for( auto& device : this->analogDevicesList )
{
device.second->mainloop();
}
for( auto& device : this->trackerDevicesList )
{
device.second->mainloop();
}
for( auto& device : this->buttonDevicesList )
{
device.second->mainloop();
}
this->connection->mainloop();
std::this_thread::sleep_for(this->pollDelay);
......@@ -98,7 +174,11 @@ void VRPNDeviceServer::exec()
// connections allocated with vrpn_create_server_connection()
// must decrement their reference to be auto-deleted by VRPN
connection->removeReference();
std::cout<<"VRPNDeviceServer: removing connection references"<<std::endl;
this->connection->removeReference();
std::cout<<"VRPNDeviceServer: closing server"<<std::endl;
delete(this->connection);
this->terminationCompleted = true;
}
......@@ -20,6 +20,10 @@
#include<vector>
#include "Devices/DeviceInterface.h"
#include "VRPNDeviceClient.h"
#include <vrpn_Analog.h>
#include <vrpn_Tracker.h>
#include <vrpn_Button.h>
class vrpn_Connection;
......@@ -32,10 +36,23 @@ public:
VRPNDeviceServer();
~VRPNDeviceServer() = default;
bool addDeviceClient(const std::shared_ptr<VRPNDeviceClient> deviceClient,
const bool addFiltering=false);
void exec() override;
private:
vrpn_Connection *connection;
/* Devices list
* The best would be to store only one map of all devices
* by using `vrpn_BaseClass` but this upcast is too many
* times ambiguous. Using `vprn_BaseClassUnique` solves the
* ambiguity problem but doesn't allow to run `mainloop()`.
*/
std::map<std::string, std::shared_ptr<vrpn_Analog>> analogDevicesList;
std::map<std::string, std::shared_ptr<vrpn_Tracker>> trackerDevicesList;
std::map<std::string, std::shared_ptr<vrpn_Button>> buttonDevicesList;
};
#endif // VRPNSERVERDEVICE_H
......@@ -23,8 +23,8 @@
// VRPN includes
#include <vrpn_ForceDevice.h>
VRPNForceDevice::VRPNForceDevice()
:
VRPNForceDevice::VRPNForceDevice(std::string deviceURL)
: VRPNDeviceClient(DeviceType::PHANTOM_OMNI, deviceURL),
enableForce(true),
contactPlane(core::Vec4f(0.0,1.0,0.0,100)),
dampingCoefficient(0.5),
......@@ -33,7 +33,6 @@ VRPNForceDevice::VRPNForceDevice()
staticFriction(0.0),
vrpnForce(nullptr)
{
this->setDeviceURL("Phantom0@localhost");
this->name = "VRPNForceDevice";
}
......
......@@ -35,7 +35,7 @@ public:
///
/// \brief Constructor/Destructor
///
VRPNForceDevice();
VRPNForceDevice(std::string deviceURL);
~VRPNForceDevice();
///
......
......@@ -23,6 +23,7 @@
#include "SimulationManager/SDK.h"
// Include required types scene objects
#include "Collision/PlaneCollisionModel.h"
#include "Collision/MeshCollisionModel.h"
#include "Collision/PlaneCollisionModel.h"
#include "Collision/PlaneToMeshCollision.h"
......@@ -58,19 +59,22 @@ int main(int ac, char** av)
// 3. Create default scene (scene 0)
//-------------------------------------------------------
auto sdk = SDK::createStandardSDK();
auto client = std::make_shared<VRPNForceDevice>();
auto server = std::make_shared<VRPNDeviceServer>();
//get some user input and setup device url
std::string input = "Phantom@localhost";
client->setDeviceURL(input);
// setup device client
std::string deviceURL = "Phantom@localhost";
auto client = std::make_shared<VRPNForceDevice>(deviceURL);
sdk->registerModule(client);
// setup controller
auto controller = std::make_shared<ToolCoupler>(client);
controller->setScalingFactor(20.0);
sdk->registerModule(server);
// sdk->registerModule(client);
sdk->registerModule(controller);
// setup server
auto server = std::make_shared<VRPNDeviceServer>();
server->addDeviceClient(client);
sdk->registerModule(server);
//-------------------------------------------------------
// Create scene actor 1: fem scene object + fem simulator
//-------------------------------------------------------
......
......@@ -59,8 +59,7 @@
#include <vtkRendererCollection.h>
#include <vtkRenderer.h>
#define SPACE_EXPLORER_DEVICE true
const DeviceType controllerType = DeviceType::NAVIGATOR_3DCONNEXION;
const float X = 8;
const float Y = 6;
const float Z = 6;
......@@ -343,7 +342,7 @@ void add2DOverlay(std::shared_ptr<VTKViewer> vtkViewer,
imageActor->SetPosition(0.5, 0.5);
// Renderer
vtkRenderer* rendererVtk = vtkViewer->getRenderWindow()->GetRenderers()->GetFirstRenderer();
vtkRenderer* rendererVtk = vtkViewer->getVtkRenderer();
rendererVtk->AddActor2D(imageActor.GetPointer());
}
......@@ -351,30 +350,35 @@ void add2DOverlay(std::shared_ptr<VTKViewer> vtkViewer,
/// \brief Create a Laparoscopic camera controller and connect
/// it to the vtk viewer
///
int addCameraController(std::shared_ptr<SDK> sdk)
void addCameraController(std::shared_ptr<SDK> sdk)
{
std::string deviceURL;
std::shared_ptr<VRPNForceDevice> camClient = std::make_shared<VRPNForceDevice>();
std::shared_ptr<VRPNDeviceServer> server;
std::string input;
if (SPACE_EXPLORER_DEVICE)
{
server = std::make_shared<VRPNDeviceServer>();
input = "navigator@localhost";
}
else
{
//get some user input and setup device url
std::string input = "Phantom0@localhost";//"Phantom@10.171.2.217"
std::cout << "Enter the VRPN device URL(" << camClient->getDeviceURL() << "): ";
std::getline(std::cin, input);
}
if (input.empty())
// Set Camera Client
switch( controllerType )
{
return EXIT_FAILURE;
case DeviceType::NAVIGATOR_3DCONNEXION:
deviceURL = "navigator@localhost";
break;
case DeviceType::SPACE_EXPLORER_3DCONNEXION:
deviceURL = "device0@localhost";
break;
case DeviceType::PHANTOM_OMNI:
deviceURL = "Phantom0@localhost"; //"Phantom@10.171.2.217"
break;
case DeviceType::XKEYS_XK3:
deviceURL = "xkeys0@localhost";
break;
case DeviceType::OSVR_HDK:
deviceURL = "com_osvr_Multiserver/OSVRHackerDevKit0@localhost";
break;
}
camClient->setDeviceURL(input);
auto camClient = std::make_shared<VRPNDeviceClient>(controllerType, deviceURL);
std::cout<<"Device URL = "<<camClient->getDeviceURL()<<std::endl;
// Set server
std::shared_ptr<VRPNDeviceServer> server = std::make_shared<VRPNDeviceServer>();
server->addDeviceClient(camClient);
// Get vtkCamera
auto viewer = sdk->getViewerInstance();
......@@ -384,18 +388,13 @@ int addCameraController(std::shared_ptr<SDK> sdk)
// Set Camera Controller
auto camController = std::make_shared<LaparoscopicCameraController>(camClient);
camController->setScalingFactor(40.0);
camController->setScalingFactor(8);
camController->setCamera(cam);
// Register modules
sdk->registerModule(server);
sdk->registerModule(camClient);
sdk->registerModule(camController);
if (SPACE_EXPLORER_DEVICE)
{
sdk->registerModule(server);
}
return EXIT_SUCCESS;
}
int main()
......@@ -433,7 +432,7 @@ int main()
// not to erase the changes on the observers made to the
// interactor in vtkViewer::addRenderer()
vtkNew<ScreenCaptureInteractorStyle> style;
style->initialize(vtkViewer->getRenderWindow());
style->initialize(vtkViewer->getVtkRenderWindow());
vtkViewer->getVtkRenderWindowInteractor()->SetInteractorStyle(style.GetPointer());
style->SetCurrentRenderer(vtkViewer->getVtkRenderer());
......
......@@ -754,7 +754,7 @@ inline int tri_tri_intersect_with_isectline(double V0[3],double V1[3],double V2[
double b,c,max;
int smallest1,smallest2;
//tansel
double temp;
double temp = 0.0;
//end tansel
/* compute plane equation of triangle(V0,V1,V2) */
......
......@@ -43,7 +43,7 @@ target_link_libraries(IO
VegaFEM::volumetricMesh
)
target_compile_options(IO PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wno-sign-compare -Wno-narrowing>)
target_compile_options(IO PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wno-sign-compare -Wno-narrowing -Wno-unused-result>)
if(BUILD_TESTING)
add_subdirectory(UnitTests)
endif()
......@@ -40,7 +40,7 @@ namespace core {
/// apply to them. They can be used to model objects that do not move in the scene or
/// or objects that are controlled by external hardware, i.e. haptics devices.
///
class StaticSceneObject : public SceneObject, public OdeSystem
class StaticSceneObject : public SceneObject
{
public:
///
......
......@@ -40,7 +40,7 @@ public:
public:
OdeSystem();
~OdeSystem() = default;
virtual ~OdeSystem() = default;
///
/// \brief Set the derivative with respect to v of the right hand side.
......
......@@ -49,7 +49,6 @@ public:
timerId(-1),
viewer(activeViewer)
{
}
VTKRenderer(){}
......@@ -91,6 +90,18 @@ public:
return this->renderWindow.GetPointer();
}
///
/// \brief Set the render window
///
void setRenderWindow(vtkSmartPointer<vtkRenderWindow> renWin)