diff --git a/.gitignore b/.gitignore index 9ecb211..b2740d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ .vscode *.pro.user +/openigtlink/debug/ +/openigtlink/release/ +openigtlink/build/ +.DS_Store +examples/solum_qt/CMakeLists.txt.user diff --git a/README.md b/README.md index 387f23c..55d5b42 100644 --- a/README.md +++ b/README.md @@ -42,3 +42,32 @@ How to obtain a probe certificate: ``` curl -H "Authorization: OEM-API-Key " "https://cloud.clarius.com/api/public/v0/devices/oem/" ``` + + +## Deploy with all dependencies of QT + +[windeployqt](https://doc.qt.io/qt-6/windows-deployment.html) needs to be executed in order to copy all required QT dependencies into the directory of the executable: + + +For example, open a terminal where the solum.exe was build and enter the following command: + +``` +C:\Qt\6.6.0\msvc2019_64\bin\windeployqt.exe solum.exe +``` + +This copies all required dependencies into the same folder. **The solum.dll file though needs to be copied manually in addition.** + +## Developer startup + + +### Windows + +1. Download and install Qt creator +2. Ensure you use a msvc compiler (Qt.bluetooth is not supported with the mingw + compiler) + - I none is installed on your machine download it via the microsoft build + tools +3. Open the `solum_qt.pro` with qt creator +4. Run the application +5. Make sure that you add the necessary certificates. You can find the + necessary token to claim them on the [clarius user website](https://cloud.clarius.com/login/) diff --git a/examples/solum_qt/CMakeLists.txt b/examples/solum_qt/CMakeLists.txt index bd00842..3dbf777 100644 --- a/examples/solum_qt/CMakeLists.txt +++ b/examples/solum_qt/CMakeLists.txt @@ -1,46 +1,8 @@ cmake_minimum_required(VERSION 3.25) -project(solum_qt LANGUAGES CXX) +project(solum) -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) +set(OpenIGTLink_BUILD_TESTING OFF) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -find_package(Qt6 REQUIRED COMPONENTS Core Gui 3DExtras Bluetooth Widgets) -message("Found Qt? ${Qt6_FOUND}") - -find_library(SOLUM_SDK_BINARY solum PATHS ${CMAKE_SOURCE_DIR}/../../lib) -message("Solum SDK binary location: ${SOLUM_SDK_BINARY}") -add_library(SOLUM_SDK UNKNOWN IMPORTED) -set_target_properties(SOLUM_SDK PROPERTIES - IMPORTED_LOCATION ${SOLUM_SDK_BINARY} - INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/../../include -) - -qt_add_executable(solum_qt - main.cpp solumqt.cpp ble.cpp display.cpp 3d.cpp - solumqt.h ble.h display.h 3d.h - solum.qrc - solumqt.ui -) - -set_target_properties(solum_qt PROPERTIES - WIN32_EXECUTABLE TRUE - MACOSX_BUNDLE TRUE - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/macos/Info.plist - MACOSX_BUNDLE_GUI_IDENTIFIER "me.clarius.sdk.solum_qt" -) - -target_precompile_headers(solum_qt PRIVATE pch.h) - -target_link_libraries(solum_qt PRIVATE - Qt::Core - Qt::Gui - Qt::3DExtras - Qt::Bluetooth - Qt::Widgets - SOLUM_SDK -) +add_subdirectory(solum) +add_subdirectory(../../openigtlink/repo openigtlink) diff --git a/examples/solum_qt/main.cpp b/examples/solum_qt/main.cpp deleted file mode 100644 index a22e137..0000000 --- a/examples/solum_qt/main.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "solumqt.h" -#include -#include -#include - -static std::unique_ptr _solum; -static std::vector _image; -static std::vector _prescanImage; -static std::vector _spectrum; -static std::vector _rfData; - -void print_firmware_version() -{ - char buffer [64]; - auto get_version = [&buffer](CusPlatform platform) -> QString - { - if (CUS_SUCCESS != solumFwVersion(platform, buffer, std::size(buffer))) - return QStringLiteral("error"); - buffer [std::size(buffer)-1] = '\0'; - return QString::fromLatin1(buffer); - }; - qDebug() << '\n'; - qDebug() << "V1 firmware version:" << get_version(CusPlatform::V1); - qDebug() << "HD firmware version:" << get_version(CusPlatform::HD); - qDebug() << "HD3 firmware version:" << get_version(CusPlatform::HD3); -} - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - - QCoreApplication::setOrganizationName(QStringLiteral("Clarius")); - QCoreApplication::setOrganizationDomain(QStringLiteral("clarius.com")); - QCoreApplication::setApplicationName(QStringLiteral("Solum Demo")); - - const int width = 640; // width of the rendered image - const int height = 480; // height of the rendered image - - _solum = std::make_unique(); - - if (solumInit(argc, argv, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString().c_str(), - // connection callback - [](CusConnection res, int port, const char* msg) - { - QApplication::postEvent(_solum.get(), new event::Connection(res, port, QString::fromLatin1(msg))); - }, - // cert callback - [](int daysValid) - { - QApplication::postEvent(_solum.get(), new event::Cert(daysValid)); - }, - // power down callback - [](CusPowerDown res, int tm) - { - QApplication::postEvent(_solum.get(), new event::PowerDown(res, tm)); - }, - // new image callback - [](const void* img, const CusProcessedImageInfo* nfo, int npos, const CusPosInfo* pos) - { - int sz = nfo->imageSize; - // we need to perform a deep copy of the image data since we have to post the event (yes this happens a lot with this api) - if (_image.size() < static_cast(sz)) - _image.resize(sz); - memcpy(_image.data(), img, sz); - QQuaternion imu; - if (npos && pos) - imu = QQuaternion(static_cast(pos[0].qw), static_cast(pos[0].qx), static_cast(pos[0].qy), static_cast(pos[0].qz)); - - QApplication::postEvent(_solum.get(), new event::Image(IMAGE_EVENT, _image.data(), nfo->width, nfo->height, nfo->bitsPerPixel, nfo->format, sz, nfo->overlay, imu)); - }, - // new raw data callback - [](const void* data, const CusRawImageInfo* nfo, int, const CusPosInfo*) - { - // we need to perform a deep copy of the image data since we have to post the event (yes this happens a lot with this api) - int sz = nfo->lines * nfo->samples * (nfo->bitsPerSample / 8); - if (nfo->rf) - { - if (_rfData.size() < static_cast(sz)) - _rfData.resize(sz); - memcpy(_rfData.data(), data, sz); - QApplication::postEvent(_solum.get(), new event::RfImage(_rfData.data(), nfo->lines, nfo->samples, nfo->bitsPerSample, sz, - nfo->lateralSize, nfo->axialSize)); - } - else - { - // image may be a jpeg, adjust the size - if (nfo->jpeg) - sz = nfo->jpeg; - if (_prescanImage.size() < static_cast(sz)) - _prescanImage.resize(sz); - memcpy(_prescanImage.data(), data, sz); - QApplication::postEvent(_solum.get(), new event::Image(PRESCAN_EVENT, _prescanImage.data(), nfo->lines, nfo->samples, - nfo->bitsPerSample, nfo->jpeg ? Jpeg : Uncompressed8Bit, sz, false, QQuaternion())); - } - }, - // new spectrum callback - [](const void* img, const CusSpectralImageInfo* nfo) - { - size_t sz = nfo->lines * nfo->samples * (nfo->bitsPerSample / 8); - // we need to perform a deep copy of the spectrum data since we have to post the event (yes this happens a lot with this api) - if (_spectrum.size() < sz) - _spectrum.resize(sz); - memcpy(_spectrum.data(), img, sz); - QApplication::postEvent(_solum.get(), new event::SpectrumImage(_spectrum.data(), nfo->lines, nfo->samples, nfo->bitsPerSample)); - }, - // imaging state change callback - [](CusImagingState state, int imaging) - { - // post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread - QApplication::postEvent(_solum.get(), new event::Imaging(state, imaging ? true : false)); - }, - // button press callback - [](CusButton btn, int clicks) - { - // post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread - QApplication::postEvent(_solum.get(), new event::Button(btn, clicks)); - }, - // error message callback - [](const char* err) - { - // post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread - QApplication::postEvent(_solum.get(), new event::Error(err)); - }, - width, height) != 0) - { - qDebug() << "error initializing listener"; - return -1; - } - - solumSetTeeFn( - [](bool connected, const char* serial, double timeRemaining, const char* id, const char* name, const char* exam) - { - // post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread - QApplication::postEvent(_solum.get(), new event::Tee(connected, QString::fromLatin1(serial), timeRemaining, - QString::fromLatin1(id), QString::fromLatin1(name), QString::fromLatin1(exam))); - }); - - print_firmware_version(); - - _solum->show(); - const int result = a.exec(); - solumDestroy(); - _solum.reset(); - return result; -} diff --git a/examples/solum_qt/solum.pro b/examples/solum_qt/solum.pro deleted file mode 100644 index 2f4808f..0000000 --- a/examples/solum_qt/solum.pro +++ /dev/null @@ -1,18 +0,0 @@ -TARGET = solum -TEMPLATE = app -QT += core widgets gui bluetooth 3dcore 3drender 3dextras -CONFIG += c++17 precompile_header -DEFINES += QT_DEPRECATED_WARNINGS USE_QT_3D -PRECOMPILED_HEADER = pch.h - -# ensure to unpack the appropriate libs from the zip file into this folder -LIBPATH = $$PWD/../../lib -INCLUDEPATH += $$PWD/../../include -LIBS += -L$$LIBPATH/ -lsolum - -SOURCES += main.cpp solumqt.cpp ble.cpp display.cpp 3d.cpp -HEADERS += solumqt.h ble.h display.h 3d.h -FORMS += solumqt.ui - -RESOURCES += \ - solum.qrc diff --git a/examples/solum_qt/3d.cpp b/examples/solum_qt/solum/3d.cpp similarity index 100% rename from examples/solum_qt/3d.cpp rename to examples/solum_qt/solum/3d.cpp diff --git a/examples/solum_qt/3d.h b/examples/solum_qt/solum/3d.h similarity index 100% rename from examples/solum_qt/3d.h rename to examples/solum_qt/solum/3d.h diff --git a/examples/solum_qt/solum/CMakeLists.txt b/examples/solum_qt/solum/CMakeLists.txt new file mode 100644 index 0000000..b2fa473 --- /dev/null +++ b/examples/solum_qt/solum/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 3.25) + +project(solum_qt LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 REQUIRED COMPONENTS Core Gui 3DExtras Bluetooth Widgets) +message("Found Qt? ${Qt6_FOUND}") + +find_library(SOLUM_SDK_BINARY solum PATHS ${CMAKE_CURRENT_SOURCE_DIR}/../../../lib) +message("Solum SDK binary location: ${SOLUM_SDK_BINARY}") +add_library(SOLUM_SDK UNKNOWN IMPORTED) +set_target_properties(SOLUM_SDK PROPERTIES + IMPORTED_LOCATION ${SOLUM_SDK_BINARY} + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/../../../include +) + +find_package(OpenIGTLink REQUIRED) + +qt_add_executable(solum_qt + main.cpp solumqt.cpp ble.cpp display.cpp 3d.cpp jobbutton.cpp openigtlink.cpp + solumqt.h ble.h display.h 3d.h image.h jobbutton.h openigtlink.h + solum.qrc + solumqt.ui +) + +set_target_properties(solum_qt PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/../macos/Info.plist + MACOSX_BUNDLE_GUI_IDENTIFIER "me.clarius.sdk.solum_qt" +) + +target_precompile_headers(solum_qt PRIVATE pch.h) + +target_include_directories(solum_qt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(solum_qt PRIVATE + Qt::Core + Qt::Gui + Qt::3DExtras + Qt::Bluetooth + Qt::Widgets + SOLUM_SDK + OpenIGTLink +) diff --git a/examples/solum_qt/ble.cpp b/examples/solum_qt/solum/ble.cpp similarity index 93% rename from examples/solum_qt/ble.cpp rename to examples/solum_qt/solum/ble.cpp index a0d8980..a52b6e0 100644 --- a/examples/solum_qt/ble.cpp +++ b/examples/solum_qt/solum/ble.cpp @@ -45,6 +45,9 @@ Ble::Ble() Ble::~Ble() { search_.stop(); + + // This would be done automatically by QLowEnergyController`'s destructor, + // but we must emit the `disconnect` signal while `ping_` is still valid. disconnectFromProbe(); } @@ -61,15 +64,16 @@ void Ble::search() /// called when ble search has completed void Ble::searchComplete() { + constexpr auto PREFIX = "CUS-"; const auto devs = search_.discoveredDevices(); probes_.clear(); QStringList probes; for (auto d : devs) { - if (d.name().startsWith(QStringLiteral("CUS"))) + if (d.name().startsWith(PREFIX)) { - auto name = d.name().remove(QStringLiteral("CUS-")); + auto name = d.name().remove(PREFIX); probes_.push_back(qMakePair(name, d)); probes.push_back(name); } @@ -103,8 +107,10 @@ bool Ble::connectToProbe(const QString& name) if (probe_ && probe_->state() != QLowEnergyController::UnconnectedState) return false; - emit powerReady(false); - emit wifiReady(false); + name_ = name; + + emit powerReady(false, name_); + emit wifiReady(false, name_); probe_.reset(QLowEnergyController::createCentral(dev, this)); QObject::connect(probe_.get(), &QLowEnergyController::connected, this, &Ble::onConnected); @@ -112,8 +118,8 @@ bool Ble::connectToProbe(const QString& name) { // ensure we stop pinging on a disconnect ping_.stop(); - emit powerReady(false); - emit wifiReady(false); + emit powerReady(false, name_); + emit wifiReady(false, name_); }); QObject::connect(probe_.get(), &QLowEnergyController::serviceDiscovered, this, &Ble::onService); QObject::connect(probe_.get(), &QLowEnergyController::discoveryFinished, this, &Ble::onDiscoveryFinished); @@ -125,10 +131,11 @@ bool Ble::connectToProbe(const QString& name) /// @return success of the call bool Ble::disconnectFromProbe() { - if (!probe_ || probe_->state() != QLowEnergyController::ConnectedState) + if (!probe_) return false; probe_->disconnectFromDevice(); + emit connected(false); return true; } @@ -137,8 +144,9 @@ void Ble::onConnected() { if (probe_) { - emit powerReady(false); - emit wifiReady(false); + emit connected(true); + emit powerReady(false, name_); + emit wifiReady(false, name_); probe_->discoverServices(); } } @@ -170,7 +178,7 @@ void Ble::onService(const QBluetoothUuid& u) }); if (s == QLowEnergyService::RemoteServiceDiscovered) { - emit powerReady(true); + emit powerReady(true, name_); auto ch = power_->characteristic(powerPublishedUuid()); if (ch.isValid()) @@ -206,7 +214,7 @@ void Ble::onService(const QBluetoothUuid& u) }); if (s == QLowEnergyService::RemoteServiceDiscovered) { - emit wifiReady(true); + emit wifiReady(true, name_); auto ch = wifi_->characteristic(wifiPublishedUuid()); if (ch.isValid()) diff --git a/examples/solum_qt/ble.h b/examples/solum_qt/solum/ble.h similarity index 82% rename from examples/solum_qt/ble.h rename to examples/solum_qt/solum/ble.h index dc523c8..eb4af0a 100644 --- a/examples/solum_qt/ble.h +++ b/examples/solum_qt/solum/ble.h @@ -28,13 +28,17 @@ private slots: void onDiscoveryFinished(); signals: + void connected(bool); void devices(const QStringList&); - void powerReady(bool); + void powerReady(bool, const QString&); void powered(bool); - void wifiReady(bool); + void wifiReady(bool, const QString&); void wifiInfo(const QString&); private: + ///< probe_->remoteName() might be prefixed with "CUS-", this one isn't. + QString name_; + DiscoveredDevices probes_; QBluetoothDeviceDiscoveryAgent search_; std::unique_ptr probe_; diff --git a/examples/solum_qt/display.cpp b/examples/solum_qt/solum/display.cpp similarity index 86% rename from examples/solum_qt/display.cpp rename to examples/solum_qt/solum/display.cpp index 8a4eb8f..2492e38 100644 --- a/examples/solum_qt/display.cpp +++ b/examples/solum_qt/solum/display.cpp @@ -16,38 +16,57 @@ UltrasoundImage::UltrasoundImage(bool overlay, QWidget* parent) : QGraphicsView( QSizePolicy p(QSizePolicy::Preferred, QSizePolicy::Preferred); p.setHeightForWidth(true); setSizePolicy(p); + + auto* snapshot = new QToolButton(this); + snapshot->setText("💾"); + snapshot->setToolTip("Saves the current ultrasound image to a PNG file."); + snapshot->setStyleSheet("QToolButton {" + "border: none;" // also hides the background? + "font-size: 16px;" + "}"); + QObject::connect(snapshot, &QToolButton::clicked, [this]() + { + QMutexLocker locker(&saveLock_); + QString fileName = QFileDialog::getSaveFileName( + this, tr("Save Image File"), QString(), tr("Images (*.png)")); + if (!fileName.isEmpty()) { + image_.save(fileName); + } + }); } /// loads a new image from raw data -/// @param[in] img the new image data -/// @param[in] w the image width -/// @param[in] h the image height -/// @param[in] bpp bits per pixel -/// @param[in] format the image format -/// @param[in] sz size of image in bytes -void UltrasoundImage::loadImage(const void* img, int w, int h, int bpp, CusImageFormat format, int sz) +/// @param[in] imgNew the new image +void UltrasoundImage::loadImage(const SolumImage& imgNew) { + // If we're in the process of saving the image, we throw this one away to + // make sure that the image saved is the same that the user saw when + // clicking the 💾 button. + if (!saveLock_.try_lock()) + return; + // check for size match - if (image_.width() != w || image_.height() != h) + if (image_.width() != imgNew.width_ || image_.height() != imgNew.height_) return; // ensure the qimage format matches - if (format == Uncompressed8Bit && image_.format() != QImage::Format_Grayscale8) + if (imgNew.format_ == Uncompressed8Bit && image_.format() != QImage::Format_Grayscale8) image_.convertTo(QImage::Format_Grayscale8); - else if (format != Uncompressed8Bit && image_.format() != QImage::Format_ARGB32) + else if (imgNew.format_ != Uncompressed8Bit && image_.format() != QImage::Format_ARGB32) image_.convertTo(QImage::Format_ARGB32); // set the image data lock_.lock(); // check that the size matches the dimensions (uncompressed) - if (sz >= (w * h * (bpp / 8))) - memcpy(image_.bits(), img, w * h * (bpp / 8)); + if (imgNew.img_.size_bytes() == size_t(imgNew.width_ * imgNew.height_ * (imgNew.bpp_ / 8))) + memcpy(image_.bits(), imgNew.img_.data(), imgNew.img_.size_bytes()); // try to load jpeg - else if (format == Jpeg) - image_.loadFromData(static_cast(img), sz, "JPG"); - else if (format == Png) - image_.loadFromData(static_cast(img), sz, "PNG"); + else if (imgNew.format_ == Jpeg) + image_.loadFromData(imgNew.img_.data(), imgNew.img_.size_bytes(), "JPG"); + else if (imgNew.format_ == Png) + image_.loadFromData(imgNew.img_.data(), imgNew.img_.size_bytes(), "PNG"); lock_.unlock(); + saveLock_.unlock(); // redraw scene()->invalidate(); @@ -447,21 +466,21 @@ Prescan::Prescan(QWidget* parent) : QGraphicsView(parent) /// @param[in] w width of image (aka # of spectrum lines) /// @param[in] h height of image (aka # of spectrum samples) /// @param[in] bpp bits per pixel (aka bits per sample) -void Prescan::loadImage(const void* img, int w, int h, int bpp, CusImageFormat format, int sz) +void Prescan::loadImage(const SolumImage& img) { lock_.lock(); // check for size match - if (image_.width() != h || image_.height() != w) + if (image_.width() != img.height_ || image_.height() != img.width_) { - image_ = QImage(h, w, QImage::Format_Grayscale8); + image_ = QImage(img.height_, img.width_, QImage::Format_Grayscale8); image_.fill(Qt::black); } - if (format == Jpeg) - image_.loadFromData(static_cast(img), sz, "JPG"); + if (img.format_ == Jpeg) + image_.loadFromData(img.img_.data(), img.img_.size_bytes(), "JPG"); else - memcpy(image_.bits(), img, w * h * (bpp / 8)); + memcpy(image_.bits(), img.img_.data(), img.img_.size_bytes()); lock_.unlock(); diff --git a/examples/solum_qt/display.h b/examples/solum_qt/solum/display.h similarity index 93% rename from examples/solum_qt/display.h rename to examples/solum_qt/solum/display.h index 0fe7bbf..c15227e 100644 --- a/examples/solum_qt/display.h +++ b/examples/solum_qt/solum/display.h @@ -1,6 +1,6 @@ #pragma once -#include +#include "image.h" /// ultrasound image display class UltrasoundImage : public QGraphicsView @@ -9,7 +9,7 @@ class UltrasoundImage : public QGraphicsView public: explicit UltrasoundImage(bool overlay, QWidget*); - void loadImage(const void* img, int w, int h, int bpp, CusImageFormat format, int sz); + void loadImage(const SolumImage& img); void setDepth(double d) { depth_ = d; } void checkRoi(); void checkGate(); @@ -30,6 +30,7 @@ class UltrasoundImage : public QGraphicsView QVector gate_; ///< gate lines to draw QImage image_; ///< the image buffer QMutex lock_; ///< locking mechanism + QMutex saveLock_; ///< separate lock for the save dialog }; /// spectrum display @@ -87,7 +88,7 @@ class Prescan : public QGraphicsView public: explicit Prescan(QWidget*); - void loadImage(const void* img, int w, int h, int bpp, CusImageFormat format, int sz); + void loadImage(const SolumImage& img); protected: virtual void drawForeground(QPainter*, const QRectF&) override; diff --git a/examples/solum_qt/solum/image.h b/examples/solum_qt/solum/image.h new file mode 100644 index 0000000..fc83038 --- /dev/null +++ b/examples/solum_qt/solum/image.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +/// Common structure for Solum-provided image data. +struct SolumImage +{ + std::span img_; + int width_; + int height_; + int bpp_; + CusImageFormat format_; +}; diff --git a/examples/solum_qt/solum/jobbutton.cpp b/examples/solum_qt/solum/jobbutton.cpp new file mode 100644 index 0000000..e72a775 --- /dev/null +++ b/examples/solum_qt/solum/jobbutton.cpp @@ -0,0 +1,22 @@ +#include "jobbutton.h" + +JobButton::JobButton(QWidget* parent) : QPushButton(parent) +{ + connect(this, &QPushButton::clicked, [this]() + { + setEnabled(false); + setText(runningText_); + }); +} + +void JobButton::setLabels(const QString& readyText, const QString& runningText) +{ + readyText_ = readyText; + runningText_ = runningText; +} + +void JobButton::ready() +{ + setText(readyText_); + setEnabled(true); +} diff --git a/examples/solum_qt/solum/jobbutton.h b/examples/solum_qt/solum/jobbutton.h new file mode 100644 index 0000000..a433745 --- /dev/null +++ b/examples/solum_qt/solum/jobbutton.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +/// Custom wrapper around QPushButton with two separate labels for ready and +/// running states. The running state is automatically entered when clicking +/// the button. +class JobButton : public QPushButton +{ + Q_OBJECT + + Q_PROPERTY(QString readyText MEMBER readyText_) + Q_PROPERTY(QString runningText MEMBER runningText_) + +public: + explicit JobButton(QWidget* parent = nullptr); + + void setLabels(const QString& readyText, const QString& runningText); + + /// Returns the button to the ready state. + void ready(); + +private: + QString readyText_; + QString runningText_; +}; diff --git a/examples/solum_qt/solum/main.cpp b/examples/solum_qt/solum/main.cpp new file mode 100644 index 0000000..b950bee --- /dev/null +++ b/examples/solum_qt/solum/main.cpp @@ -0,0 +1,200 @@ +#include "solumqt.h" +#include +#include +#include + +static std::unique_ptr _solum; +static std::vector _image; +static std::vector _prescanImage; +static std::vector _spectrum; +static std::vector _rfData; + +void print_firmware_version() +{ + char buffer [64]; + auto get_version = [&buffer](CusPlatform platform) -> QString + { + if (CUS_SUCCESS != solumFwVersion(platform, buffer, std::size(buffer))) + return QStringLiteral("error"); + buffer [std::size(buffer)-1] = '\0'; + return QString::fromLatin1(buffer); + }; + qDebug() << '\n'; + qDebug() << "V1 firmware version:" << get_version(CusPlatform::V1); + qDebug() << "HD firmware version:" << get_version(CusPlatform::HD); + qDebug() << "HD3 firmware version:" << get_version(CusPlatform::HD3); +} + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + // When using the default `windowsvista` style on Windows 10 in Dark Mode, + // Qt 6.5.1 renders the labels of disabled QPushButtons with the same + // black color as enabled ones, making it hard to distinguish the two: + // + // https://bugreports.qt.io/browse/QTBUG-115036 + // + // The `fusion` style is bundled with Qt as well, does not have this issue, + // and looks much nicer in general. We only override the specific + // `windowsvista` style though: Other styles don't have this issue, and we + // do want to retain a potential system-wide Qt style setting, especially + // on Linux. + // + // QStyle::name() is also only available on Qt 6.1 and above. +#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0) + if (a.style()->name() == "windowsvista") { + QApplication::setStyle("fusion"); + } +#endif + + QCoreApplication::setOrganizationName(QStringLiteral("Siemens Healthineers AG")); + QCoreApplication::setOrganizationDomain(QStringLiteral("healthineers.com")); + QCoreApplication::setApplicationName(QStringLiteral("Clarius Server")); + + const int width = 640; // width of the rendered image + const int height = 480; // height of the rendered image + + _solum = std::make_unique(); + + CusInitParams initParams = solumDefaultInitParams(); + initParams.args = {argc, argv}; + + const std::string security_key_dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString(); + initParams.storeDir = security_key_dir.c_str(); + + initParams.connectFn = [](CusConnection res, int port, const char* msg) { + QApplication::postEvent(_solum.get(), new event::Connection(res, port, QString::fromLatin1(msg))); + }; + + initParams.certFn = [](int daysValid) { + QApplication::postEvent(_solum.get(), new event::Cert(daysValid)); + }; + + initParams.powerDownFn = [](CusPowerDown res, int tm) { + QApplication::postEvent(_solum.get(), new event::PowerDown(res, tm)); + }; + + initParams.newProcessedImageFn = + [](const void* img, const CusProcessedImageInfo* nfo, int npos, const CusPosInfo* pos) { + size_t sz = nfo->imageSize; + // we need to perform a deep copy of the image data since we have to post the event (yes this happens a lot with this api) + if (_image.size() < static_cast(sz)) + _image.resize(sz); + memcpy(_image.data(), img, sz); + QQuaternion imu; + if (npos && pos) + imu = QQuaternion(static_cast(pos[0].qw), static_cast(pos[0].qx), static_cast(pos[0].qy), static_cast(pos[0].qz)); + + SolumImage solumImage = { + .img_ = { reinterpret_cast(_image.data()), sz }, + .width_ = nfo->width, + .height_ = nfo->height, + .bpp_ = nfo->bitsPerPixel, + .format_ = nfo->format, + }; + + QApplication::postEvent(_solum.get(), new event::ProcessedImage( + IMAGE_EVENT, solumImage, nfo->overlay, imu, nfo->micronsPerPixel, nfo->originX, nfo->originY + )); + }; + + + initParams.buttonFn = [](CusButton btn, int clicks) { + // post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread + QApplication::postEvent(_solum.get(), new event::Button(btn, clicks)); + }; + + initParams.errorFn = [](CusErrorCode code, const char* msg) { + // post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread + QApplication::postEvent(_solum.get(), new event::Error(msg)); + }; + + initParams.imagingFn = [](CusImagingState state, int imaging) { + // post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread + QApplication::postEvent(_solum.get(), new event::Imaging(state, imaging ? true : false)); + }; + + + initParams.newRawImageFn = [](const void* data, const CusRawImageInfo* nfo, int, const CusPosInfo*) { + SolumImage solumImage = { + .width_ = nfo->lines, + .height_ = nfo->samples, + .bpp_ = nfo->bitsPerSample, + .format_ = nfo->jpeg ? Jpeg : Uncompressed8Bit, + }; + + // we need to perform a deep copy of the image data since we have to post the event (yes this happens a lot with this api) + size_t sz = nfo->lines * nfo->samples * (nfo->bitsPerSample / 8); + if (nfo->rf) { + if (_rfData.size() < static_cast(sz)) + _rfData.resize(sz); + memcpy(_rfData.data(), data, sz); + solumImage.img_ = { reinterpret_cast(_rfData.data()), sz }, + QApplication::postEvent(_solum.get(), new event::RfImage(solumImage, nfo->lateralSize, nfo->axialSize)); + } + else { + // image may be a jpeg, adjust the size + if (nfo->jpeg) { sz = nfo->jpeg; } + if (_prescanImage.size() < static_cast(sz)) + _prescanImage.resize(sz); + memcpy(_prescanImage.data(), data, sz); + solumImage.img_ = { reinterpret_cast(_prescanImage.data()), sz }, + QApplication::postEvent(_solum.get(), new event::Image(PRESCAN_EVENT, solumImage, false)); + } + }; + + initParams.newSpectralImageFn = [](const void* img, const CusSpectralImageInfo* nfo) { + size_t sz = nfo->lines * nfo->samples * (nfo->bitsPerSample / 8); + // we need to perform a deep copy of the spectrum data since we have to post the event (yes this happens a lot with this api) + if (_spectrum.size() < sz) { _spectrum.resize(sz); } + memcpy(_spectrum.data(), img, sz); + QApplication::postEvent(_solum.get(), new event::SpectrumImage(_spectrum.data(), nfo->lines, nfo->samples, nfo->bitsPerSample)); + }; + + initParams.newImuPortFn = [](int port) { + QApplication::postEvent(_solum.get(), new event::ImuPort(port)); + }; + + initParams.newImuDataFn = [](const CusPosInfo* pos) { + QQuaternion imu; + if (pos) + imu = QQuaternion(static_cast(pos->qw), static_cast(pos->qx), static_cast(pos->qy), static_cast(pos->qz)); + QApplication::postEvent(_solum.get(), new event::Imu(IMU_EVENT, imu)); + }; + + initParams.width = width; + initParams.height = height; + + if (solumInit(&initParams) != 0) + { + qDebug() << "error initializing listener"; + return -1; + } + + solumSetTeeFn( [](bool connected, const char* serial, double timeRemaining, const char* id, const char* name, const char* exam) { + // post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread + QApplication::postEvent(_solum.get(), new event::Tee(connected, QString::fromLatin1(serial), timeRemaining, + QString::fromLatin1(id), QString::fromLatin1(name), QString::fromLatin1(exam))); + }); + + print_firmware_version(); + + // CONFIGURE PROBE SETTINGS + CusProbeSettings settings; + settings.contactDetection = 0; + settings.autoFreeze = 0; + settings.keepAwake = 0; + settings.deepSleep = 0; + settings.wifiOptimization = 0; + if (solumSetProbeSettings(&settings) != 0) + { + std::cerr << "Failed to set Clarius OEM probe settings" << std::endl; + } + + _solum->show(); + const int result = a.exec(); + solumDestroy(); + _solum.reset(); + return result; +} diff --git a/examples/solum_qt/solum/openigtlink.cpp b/examples/solum_qt/solum/openigtlink.cpp new file mode 100644 index 0000000..519e218 --- /dev/null +++ b/examples/solum_qt/solum/openigtlink.cpp @@ -0,0 +1,142 @@ +#include "openigtlink.h" + +SolumIGTL::SolumIGTL() +{ + msg_ = igtl::ImageMessage::New(); + QObject::connect(&clientConnectTimer_, &QTimer::timeout, [this]() + { + client_ = server_->WaitForConnection(1); // 0 would wait forever. + if (client_.IsNotNull()) + { + emit clientConnected(true); + clientConnectTimer_.stop(); + msSinceLastFrame_ = 0; + fpsSignalTimer_.start(1000); + } + }); + + QObject::connect(&fpsSignalTimer_, &QTimer::timeout, [this]() + { + if (!imageTimer_.isValid()) + emit msSinceLastFrame(0); + else + { + const auto elapsed = imageTimer_.elapsed(); + emit msSinceLastFrame((elapsed >= 1000) ? elapsed : msSinceLastFrame_); + } + }); +} + +bool SolumIGTL::serve(uint16_t port) +{ + server_ = igtl::ServerSocket::New(); + if (server_->CreateServer(port) < 0) + return false; + reconnectClient(); + return true; +} + +void SolumIGTL::close() +{ + disconnectClient(); + server_->CloseSocket(); +} + +void SolumIGTL::setNodeName(const QString &name) +{ + nodeName_ = name.toStdString(); +} + +void SolumIGTL::setFlip(bool flip) +{ + flip_ = flip; +} + +void SolumIGTL::sendImage(const SolumImage& img, double micronsPerPixel) +{ + if (!isClientConnected()) + return; + + assert((img.bpp_ == 32) && (img.format_ == Uncompressed)); + + int wPrev, hPrev, zPrev; + msg_->GetDimensions(wPrev, hPrev, zPrev); + if ((wPrev != img.width_) || (hPrev != img.height_)) + { + msg_->SetDimensions(img.width_, img.height_, 1); + msg_->SetOrigin(0, 0, 0); + msg_->SetScalarType(igtl::ImageMessage::TYPE_UINT8); + msg_->SetNumComponents(4); + msg_->SetSubVolume(img.width_, img.height_, 1, 0, 0, 0); // determines the buffer size! + msg_->SetDeviceName(nodeName_); + msg_->AllocateScalars(); + } + + // Also necessary to force a repack below. + msg_->SetMessageID(msg_->GetMessageID() + 1); + + // Required for reslicing to not crash. The microns per pixel will change + // as the imaging depth changes, independently of the image resolution. + const auto spacing = (micronsPerPixel / 1000.0); + msg_->SetSpacing(spacing, spacing, 1.0f); + + if (flip_) + { + // Copy the image upside down + const auto stride = (img.width_ * (img.bpp_ / 8)); + auto* dst_row = reinterpret_cast(msg_->GetScalarPointer()); + auto* src_row = (img.img_.data() + img.img_.size_bytes() - stride); + for (int y = 0; y < img.height_; y++) + { + memcpy(dst_row, src_row, stride); + dst_row += stride; + src_row -= stride; + } + } + else + { + // Even C++23 does not have output ranges anyway... + // (https://thephd.dev/output-ranges) + memcpy(msg_->GetScalarPointer(), img.img_.data(), img.img_.size_bytes()); + } + + msg_->Pack(); + if (client_->Send(msg_->GetPackPointer(), msg_->GetPackSize()) == 0) + reconnectClient(); + + if (!imageTimer_.isValid()) + imageTimer_.start(); + else + { + constexpr double SMOOTHING = 0.75; + static_assert(SMOOTHING < 1.0); + msSinceLastFrame_ = ((msSinceLastFrame_ * SMOOTHING) + + (imageTimer_.restart() * (1.0 - SMOOTHING))); + } +} + +void SolumIGTL::disconnectClient() +{ + clientConnectTimer_.stop(); + fpsSignalTimer_.stop(); + imageTimer_.invalidate(); + if (client_) + client_->CloseSocket(); + emit clientConnected(false); +} + +void SolumIGTL::reconnectClient() +{ + disconnectClient(); + clientConnectTimer_.start(100); +} + +bool SolumIGTL::isServing() const +{ + return (server_ && server_->GetConnected()); +} + +bool SolumIGTL::isClientConnected() const +{ + return (client_ && client_->GetConnected()); +} diff --git a/examples/solum_qt/solum/openigtlink.h b/examples/solum_qt/solum/openigtlink.h new file mode 100644 index 0000000..8684fc8 --- /dev/null +++ b/examples/solum_qt/solum/openigtlink.h @@ -0,0 +1,49 @@ +#pragma once + +#include "igtlImageMessage.h" +#include "igtlServerSocket.h" +#include "image.h" + +/// OpenIGTLink module +class SolumIGTL : public QObject +{ + Q_OBJECT; + +public: + SolumIGTL(); + + bool serve(uint16_t port); /// Returns `false` on failure. + void close(); + + void setNodeName(const QString& name); + void setFlip(bool flip); + void sendImage(const SolumImage& img, double micronsPerPixel); + + bool isServing() const; + bool isClientConnected() const; + +signals: + void clientConnected(bool); + void msSinceLastFrame(double); + +private: + void disconnectClient(); + void reconnectClient(); + + igtl::ServerSocket::Pointer server_; + igtl::Socket::Pointer client_; + QTimer clientConnectTimer_; + std::string nodeName_; + bool flip_ = false; + + // Sharing an allocation for all images of the same size. + igtl::ImageMessage::Pointer msg_; + + // Periodically sends a msSinceLastFrame() signal. + QTimer fpsSignalTimer_; + + // FPS timer + QElapsedTimer imageTimer_; + + double msSinceLastFrame_; +}; diff --git a/examples/solum_qt/pch.h b/examples/solum_qt/solum/pch.h similarity index 100% rename from examples/solum_qt/pch.h rename to examples/solum_qt/solum/pch.h diff --git a/examples/solum_qt/res/logo.png b/examples/solum_qt/solum/res/logo.png similarity index 100% rename from examples/solum_qt/res/logo.png rename to examples/solum_qt/solum/res/logo.png diff --git a/examples/solum_qt/solum/solum.pro b/examples/solum_qt/solum/solum.pro new file mode 100644 index 0000000..529ee88 --- /dev/null +++ b/examples/solum_qt/solum/solum.pro @@ -0,0 +1,22 @@ +TARGET = solum +TEMPLATE = app +QT += core widgets gui bluetooth 3dcore 3drender 3dextras +CONFIG += c++20 precompile_header +DEFINES += QT_DEPRECATED_WARNINGS USE_QT_3D +PRECOMPILED_HEADER = pch.h + +CONFIG(release, debug|release): CONFIG += ltcg + +include($$PWD/../../../openigtlink/openigtlink.pri) + +# ensure to unpack the appropriate libs from the zip file into this folder +LIBPATH = $$PWD/../../../lib +INCLUDEPATH += $$PWD/../../../include +LIBS += -L$$LIBPATH/ -lsolum + +SOURCES += main.cpp solumqt.cpp ble.cpp display.cpp 3d.cpp jobbutton.cpp openigtlink.cpp +HEADERS += solumqt.h ble.h display.h 3d.h image.h jobbutton.h openigtlink.h +FORMS += solumqt.ui + +RESOURCES += \ + solum.qrc diff --git a/examples/solum_qt/solum.qrc b/examples/solum_qt/solum/solum.qrc similarity index 100% rename from examples/solum_qt/solum.qrc rename to examples/solum_qt/solum/solum.qrc diff --git a/examples/solum_qt/solum/solumqt.cpp b/examples/solum_qt/solum/solumqt.cpp new file mode 100644 index 0000000..39e6d6d --- /dev/null +++ b/examples/solum_qt/solum/solumqt.cpp @@ -0,0 +1,1226 @@ +#include "solumqt.h" +#include "display.h" +#include "3d.h" +#include +#include + +static Solum* _me; + +/// default constructor +/// @param[in] parent the parent object +Solum::Solum(QWidget *parent) : QMainWindow(parent), imaging_(false), teeConnected_(false) +{ + _me = this; + ui_.setupUi(this); + + connect(ui_.igtlnode, &QLineEdit::textChanged, [this](auto& text) + { + igtl_.setNodeName(text); + settings_->setValue("OpenIGTLink/node", text); + }); + + // Job button labels + ui_.retrieve->setLabels(tr("Retrieve from Cloud"), tr("Retrieving...")); + ui_.blesearch->setLabels(tr("Search"), tr("Searching...")); + ui_.bleconnect->setLabels(tr("Connect"), tr("Connecting...")); + + // Port validation + portValidator_ = new QIntValidator(1, std::numeric_limits::max()); + portError_ = tr("must be between %1 and %2") + .arg(portValidator_->bottom()) + .arg(portValidator_->top()); + + connectPortChanged(ui_.igtlport, ui_.igtlserve); + + // UI polish handlers + connect(ui_.token, &QLineEdit::textChanged, [this](auto& text) + { + ui_.retrieve->setEnabled(!text.isEmpty()); + }); + + ui_.status->viewport()->setAutoFillBackground(false); + ui_.progress->hide(); + setWindowIcon(QIcon(":/res/logo.png")); + image_ = new UltrasoundImage(false, this); + image2_ = new UltrasoundImage(true, this); + image2_->setVisible(false); + spectrum_ = new Spectrum(this); + signal_ = new RfSignal(this); + prescan_ = new Prescan(this); + ui_.image->addWidget(image_); + ui_.image->addWidget(prescan_); + ui_.image->addWidget(spectrum_); + ui_.image->addWidget(signal_); + ui_.image2->addWidget(image2_); + render_ = new ProbeRender(QGuiApplication::primaryScreen()); + ui_.render->addWidget(QWidget::createWindowContainer(render_)); + auto reset = new QPushButton(QStringLiteral("Reset"), this); + ui_.render->addWidget(reset); + render_->init(QStringLiteral("scanner.obj")); + render_->show(); + reflectMode(BMode); + ui_._tabs->setTabEnabled(ui_._tabs->indexOf(ui_._3d), false); + + // settings.ini file needs to be at a location the application can write to. + // Writing directly into the application directory (using 'settings.ini') does not work on some systems (e.g. macos). + QString p = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); + settings_ = std::make_unique(p + "/settings.ini", QSettings::IniFormat); + + ui_.token->setText(settings_->value("token").toString()); + settings_->beginGroup("Probes"); + for (const auto& probe: settings_->childGroups()) + { + settings_->beginGroup(probe); + + ProbeData probeData; + probeData.crt = settings_->value("crt").toString(); + probeData.model = settings_->value("model").toString(); + certified_[probe] = probeData; + + settings_->endGroup(); + } + settings_->endGroup(); + auto igtlport = settings_->value("OpenIGTLink/port").toString(); + if (!igtlport.isEmpty()) + ui_.igtlport->setText(igtlport); + auto igtlnode = settings_->value("OpenIGTLink/node").toString(); + ui_.igtlnode->setText(igtlnode.isEmpty() ? "Ultrasound" : igtlnode); + igtl_.setFlip(settings_->value("OpenIGTLink/flip").toBool()); + + ui_.certtable->setColumnCount(4); + ui_.certtable->setHorizontalHeaderLabels({tr("Serial number"), + tr("Issue date"), + tr("Expiry date"), tr("Valid")}); + + // Avoids the need for calling resizeColumnsToContents(), which breaks in + // conjunction with the `StretchLastSection` flag: + // + // https://forum.qt.io/topic/129429 + ui_.certtable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + + // handle the reply from the call to clarius cloud to obtain json probe information + connect(&cloud_, &QNetworkAccessManager::finished, [this](QNetworkReply* reply) + { + ui_.retrieve->ready(); + auto result = reply->readAll(); + auto doc = QJsonDocument::fromJson(result); + // check for errors + if (doc.isNull()) + { + addStatus(tr("(Cloud) Error retrieving certificates")); + return; + } + + const size_t previouslyCertifiedCount = certified_.size(); + size_t newlyCertifiedCount = 0; + + certified_.clear(); + auto json = doc.object(); + if (json.contains("results") && json["results"].isArray()) + { + settings_->beginGroup("Probes"); + + auto probes = json["results"].toArray(); + for (auto i = 0u; i < probes.size(); i++) + { + ProbeData probeData; + QString serial; + + auto probe = probes[i].toObject(); + if (probe.contains("crt") && probe.contains("device") && probe["device"].isObject()) + { + auto device = probe["device"].toObject(); + if (device.contains("serial")) + { + serial = device["serial"].toString(); + probeData.crt = probe["crt"].toString(); + + if (device.contains("model")) + { + probeData.model = device["model"].toString(); + } + } + } + if (!serial.isEmpty() && !probeData.crt.isEmpty() && !probeData.model.isEmpty()) + { + settings_->beginGroup(serial); + if (settings_->value("crt") != probeData.crt) + { + settings_->setValue("crt", probeData.crt); + newlyCertifiedCount++; + } + settings_->setValue("model", probeData.model); + certified_[serial] = probeData; + settings_->endGroup(); + } + } + settings_->endGroup(); + + if (previouslyCertifiedCount == 0) + { + if (newlyCertifiedCount == 0) + addStatus(tr("(Cloud) Found no valid OEM probes")); + else + addStatus(tr("(Cloud) Found %1 valid OEM probes").arg(certified_.size())); + } + else + { + if (newlyCertifiedCount == 0) + addStatus(tr("(Cloud) Stored certificates are recent enough, not renewed")); + else + addStatus(tr("(Cloud) Renewed certificates for %1 probes").arg(newlyCertifiedCount)); + } + + reflectCertification(); + } + }); + + connect(ui_.bleprobes, &QComboBox::currentTextChanged, [this](const auto& probe) + { + ui_.bleconnect->setEnabled(probe != this->bleConnectedProbe_); + }); + + QObject::connect(reset, &QPushButton::clicked, [this]() + { + render_->reset(); + }); + + // load probes list + solumProbes([](const char* list, int) + { + QApplication::postEvent(_me, new event::List(list, true)); + }); + + ui_.modes->blockSignals(true); + ui_.modes->addItem(QStringLiteral("B")); + ui_.modes->addItem(QStringLiteral("SC")); + ui_.modes->addItem(QStringLiteral("M")); + ui_.modes->addItem(QStringLiteral("CFI")); + ui_.modes->addItem(QStringLiteral("PDI")); + ui_.modes->addItem(QStringLiteral("PW")); + ui_.modes->addItem(QStringLiteral("NE")); + ui_.modes->addItem(QStringLiteral("SI")); + ui_.modes->addItem(QStringLiteral("RF")); + ui_.modes->blockSignals(false); + + // Start the IGTL server at startup + onIGTLServe(); + + // connect status timer + connect(&timer_, &QTimer::timeout, [this]() + { + CusStatusInfo st; + if (solumStatusInfo(&st) == 0) + { + QString teeTime; + if (teeConnected_) + teeTime = QStringLiteral(", TEE: %1%").arg(st.teeTimeRemaining); + + ui_.probeStatus->setText(QStringLiteral("Battery: %1%, Temp: %2%, FR: %3 Hz%4") + .arg(st.battery).arg(st.temperature).arg(QString::number(st.frameRate, 'f', 0)).arg(teeTime)); + } + }); + + const auto bleReadyCheck = [this](const QString& probe) + { + if(ui_.wifi->isEnabled() && ui_.ring->isEnabled()) + { + addStatus("(BLE) Service discovery finished"); + ui_.bleconnect->ready(); + + ui_.bleconnect->setEnabled(probe != ui_.bleprobes->currentText()); + + ui_.tcpbox->setTitle(tr("Connection to %1").arg(probe)); + ui_.tcpbox->setEnabled(true); + bleConnectedProbe_ = probe; + reflectProbeModelAndWorkflows(); + ui_.ip->setEnabled(false); + ui_.ip->setText(tr("(waiting for BLE message)")); + ui_.port->setEnabled(false); + ui_.port->setText(tr("(waiting for BLE message)")); + } + }; + + connect(&ble_, &Ble::connected, [this, bleReadyCheck](bool connected) + { + if(connected) + addStatus("(BLE) Connected, discovering services..."); + else + { + addStatus("(BLE) Disconnected"); + bleConnectedProbe_.clear(); + ui_.ring->setEnabled(false); + bleReadyCheck(""); + } + }); + + // connect ble device list + connect(&ble_, &Ble::devices, [this](const QStringList& devs) + { + ui_.bleprobes->clear(); + for (const auto& d : devs) + { + addStatus(QStringLiteral("(BLE) Found %1").arg(d)); + ui_.bleprobes->addItem(d); + } + if (ui_.bleprobes->count()) + ui_.bleprobes->setCurrentIndex(0); + else + addStatus("(BLE) Found no devices"); + ui_.blesearch->ready(); + }); + + // power service ready + connect(&ble_, &Ble::powerReady, [this, bleReadyCheck](bool en, const QString& probe) + { + ui_.poweron->setEnabled(en); + ui_.poweroff->setEnabled(en); + ui_.ring->setEnabled(en); + bleReadyCheck(probe); + }); + + // wifi service ready + connect(&ble_, &Ble::wifiReady, [this, bleReadyCheck](bool en, const QString& probe) + { + ui_.networkConfig->setEnabled(en); + bleReadyCheck(probe); + }); + + // power status sent + connect(&ble_, &Ble::powered, [this](bool en) + { + addStatus(tr("Powered: %1").arg(en ? tr("On") : tr("Off"))); + }); + + // wifi info sent + connect(&ble_, &Ble::wifiInfo, [this](const QString& info) + { + // yaml formatted network information + QStringList network = info.split(QStringLiteral("\n")); + auto getField = [&network](const QString& field) -> QString + { + QString ret; + auto f = network.filter(field); + if (f.size()) + { + ret = f[0]; + ret = ret.replace("\"", QString{}); + ret.replace(field + QStringLiteral(" "), QString{}); + } + return ret; + }; + auto ip = getField(QStringLiteral("ip4:")); + auto port = getField(QStringLiteral("ctl:")); + auto ssid = getField(QStringLiteral("ssid:")); + auto pw = getField(QStringLiteral("pw:")); + if (!ip.isEmpty() && !port.isEmpty()) + { + ui_.ip->setEnabled(true); + ui_.ip->setText(ip); + ui_.port->setEnabled(true); + ui_.port->setText(port); + ui_.tcpconnect->setEnabled(true); + if (!pw.isEmpty()) + addStatus(tr("Wi-Fi: %1 (%2) [SSID: %3, Password: %4]").arg(ip).arg(port).arg(ssid).arg(pw)); + else + addStatus(tr("Wi-Fi: %1 (%2) [SSID: %3]").arg(ip).arg(port).arg(ssid)); + } + }); + + connect(&igtl_, &SolumIGTL::clientConnected, [this](bool connected) + { + if(connected) + ui_.igtlStatusClient->setText(tr("🟢 Client connected")); + else + ui_.igtlStatusClient->setText(tr("⌛ Waiting for client connection…")); + ui_.igtlStatusFPS->clear(); + }); + + connect(&igtl_, &SolumIGTL::msSinceLastFrame, [this](auto ms) + { + const auto fps = ((ms == 0) ? 0 : (1000.0 / ms)); + ui_.igtlStatusFPS->setText(tr("🎥 %1 fps").arg(fps, 0, 'f', 1)); + }); + + imagingState(ImagingNotReady, false); + +#if QT_CONFIG(permissions) + QBluetoothPermission bluetoothPermission; + switch (qApp->checkPermission(bluetoothPermission)) { + case Qt::PermissionStatus::Undetermined: + qApp->requestPermission(bluetoothPermission, this, [this]() + { + qDebug() << "bluetooth permission granted"; + ui_.blesearch->setEnabled(true); + // Automatically trigger a BLE search at startup + ui_.blesearch->click(); + }); + return; + case Qt::PermissionStatus::Denied: + qDebug() << "bluetooth permission was denied"; + return; + case Qt::PermissionStatus::Granted: + // Automatically trigger a BLE search at startup + ui_.blesearch->setEnabled(true); + ui_.blesearch->click(); + break; // Proceed + } +#endif +} + +/// destructor +Solum::~Solum() +{ + timer_.stop(); +} + +/// loads a list of applications into selection box +/// @param[in] apps the applications list +void Solum::loadApplications(const QStringList& apps) +{ + ui_.workflows->clear(); + for (auto a : apps) + ui_.workflows->addItem(a); + if (ui_.workflows->count()) + ui_.workflows->setCurrentIndex(0); +} + +/// called when the window is closing to clean up the library +void Solum::closeEvent(QCloseEvent*) +{ + if (tcpConnected_) + solumDisconnect(); +} + +/// called for starting a cloud request to retrieve the probe credentials +void Solum::onRetrieve() +{ + auto token = ui_.token->text(); + if (token.isEmpty()) + return; + + addStatus("(Cloud) Retrieving probe credentials..."); + + // Defer the actual retrieval, so that we immediately return and refresh + // the UI. + QTimer::singleShot(1, [=] () + { + settings_->setValue("token", token); + QNetworkRequest request(QUrl("https://cloud.clarius.com/api/public/v0/devices/oem/?limit=300&format=json")); + request.setTransferTimeout(5000); + QByteArray auth(QString("OEM-API-Key %1").arg(token).toUtf8()); + request.setRawHeader("Authorization", auth); + cloud_.get(request); + }); +} + +/// initiates ble search +void Solum::onBleSearch() +{ + addStatus("(BLE) Searching..."); + ble_.search(); +} + +/// called when a ble probe is selected +void Solum::onBleProbe(int index) +{ + ui_.bleconnect->setEnabled(index >= 0); +} + +/// called when a ble connect is initiated +void Solum::onBleConnect() +{ + const auto& probe = ui_.bleprobes->currentText(); + addStatus(QStringLiteral("(BLE) Connecting to %1...").arg(probe)); + ble_.connectToProbe(probe); +} + +/// tries to power on probe +void Solum::onPowerOn() +{ + ble_.power(true); +} + +/// tries to power off probe +void Solum::onPowerOff() +{ + ble_.power(false); +} + +/// rings the probe +void Solum::onRing() +{ + ble_.ring(); +} + +/// tries to reprogram probe to a new wifi network (router) +void Solum::onWiFi() +{ + auto ssid = ui_.ssid->text(); + auto pw = ui_.password->text(); + if (ssid.isEmpty()) + return; + + QString req(QStringLiteral("ap: false\n")); + req += QStringLiteral("ssid: %1\n").arg(ssid); + if (!pw.isEmpty()) + req += QStringLiteral("pw: %1\n").arg(pw); + ble_.requestWifi(req); +} + +/// tries to repgram probe to it's own access point wifi +void Solum::onAp() +{ + ble_.requestWifi(QStringLiteral("ap: true\nch: auto\n")); +} + +/// handles custom events posted by solum api callbacks +/// @param[in] event the event to parse +/// @return handling status +bool Solum::event(QEvent *event) +{ + if (event->type() == CONNECT_EVENT) + { + auto evt = static_cast(event); + setConnected(evt->result_, evt->port_, evt->message_); + return true; + } + else if (event->type() == CERT_EVENT) + { + auto evt = static_cast(event); + certification(evt->daysValid_); + return true; + } + else if (event->type() == POWER_EVENT) + { + auto evt = static_cast(event); + poweringDown(evt->res_, evt->timeOut_); + return true; + } + else if (event->type() == SWUPDATE_EVENT) + { + auto evt = static_cast(event); + softwareUpdate(evt->res_); + return true; + } + else if (event->type() == LIST_EVENT) + { + auto evt = static_cast(event); + if (evt->probes_) + { + probesSupported_ = evt->list_; + reflectCertification(); + } + else + loadApplications(evt->list_); + return true; + } + else if (event->type() == IMAGE_EVENT) + { + newProcessedImage(*dynamic_cast(event)); + return true; + } + else if (event->type() == PRESCAN_EVENT) + { + newPrescanImage(*dynamic_cast(event)); + return true; + } + else if (event->type() == SPECTRUM_EVENT) + { + newSpectrumImage(*dynamic_cast(event)); + return true; + } + else if (event->type() == RF_EVENT) + { + newRfImage(*dynamic_cast(event)); + return true; + } + else if (event->type() == IMAGING_EVENT) + { + auto evt = static_cast(event); + imagingState(evt->state_, evt->imaging_); + return true; + } + else if (event->type() == BUTTON_EVENT) + { + auto evt = static_cast(event); + onButton(evt->button_, evt->clicks_); + return true; + } + else if (event->type() == PROGRESS_EVENT) + { + setProgress((static_cast(event))->progress_); + return true; + } + else if (event->type() == ERROR_EVENT) + { + addError((static_cast(event))->error_); + return true; + } + else if (event->type() == TEE_EVENT) + { + auto evt = static_cast(event); + onTee(evt->connected_, evt->serial_, evt->timeRemaining_); + return true; + } + + return QMainWindow::event(event); +} + +/// called when reporting the result of a user action +/// @param[in] status the status message +void Solum::addStatus(const QString &status) +{ + ui_.status->appendPlainText(QStringLiteral("(%1) %2").arg(QTime::currentTime().toString()).arg(status)); +} + +/// called when the api returns an error +/// @param[in] err the error message +void Solum::addError(const QString &err) +{ + addStatus(tr("Error: %1").arg(err)); +} + +/// called when there's a new connection event +/// @param[in] res the connection result +/// @param[in] port the connection port +/// @param[in] msg the associated message +void Solum::setConnected(CusConnection res, int port, const QString& msg) +{ + if (res == ProbeConnected) + { + timer_.start(1000); + tcpConnected_ = true; + addStatus(tr("Connected on port: %1").arg(port)); + ui_.tcpconnect->setText(tr("Disconnect")); + ui_.update->setEnabled(true); + ui_.load->setEnabled(true); + + // load the certificate if it was already retrieved from the cloud + if (certified_.count(bleConnectedProbe_)) + solumSetCert(certified_[bleConnectedProbe_].crt.toLatin1()); + + if (tcpConnectedProbe_ != bleConnectedProbe_) + activeWorkflow_.clear(); + tcpConnectedProbe_ = bleConnectedProbe_; + } + else if (res == ProbeDisconnected) + { + timer_.stop(); + tcpConnected_ = false; + addStatus(tr("Disconnected")); + ui_.tcpconnect->setText(tr("Connect")); + ui_.probeStatus->clear(); + ui_.imaging->setEnabled(false); + ui_.update->setEnabled(false); + ui_.load->setEnabled(false); + // disable controls upon disconnect + imagingState(ImagingNotReady, false); + } + else if (res == ConnectionFailed || res == ConnectionError) + addStatus(tr("Error connecting: %1").arg(msg)); + else if (res == SwUpdateRequired) + addStatus(tr("Software update required prior to imaging")); +} + +/// called when a new certification message has been sent +/// @param[in] daysValid # of days valid for certificate +void Solum::certification(int daysValid) +{ + if (daysValid == CERT_INVALID) + ui_.cert->setText(QStringLiteral("Invalid")); + else if (!daysValid) + ui_.cert->setText(QStringLiteral("Expired")); + else + ui_.cert->setText(QStringLiteral("%1 Days").arg(daysValid)); +} + +/// called when there's a power down event +/// @param[in] res the power down reason +/// @param[in] tm the associated timeout +void Solum::poweringDown(CusPowerDown res, int tm) +{ + if (res == Idle) + addStatus(tr("Idle power down in: %1s").arg(tm)); + else if (res == TooHot) + addStatus(tr("Heating power down in: %1s").arg(tm)); + else if (res == LowBattery) + addStatus(tr("Battery low power down in: %1s").arg(tm)); + else if (res == ButtonOff) + addStatus(tr("Button press power down in: %1s").arg(tm)); +} + +/// called when there's a software update notification +/// @param[in] res the software update result +void Solum::softwareUpdate(CusSwUpdate res) +{ + if (res == SwUpdateSuccess) + addStatus(tr("Successfully updated software")); + else if (res == SwUpdateCurrent) + addStatus(tr("Software already up to date")); + else + addStatus(tr("Software not updated: %1").arg(res)); +} + +/// called when the imaging state changes +/// @param[in] state the imaging ready code +/// @param[in] imaging the imaging state +void Solum::imagingState(CusImagingState state, bool imaging) +{ + bool ready = (state != ImagingNotReady); + ui_.imaging->setEnabled(ready ? true : false); + ui_.autogain->setEnabled(ready ? true : false); + ui_.autofocus->setEnabled(ready ? true : false); + ui_.decdepth->setEnabled(ready ? true : false); + ui_.incdepth->setEnabled(ready ? true : false); + ui_.gain->setEnabled(ready ? true : false); + ui_.focus->setEnabled((ready && !ui_.autofocus->isChecked()) ? true : false); + ui_.cfigain->setEnabled(ready ? true : false); + ui_.opacity->setEnabled(ready ? true : false); + ui_.rfzoom->setEnabled(ready ? true : false); + ui_.rfStream->setEnabled(ready ? true : false); + ui_.prescan->setEnabled(ready ? true : false); + ui_.split->setEnabled(ready ? true : false); + ui_.imu->setEnabled(ready ? true : false); + ui_.tgc->setEnabled(ready && !ui_.autogain->isChecked()); + + ui_.modes->setEnabled(imaging ? true : false); + if (!imaging) + { + ui_.modes->blockSignals(true); + ui_.modes->setCurrentText(QStringLiteral("B")); + ui_.modes->blockSignals(false); + } + + if (!imaging || !tcpConnected_) + ui_.imaging->setLabels(tr("Run"), tr("Starting imaging...")); + else + ui_.imaging->setLabels(tr("Stop"), tr("Stopping imaging...")); + + if (tcpConnected_) + { + if (imaging_ != imaging) + ui_.imaging->ready(); + addStatus(tr("Image: %1").arg(imaging ? tr("Running") : tr("Frozen"))); + } + else + { + ui_.imaging->ready(); + ui_.imaging->setEnabled(false); + } + + if (ready) + { + imaging_ = imaging; + getParams(); + image_->checkRoi(); + image_->checkGate(); + } + else if (state == CertExpired) + addStatus(tr("Certificate needs updating prior to imaging")); +} + +/// called when there is a button press on the ultrasound +/// @param[in] btn the button pressed +/// @param[in] clicks # of clicks used +void Solum::onButton(CusButton btn, int clicks) +{ + QString text; + switch (btn) + { + case ButtonDown: text = QStringLiteral("Down"); break; + case ButtonUp: text = QStringLiteral("Up"); break; + case ButtonHandle: text = QStringLiteral("Handle"); break; + } + + addStatus(tr("Button %1 Pressed, %2 Clicks").arg(text).arg(clicks)); +} + +/// called when there is a tee connect or disconnect +/// @param[in] connected flag if the probe is connected or not +/// @param[in] serial the serial number if the probe is connected +/// @param[in] timeRemaining the time remaining in percent if the probe is connected +void Solum::onTee(bool connected, const QString& serial, double timeRemaining) +{ + teeConnected_ = connected; + if (connected) + addStatus(tr("TEE Connected: %1 @ %2% Remaining").arg(serial).arg(timeRemaining)); + else + addStatus(tr("TEE Disconnected")); +} + +/// called when the download progress changes +/// @param[in] progress the current progress +void Solum::setProgress(int progress) +{ + ui_.progress->show(); + ui_.progress->setValue(progress); +} + +/// called when a new image has been sent +/// @param[in] evt the processed image event +void Solum::newProcessedImage(const event::ProcessedImage& evt) +{ + igtl_.sendImage(evt.img_, evt.micronsPerPixel_); + + if (evt.overlay_) + image2_->loadImage(evt.img_); + else + image_->loadImage(evt.img_); + + if (!evt.imu_.isNull()) + render_->update(evt.imu_); +} + +/// called when a new pre-scan image has been sent +/// @param[in] evt the pre-scan image event +void Solum::newPrescanImage(const event::Image& evt) +{ + prescan_->loadImage(evt.img_); +} + +/// called when a new spectrum image has been sent +/// @param[in] evt the spectrum image event +void Solum::newSpectrumImage(const event::SpectrumImage& evt) +{ + spectrum_->loadImage(evt.data_, evt.lines_, evt.samples_, evt.bps_); +} + +/// called when new rf data has been sent +/// @param[in] evt the RF image event +void Solum::newRfImage(const event::RfImage& evt) +{ + signal_->loadSignal(evt.img_.img_.data(), evt.img_.width_, evt.img_.height_, evt.img_.bpp_ / 8); +} + +void Solum::reflectCertification() +{ + // Check for unsupported probe models + { + auto it = certified_.begin(); + while(it != certified_.end()) + { + if (!probesSupported_.contains(it->second.model)) + { + addStatus(tr("%1: Probe model \"%2\" not supported by this version of Solum").arg(it->first).arg(it->second.model)); + it = certified_.erase(it); + } + else + it++; + } + } + + ui_.certtable->setRowCount(int(certified_.size())); + int row = 0; + bool tcpMakesSense = false; + for (const auto& probe : certified_) + { + QSslCertificate cert(probe.second.crt.toLatin1()); + + auto issued = cert.effectiveDate().toString(Qt::RFC2822Date); + auto expiry = cert.expiryDate().toString(Qt::RFC2822Date); + auto now = QDateTime::currentDateTime(); + auto valid = ((cert.effectiveDate() <= now) && (cert.expiryDate() >= now)); + tcpMakesSense |= valid; + + auto itemSerial = new QTableWidgetItem(probe.first); + auto itemIssued = new QTableWidgetItem(issued); + auto itemExpiry = new QTableWidgetItem(expiry); + auto itemValid = new QTableWidgetItem(valid ? "✅" : "❌"); + itemValid->setTextAlignment(Qt::AlignCenter); + + ui_.certtable->setItem(row, 0, itemSerial); + ui_.certtable->setItem(row, 1, itemIssued); + ui_.certtable->setItem(row, 2, itemExpiry); + ui_.certtable->setItem(row, 3, itemValid); + row++; + } + ui_._tabs->setTabEnabled(ui_._tabs->indexOf(ui_.tcp), tcpMakesSense); + reflectProbeModelAndWorkflows(); +} + +/// called when the connect/disconnect button is clicked +void Solum::onTcpConnect() +{ + if (!tcpConnected_) + { + + const std::string ip = ui_.ip->text().toStdString(); + const CusConnectionParams connectionParams = { + ip.c_str(), + ui_.port->text().toUInt(), + 0 + }; + + if (solumConnect(&connectionParams) < 0) + addStatus(tr("Connection failed")); + else + addStatus(tr("Trying connection")); + } + else + { + if (solumDisconnect() < 0) + addStatus(tr("Disconnect failed")); + } +} + +/// handles starting and stopping imaging with the selected workflow +void Solum::onImaging() +{ + if (!tcpConnected_) + return; + + if (solumRun(imaging_ ? 0 : 1) < 0) + addStatus(tr("Error requesting imaging run/stop")); + else + { + imagingState(ImagingReady, !imaging_); + if (imaging_) + spectrum_->reset(); + } +} + +/// initiates a software update +void Solum::onUpdate() +{ + if (!tcpConnected_) + return; + + auto filePath = QFileDialog::getOpenFileName(this, + QStringLiteral("Choose Firmware Package"), QString(), QStringLiteral("Zip Files (*.zip)")); + if (filePath.isEmpty()) + return; + + if (solumSoftwareUpdate( + filePath.toStdString().c_str(), + // software update result + [](CusSwUpdate res) + { + QApplication::postEvent(_me, new event::SwUpdate(res)); + }, + // download progress + [](int progress) + { + QApplication::postEvent(_me, new event::Progress(progress)); + }, 0) < 0) + addStatus(tr("Error requesting software update")); +} + +/// initiates a workflow load +void Solum::onLoad() +{ + if (!tcpConnected_) + return; + + // capture the currently selected one, just in case the user changes it + // before the timer + const auto probeModel = ui_.tcpprobe->text().toStdString(); + const auto workflow = ui_.workflows->currentText().toStdString(); + + if (solumLoadApplication(probeModel.c_str(), workflow.c_str()) < 0) + addStatus(tr("Error requesting application load")); + // update depth range on a successful load + else + { + // wait a second for the application load to propagate internally before fetching the range + // ideally the api would provide a callback for when the application is fully loaded (ofi) + QTimer::singleShot(1000, this, [this, workflow] () + { + CusRange range; + if (solumGetRange(ImageDepth, &range) == 0) + { + ui_.maxdepth->setText( + tr("Range: %1 - %2cm").arg(range.min).arg(range.max) + ); + activeWorkflow_ = workflow; + } + }); + } +} + +/// updates the probe model and workflow fields +/// @param[in] probe the probe selected +void Solum::reflectProbeModelAndWorkflows() +{ + if (certified_.count(bleConnectedProbe_)) + { + const auto& model = certified_[bleConnectedProbe_].model; + ui_.tcpprobe->setText(model); + ui_.tcpprobe->setEnabled(true); + solumApplications(model.toStdString().c_str(), [](const char* list, int) + { + QApplication::postEvent(_me, new event::List(list, false)); + }); + } +} + +/// shows or hides parameter widgets depending on the given mode +/// @param[in] m an imaging mode +void Solum::reflectMode(CusMode m) +{ + spectrum_->setVisible(m == MMode || m == PwMode); + signal_->setVisible(m == RfMode); + ui_.cfigain->setVisible(m == ColorMode || m == PowerMode); + ui_.cfigain_label->setVisible(m == ColorMode || m == PowerMode); + ui_.velocity->setVisible(m == ColorMode || m == PwMode); + ui_.opacity->setVisible(m == Strain); + ui_.opacity_label->setVisible(m == Strain); + ui_.rfzoom->setVisible(m == RfMode); + ui_.rf_label->setVisible(m == RfMode); + ui_.rfStream->setVisible(m == RfMode); + ui_.split->setVisible(m == ColorMode || m == PowerMode || m == Strain); +} + +/// increases the depth +void Solum::incDepth() +{ + auto v = solumGetParam(ImageDepth); + if (v != -1) + solumSetParam(ImageDepth, v + 1.0); +} + +/// decreases the depth +void Solum::decDepth() +{ + auto v = solumGetParam(ImageDepth); + if (v > 1.0) + solumSetParam(ImageDepth, v - 1.0); +} + +/// called when gain adjusted +/// @param[in] gn the gain level +void Solum::onGain(int gn) +{ + solumSetParam(Gain, gn); +} + +/// called when manual focus adjusted +/// @param[in] fd the focus depth +void Solum::onFocus(int fd) +{ + auto v = solumGetParam(ImageDepth); + if (fd < v) + solumSetParam(FocusDepth, fd); +} + +/// called when color gain adjusted +/// @param[in] gn the gain level +void Solum::onColorGain(int gn) +{ + solumSetParam(ColorGain, gn); +} + +/// called when strain opacity adjusted +/// @param[in] gn the opacity level +void Solum::onOpacity(int gn) +{ + solumSetParam(StrainOpacity, gn); +} + +/// called when auto gain enable adjusted +/// @param[in] state checkbox state +void Solum::onAutoGain(int state) +{ + bool en = (state == Qt::Checked); + solumSetParam(AutoGain, en ? 1 : 0); + ui_.tgctop->setEnabled(en ? false: true); + ui_.tgcmid->setEnabled(en ? false: true); + ui_.tgcbottom->setEnabled(en ? false: true); + // reset the tgc sliders + ui_.tgctop->setValue(0); + ui_.tgcmid->setValue(0); + ui_.tgcbottom->setValue(0); +} + +/// called when auto focus enable adjusted +/// @param[in] state checkbox state +void Solum::onAutoFocus(int state) +{ + bool en = (state == Qt::Checked); + solumSetParam(AutoFocus, en ? 1 : 0); + ui_.focus->setEnabled(en ? false: true); +} + +/// called when imu enable adjusted +/// @param[in] state checkbox state +void Solum::onImu(int state) +{ + ui_._tabs->setTabEnabled(ui_._tabs->indexOf(ui_._3d), (state == Qt::Checked)); + solumSetParam(ImuStreaming, (state == Qt::Checked) ? 1 : 0); +} + +/// called when rf stream enable adjusted +/// @param[in] state checkbox state +void Solum::onRfStream(int state) +{ + solumSetParam(RfStreaming, (state == Qt::Checked) ? 1 : 0); +} + +/// called when separate overlays is changed +/// @param[in] state checkbox state +void Solum::onSplit(int state) +{ + bool en = (state == Qt::Checked); + solumSeparateOverlays(en ? 1 : 0); + image2_->setVisible(en); +} + +/// called when separate overlays is changed +/// @param[in] state checkbox state +void Solum::onPrescan(int state) +{ + bool en = (state == Qt::Checked); + prescan_->setVisible(en); +} + +/// sets the tgc top +/// @param[in] v the tgc value +void Solum::tgcTop(int v) +{ + CusTgc t; + t.top = v; + t.mid = ui_.tgcmid->value(); + t.bottom = ui_.tgcbottom->value(); + solumSetTgc(&t); +} + +/// sets the tgc mid +/// @param[in] v the tgc value +void Solum::tgcMid(int v) +{ + CusTgc t; + t.top = ui_.tgctop->value(); + t.mid = v; + t.bottom = ui_.tgcbottom->value(); + solumSetTgc(&t); +} + +/// sets the tgc bottom +/// @param[in] v the tgc value +void Solum::tgcBottom(int v) +{ + CusTgc t; + t.top = ui_.tgctop->value(); + t.mid = ui_.tgcmid->value(); + t.bottom = v; + solumSetTgc(&t); +} + +/// get the initial parameter values +void Solum::getParams() +{ + auto v = solumGetParam(ImageDepth); + if (v != -1 && image_) + image_->setDepth(v); + + v = solumGetParam(AutoGain); + ui_.autogain->setChecked(v > 0); + v = solumGetParam(AutoFocus); + ui_.autofocus->setChecked(v > 0); + v = solumGetParam(ImuStreaming); + ui_.imu->setChecked(v > 0); + v = solumGetParam(RfStreaming); + ui_.rfStream->setChecked(v > 0); + + CusTgc t; + if (solumGetTgc(&t) == 0) + { + ui_.tgctop->setValue(static_cast(t.top)); + ui_.tgcmid->setValue(static_cast(t.mid)); + ui_.tgcbottom->setValue(static_cast(t.bottom)); + } +} + +/// called on a mode change +void Solum::onMode(int mode) +{ + auto m = static_cast(mode); + if (solumSetMode(m) < 0) + addStatus(tr("Error setting imaging mode")); + else + { + reflectMode(m); + updateVelocity(m); + } +} + +/// updates the velocity range on the interface +/// @param[in] mode the current imaging mode +/// @note called on a mode change, but should also be called if a prf adjustment occurs +void Solum::updateVelocity(CusMode mode) +{ + // wait a second for the mode load to propagate internally before fetching the velociy + if (mode == ColorMode || mode == PwMode) + { + QTimer::singleShot(1000, this, [this] () + { + auto v = solumGetParam(DopplerVelocity); + if (v) + { + ui_.velocity->setText(QStringLiteral("+/- %1cm/s").arg(v)); + } + }); + } +} + +/// called when rf zoom adjusted +void Solum::onZoom(int zoom) +{ + signal_->setZoom(zoom); +} + +void Solum::connectPortChanged(QLineEdit* portEdit, QPushButton* connectButton) +{ + portEdit->setValidator(portValidator_); + connect(portEdit, &QLineEdit::textChanged, [=]() + { + const auto pos = portEdit->mapToGlobal(QPoint(0, 0)); + if (portEdit->hasAcceptableInput()) + { + portEdit->setStyleSheet(""); + connectButton->setEnabled(true); + QToolTip::showText(pos, "", portEdit); + } + else + { + portEdit->setStyleSheet("QLineEdit { border: 1px solid red }"); + connectButton->setEnabled(false); + if (portEdit->isVisible()) + QToolTip::showText(pos, portError_, portEdit); + } + }); +} + +void Solum::onIGTLServe() +{ + const auto port = ui_.igtlport->text().toInt(); + if (!igtl_.isServing()) + { + settings_->setValue("OpenIGTLink/port", port); + if (igtl_.serve(port)) + { + ui_.igtlStatusServer->setText(tr("🟢 Server is running")); + ui_.igtlport->setEnabled(false); + ui_.igtlserve->setText(tr("Stop")); + } + else + ui_.igtlStatusServer->setText( + tr("❌ Socket could not be opened on port %1").arg(port)); + } + else + { + igtl_.close(); + ui_.igtlStatusServer->setText(tr("🔴 Server is stopped")); + ui_.igtlStatusClient->clear(); + ui_.igtlStatusFPS->clear(); + ui_.igtlport->setEnabled(true); + ui_.igtlserve->setText(tr("Serve")); + } +} + +void Solum::onIGTLFlip(int check) +{ + const auto value = (check == Qt::Checked); + igtl_.setFlip(value); + settings_->setValue("OpenIGTLink/flip", value); +} diff --git a/examples/solum_qt/solumqt.h b/examples/solum_qt/solum/solumqt.h similarity index 63% rename from examples/solum_qt/solumqt.h rename to examples/solum_qt/solum/solumqt.h index 26e0082..5d8f26f 100644 --- a/examples/solum_qt/solumqt.h +++ b/examples/solum_qt/solum/solumqt.h @@ -1,12 +1,9 @@ #pragma once #include "ble.h" -#include - -namespace Ui -{ - class Solum; -} +#include "openigtlink.h" +#include "ui_solumqt.h" +#include "image.h" class UltrasoundImage; class Spectrum; @@ -14,20 +11,25 @@ class RfSignal; class Prescan; class ProbeRender; -#define CONNECT_EVENT static_cast(QEvent::User + 1) -#define CERT_EVENT static_cast(QEvent::User + 2) -#define POWER_EVENT static_cast(QEvent::User + 3) -#define SWUPDATE_EVENT static_cast(QEvent::User + 4) -#define LIST_EVENT static_cast(QEvent::User + 5) -#define IMAGE_EVENT static_cast(QEvent::User + 6) -#define PRESCAN_EVENT static_cast(QEvent::User + 7) -#define SPECTRUM_EVENT static_cast(QEvent::User + 8) -#define RF_EVENT static_cast(QEvent::User + 9) -#define IMAGING_EVENT static_cast(QEvent::User + 10) -#define BUTTON_EVENT static_cast(QEvent::User + 11) -#define ERROR_EVENT static_cast(QEvent::User + 12) -#define PROGRESS_EVENT static_cast(QEvent::User + 13) -#define TEE_EVENT static_cast(QEvent::User + 14) +#define CONNECT_EVENT static_cast(QEvent::User + 1) +#define CERT_EVENT static_cast(QEvent::User + 2) +#define POWER_EVENT static_cast(QEvent::User + 3) +#define SWUPDATE_EVENT static_cast(QEvent::User + 4) +#define LIST_EVENT static_cast(QEvent::User + 5) +#define IMAGE_EVENT static_cast(QEvent::User + 6) +#define PRESCAN_EVENT static_cast(QEvent::User + 7) +#define SPECTRUM_EVENT static_cast(QEvent::User + 8) +#define RF_EVENT static_cast(QEvent::User + 9) +#define IMAGING_EVENT static_cast(QEvent::User + 10) +#define BUTTON_EVENT static_cast(QEvent::User + 11) +#define ERROR_EVENT static_cast(QEvent::User + 12) +#define PROGRESS_EVENT static_cast(QEvent::User + 13) +#define TEE_EVENT static_cast(QEvent::User + 14) +#define IMU_EVENT static_cast(QEvent::User + 15) +#define RAWAVAIL_EVENT static_cast(QEvent::User + 16) +#define RAWREADY_EVENT static_cast(QEvent::User + 17) +#define RAWDOWNLOADED_EVENT static_cast(QEvent::User + 18) +#define IMU_PORT_EVENT static_cast(QEvent::User + 19) namespace event { @@ -102,25 +104,13 @@ namespace event public: /// default constructor /// @param[in] evt the event type - /// @param[in] data the image data - /// @param[in] w the image width - /// @param[in] h the image height - /// @param[in] bpp the image bits per pixel - /// @param[in] format the image format - /// @param[in] sz total size of the image + /// @param[in] img the image /// @param[in] overlay flag if the image came from a separated overlay - /// @param[in] imu latest imu data if sent - Image(QEvent::Type evt, const void* data, int w, int h, int bpp, CusImageFormat format, int sz, bool overlay, const QQuaternion& imu) : QEvent(evt), - data_(data), width_(w), height_(h), bpp_(bpp), format_(format), size_(sz), overlay_(overlay), imu_(imu) { } - - const void* data_; ///< pointer to the image data - int width_; ///< width of the image - int height_; ///< height of the image - int bpp_ ; ///< bits per pixel - CusImageFormat format_; ///< image format - int size_; ///< total size of image - bool overlay_; ///< flag if the image came from a separated overlay - QQuaternion imu_; ///< latest imu position + Image(QEvent::Type evt, const SolumImage& img, bool overlay) : + QEvent(evt), img_(img), overlay_(overlay) { } + + SolumImage img_; + bool overlay_; ///< flag if the image came from a separated overlay }; /// wrapper for new spectrum events that can be posted from the api callbacks @@ -141,19 +131,38 @@ namespace event int bps_ ; ///< bits per sample }; + /// wrapper for new processed image events that can be posted from the api callbacks + class ProcessedImage : public Image + { + public: + /// default constructor + /// @param[in] evt the event type + /// @param[in] img the image data + /// @param[in] overlay flag if the image came from a separated overlay + /// @param[in] imu latest imu data if sent + ProcessedImage(QEvent::Type evt, const SolumImage& img, bool overlay, const QQuaternion& imu, double mpp, double originX, double originY) : + Image(evt, img, overlay), imu_(imu), micronsPerPixel_(mpp), originX_(originX), originY_(originY) { } + + QQuaternion imu_; ///< latest imu position + double micronsPerPixel_; ///< Microns per pixel (always 1:1 aspect ratio axially/laterally) + double originX_; ///< Image origin in microns in the horizontal axis + double originY_; ///< Image origin in microns in the vertical axis + }; + /// wrapper for new rf events that can be posted from the api callbacks class RfImage : public Image { public: /// default constructor - /// @param[in] data the rf data - /// @param[in] l # of rf lines - /// @param[in] s # of samples per line - /// @param[in] bps bits per sample - /// @param[in] sz total size of the image + /// @param[in] img the rf image /// @param[in] lateral lateral spacing between lines /// @param[in] axial sample size - RfImage(const void* data, int l, int s, int bps, int sz, double lateral, double axial) : Image(RF_EVENT, data, l, s, bps, Uncompressed, sz, false, QQuaternion()), lateral_(lateral), axial_(axial) { } + RfImage(SolumImage img, double lateral, double axial) : + Image(RF_EVENT, img, false), + lateral_(lateral), + axial_(axial) + { + } double lateral_; ///< spacing between each line double axial_; ///< sample size @@ -207,6 +216,29 @@ namespace event QString exam_; ///< exam id }; + /// wrapper for new imu data events that can be posted from the api callbacks + class ImuPort : public QEvent + { + public: + /// default constructor + /// @param[in] port latest imu port + explicit ImuPort(int port) : QEvent(IMU_PORT_EVENT), port_(port) { } + + int port_; ///< latest imu port + }; + + /// wrapper for new imu data events that can be posted from the api callbacks + class Imu : public QEvent + { + public: + /// default constructor + /// @param[in] evt the event type + /// @param[in] imu latest imu data + Imu(QEvent::Type evt, const QQuaternion& imu) : QEvent(evt), imu_(imu) { } + + QQuaternion imu_; ///< latest imu position + }; + /// wrapper for error events that can be posted from the api callbacks class Error : public QEvent { @@ -230,7 +262,13 @@ namespace event }; } -using Probes = std::map; +struct ProbeData +{ + QString crt; + QString model; +}; + +using Probes = std::map; /// solum gui application class Solum : public QMainWindow @@ -246,12 +284,14 @@ class Solum : public QMainWindow virtual void closeEvent(QCloseEvent *event) override; private: - void loadProbes(const QStringList& probes); void loadApplications(const QStringList& probes); - void newProcessedImage(const void* img, int w, int h, int bpp, CusImageFormat format, int sz, bool overlay, const QQuaternion& imu); - void newPrescanImage(const void* img, int w, int h, int bpp, int sz, CusImageFormat format); - void newSpectrumImage(const void* img, int l, int s, int bps); - void newRfImage(const void* rf, int l, int s, int ss); + void newProcessedImage(const event::ProcessedImage& evt); + void newPrescanImage(const event::Image& evt); + void newSpectrumImage(const event::SpectrumImage& evt); + void newRfImage(const event::RfImage& evt); + void reflectCertification(); + void reflectProbeModelAndWorkflows(); + void reflectMode(CusMode m); void setConnected(CusConnection res, int port, const QString& msg); void certification(int daysValid); void poweringDown(CusPowerDown res, int tm); @@ -260,9 +300,11 @@ class Solum : public QMainWindow void onButton(CusButton btn, int clicks); void onTee(bool connected, const QString& serial, double timeRemaining); void setProgress(int progress); - void setError(const QString& err); + void addStatus(const QString &status); + void addError(const QString &err); void getParams(); void updateVelocity(CusMode mode); + void connectPortChanged(QLineEdit* portEdit, QPushButton* connectButton); public slots: void onRetrieve(); @@ -274,12 +316,10 @@ public slots: void onRing(); void onWiFi(); void onAp(); - void onConnect(); - void onFreeze(); + void onTcpConnect(); + void onImaging(); void onUpdate(); - void onUpdateCert(); void onLoad(); - void onProbeSelected(const QString& probe); void onMode(int); void onZoom(int); void incDepth(); @@ -297,12 +337,16 @@ public slots: void tgcTop(int); void tgcMid(int); void tgcBottom(int); + void onIGTLServe(); + void onIGTLFlip(int check); private: - bool connected_; ///< connection state + QString bleConnectedProbe_; ///< serial of the probe connected via BLE + bool tcpConnected_ = false; ///< TCP connection state bool imaging_; ///< imaging state bool teeConnected_; ///< tee connected state - Ui::Solum *ui_; ///< ui controls, etc. + QString tcpConnectedProbe_; ///< serial of the probe connected via TCP + Ui::Solum ui_; ///< ui controls, etc. UltrasoundImage* image_; ///< image display UltrasoundImage* image2_; ///< secondary image display Spectrum* spectrum_; ///< spectrum display @@ -312,6 +356,13 @@ public slots: QTimer timer_; ///< timer for updating probe status QNetworkAccessManager cloud_; ///< for accessing clarius cloud Ble ble_; ///< bluetooth module + QStringList probesSupported_; ///< result of solumProbes() API call Probes certified_; ///< list of certified probes + std::string activeWorkflow_; ///< preserves parameters across imaging runs std::unique_ptr settings_; ///< persistent settings + QIntValidator* portValidator_; ///< keeps port fields between 1 and 65535 + QString portError_; ///< error message for port validation + + std::optional igtlport_; ///< OpenIGTLink port + SolumIGTL igtl_; ///< OpenIGTLink module }; diff --git a/examples/solum_qt/solumqt.ui b/examples/solum_qt/solum/solumqt.ui similarity index 53% rename from examples/solum_qt/solumqt.ui rename to examples/solum_qt/solum/solumqt.ui index 5bb5a98..cc21ada 100644 --- a/examples/solum_qt/solumqt.ui +++ b/examples/solum_qt/solum/solumqt.ui @@ -7,11 +7,11 @@ 0 0 584 - 657 + 857 - Solum Tester + Clarius Server @@ -41,17 +41,45 @@ - 0 + 1 - + - Setup + Certificates - + + + + + QAbstractItemView::NoEditTriggers + + + true + + + true + + + 0 + + + 0 + + + true + + + true + + + false + + + - Authentication + Fetch and renew @@ -75,206 +103,12 @@ - - - Retrieve from Cloud - - - - - - - - - - - - Bluetooth - - - - - - - - - 100 - 16777215 - - - - Search - - - - - - - - 200 - 0 - - - - - - + false - - - 100 - 16777215 - - - Connect - - - - - - - - - - - false - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - On - - - - - - - false - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - Off - - - - - - - false - - - - 16777215 - 16777215 - - - - Ring - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - QLayout::SetDefaultConstraint - - - - - false - - - - 100 - 16777215 - - - - Wi-Fi - - - - - - - false - - - - 100 - 16777215 - - - - AP - - - - - - - - 150 - 0 - - - - SSID - - - - - - - - 150 - 0 - - - - Password - - - QLineEdit::Password + Retrieve from Cloud @@ -284,7 +118,7 @@ - + Qt::Vertical @@ -298,76 +132,418 @@ - + - Connection + Bluetooth - - - - - false - - - Software Update - - + + + + + + + false + + + + 100 + 16777215 + + + + Search + + + + + + + + 200 + 0 + + + + + + + + false + + + + 100 + 16777215 + + + + Connect + + + + - - - - Port - - + + + + + + false + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + On + + + + + + + false + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Off + + + + + + + false + + + + 16777215 + 16777215 + + + + Ring + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - - Connect + + + + QLayout::SetDefaultConstraint - - - - + - - + + false - - Load - - - - - - - 000.000.000.000 - - - 192.168.1.1 + + QTabWidget::North + + + Wi-Fi connection + + + + + + + 0 + 0 + + + + Reprograms the probe to join a specific Wi-Fi network. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + &SSID + + + ssid + + + + + + + + + + &Password + + + password + + + + + + + QLineEdit::Password + + + + + + + Reprogram and retrieve IP + + + + + + + + Direct connection to probe + + + + + + Reprograms the probe to set up its own access point. +After clicking the button, wait for the SSID to be published via BLE, then connect your operating system to this network. + + + true + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + 1 + 0 + + + + Reprogram and retrieve IP + + + + + - - - - Software Update Progress + + + + + false + + + Connection + + + + + + false - - 0 + + (connect to a probe via BLE first) + + + + + false + + + + 1 + 0 + + + + Software Update + + + + + + + Port + + + + + + + false + + + Connect + + + + + + + false + + + (waiting for BLE connection) + + + + + + + false + + + Load + + + + + + + + 1 + 0 + + + + (waiting for BLE message) + + + + + + + Software Update Progress + + + 0 + + + + + + + IP Address + + + + + + + QFrame::StyledPanel + + + + + + + + + + + 0 + 0 + + + + Cert Valid + + + + + + + Probe model + + + + + + + (waiting for BLE message) + + + + + + + + 0 + 0 + + + + + + + + Workflows + + + + - - - IP Address - - - - Qt::Vertical @@ -380,73 +556,6 @@ - - - - QFrame::StyledPanel - - - - - - - - - - Cert Valid - - - - - - - Probes - - - - - - - ##### - - - 11000 - - - - - - - - 0 - 0 - - - - - - - - true - - - - 150 - 0 - - - - Update Cert... - - - - - - - Workflows - - - @@ -455,235 +564,202 @@ - + + + + + false + + + + + + + Imaging mode + + + + + + + - - - - - false - - - Depth - - - - - - - - false - - - Depth + - - - - - - - QFrame::StyledPanel - - - Max: 0 cm - - - Qt::AlignCenter - - - - - - - true - - - QFrame::StyledPanel - - - +/- 0 cm/s - - - - + + + false + + + Show Prescan Image + + - - - + + + false + + + Split Overlays + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Depth + + + + + + + Gain + + + + + + + Focus + + + + + + + CFI Gain + + + + + + + Opacity + + + + + + + RF + + + + + + + IMU + + + + + + + false - - - 16777215 - 16777215 - - - - -20 - - - 20 - - - 5 - - - Qt::Horizontal + + - - - + + false - - - 16777215 - 16777215 - - - - -20 + + + - - 20 + + + + + + QFrame::StyledPanel - - 5 + + Range: 0 - 0 cm - - Qt::Horizontal + + Qt::AlignCenter - - + + - false - - - - 16777215 - 16777215 - - - - -20 - - - 20 + true - - 5 + + QFrame::StyledPanel - - Qt::Horizontal + + +/- 0 cm/s - - - - - + false - Auto Gain + Auto - + false - Auto Focus - - - - - - - false - - - IMU + Auto - + false - RF Stream - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - false - - - Show Prescan Image + Stream - - + + false - Split Overlays + Stream - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - + false @@ -714,7 +790,7 @@ - + false @@ -748,7 +824,7 @@ - + @@ -776,7 +852,7 @@ - + @@ -810,7 +886,7 @@ - + @@ -841,23 +917,115 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + Time Gain Compensation + + + + + + false + + + + 16777215 + 16777215 + + + + -20 + + + 20 + + + 5 + + + Qt::Horizontal + + + + + + + false + + + + 16777215 + 16777215 + + + + -20 + + + 20 + + + 5 + + + Qt::Horizontal + + + + + + + false + + + + 16777215 + 16777215 + + + + -20 + + + 20 + + + 5 + + + Qt::Horizontal + + + + + + + Top + + + + + + + Middle + + + + + + + Bottom + + + + + + + + false @@ -875,26 +1043,6 @@ - - - - false - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -910,6 +1058,109 @@ + + + true + + + OpenIGTLink + + + + + + Serve + + + + + + + Port + + + Qt::AlignRight + + + igtlport + + + + + + + + + + Node name + + + Qt::AlignRight + + + igtlnode + + + + + + + + + + Flip vertically + + + + + + + + + + 1 + 0 + + + + + + + + + 1 + 0 + + + + + + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + + + + true + @@ -927,19 +1178,28 @@ - + + + JobButton + QPushButton +
jobbutton.h
+
+
_tabs + tcpconnect + workflows + load + imaging update - ip + modes decdepth incdepth tgctop tgcmid tgcbottom - modes @@ -1151,22 +1411,6 @@ - - probes - currentTextChanged(QString) - Solum - onProbeSelected(QString) - - - 161 - 360 - - - 241 - 217 - - - update clicked() @@ -1312,10 +1556,10 @@ - connect + tcpconnect clicked() Solum - onConnect() + onTcpConnect() 478 @@ -1327,22 +1571,6 @@ - - updateCert - clicked() - Solum - onUpdateCert() - - - 341 - 388 - - - 228 - 273 - - - blesearch clicked() @@ -1408,14 +1636,14 @@ - split - stateChanged(int) + imaging + clicked() Solum - onSplit(int) + onImaging() - 333 - 430 + 291 + 501 291 @@ -1424,44 +1652,43 @@ - prescan - stateChanged(int) + igtlserve + clicked() Solum - onPrescan(int) + onIGTLServe() - 100 - 443 + 20 + 20 - 291 - 328 + 20 + 20 - freeze - clicked() + igtlflip + stateChanged(int) Solum - onFreeze() + onIGTLFlip(int) - 291 - 501 + 20 + 20 - 291 - 328 + 20 + 20 - onConnect() - onFreeze() + onTcpConnect() + onImaging() onLoad() onUpdate() - onProbeSelected(QString) decDepth() incDepth() tgcTop(int) @@ -1480,7 +1707,6 @@ onColorGain(int) onImu(int) onAutoGain(int) - onUpdateCert() onRfStream(int) onRing() onRetrieve() @@ -1489,5 +1715,7 @@ onFocus(int) onSplit(int) onPrescan(int) + onIGTLServe() + onIGTLFlip(int) diff --git a/examples/solum_qt/solum_qt.pro b/examples/solum_qt/solum_qt.pro new file mode 100644 index 0000000..1cede7b --- /dev/null +++ b/examples/solum_qt/solum_qt.pro @@ -0,0 +1,6 @@ +TEMPLATE = subdirs + +SUBDIRS = solum openigtlink + +openigtlink.subdir = ../../openigtlink +solum.depends = openigtlink diff --git a/examples/solum_qt/solumqt.cpp b/examples/solum_qt/solumqt.cpp deleted file mode 100644 index 6ff25ed..0000000 --- a/examples/solum_qt/solumqt.cpp +++ /dev/null @@ -1,922 +0,0 @@ -#include "solumqt.h" -#include "display.h" -#include "3d.h" -#include "ui_solumqt.h" -#include - -#define IMU_TAB 4 - -static Solum* _me; - -/// default constructor -/// @param[in] parent the parent object -Solum::Solum(QWidget *parent) : QMainWindow(parent), connected_(false), imaging_(false), teeConnected_(false), ui_(new Ui::Solum) -{ - _me = this; - ui_->setupUi(this); - setWindowIcon(QIcon(":/res/logo.png")); - image_ = new UltrasoundImage(false, this); - image2_ = new UltrasoundImage(true, this); - image2_->setVisible(false); - spectrum_ = new Spectrum(this); - signal_ = new RfSignal(this); - prescan_ = new Prescan(this); - ui_->image->addWidget(image_); - ui_->image->addWidget(prescan_); - ui_->image->addWidget(spectrum_); - ui_->image->addWidget(signal_); - ui_->image2->addWidget(image2_); - render_ = new ProbeRender(QGuiApplication::primaryScreen()); - ui_->render->addWidget(QWidget::createWindowContainer(render_)); - auto reset = new QPushButton(QStringLiteral("Reset"), this); - ui_->render->addWidget(reset); - render_->init(QStringLiteral("scanner.obj")); - render_->show(); - ui_->cfigain->setVisible(false); - ui_->velocity->setVisible(false); - ui_->opacity->setVisible(false); - ui_->rfzoom->setVisible(false); - ui_->rfStream->setVisible(false); - ui_->split->setVisible(false); - ui_->_tabs->setTabEnabled(IMU_TAB, false); - - settings_ = std::make_unique(QStringLiteral("settings.ini"), QSettings::IniFormat); - ui_->token->setText(settings_->value("token").toString()); - auto ip = settings_->value("ip").toString(); - if (!ip.isEmpty()) - ui_->ip->setText(ip); - auto port = settings_->value("port").toString(); - if (!port.isEmpty()) - ui_->port->setText(port); - auto probe = settings_->value("probe").toString(); - if (!probe.isEmpty()) - ui_->probes->setCurrentText(probe); - - // handle the reply from the call to clarius cloud to obtain json probe information - connect(&cloud_, &QNetworkAccessManager::finished, [this](QNetworkReply* reply) - { - auto result = reply->readAll(); - auto doc = QJsonDocument::fromJson(result); - // check for errors - if (doc.isNull()) - { - ui_->status->showMessage(QStringLiteral("Error retrieving certificates")); - return; - } - - certified_.clear(); - auto json = doc.object(); - if (json.contains("results") && json["results"].isArray()) - { - auto probes = json["results"].toArray(); - for (auto i = 0u; i < probes.size(); i++) - { - auto probe = probes[i].toObject(); - if (probe.contains("crt") && probe.contains("device") && probe["device"].isObject()) - { - auto device = probe["device"].toObject(); - if (device.contains("serial")) - { - auto serial = device["serial"].toString(); - if (!serial.isEmpty()) - certified_[serial] = probe["crt"].toString(); - } - } - } - - ui_->status->showMessage(QStringLiteral("Found %1 valid OEM probes").arg(certified_.size())); - } - }); - - QObject::connect(reset, &QPushButton::clicked, [this]() - { - render_->reset(); - }); - - // load probes list - solumProbes([](const char* list, int) - { - QApplication::postEvent(_me, new event::List(list, true)); - }); - - ui_->modes->blockSignals(true); - ui_->modes->addItem(QStringLiteral("B")); - ui_->modes->addItem(QStringLiteral("SC")); - ui_->modes->addItem(QStringLiteral("M")); - ui_->modes->addItem(QStringLiteral("CFI")); - ui_->modes->addItem(QStringLiteral("PDI")); - ui_->modes->addItem(QStringLiteral("PW")); - ui_->modes->addItem(QStringLiteral("NE")); - ui_->modes->addItem(QStringLiteral("SI")); - ui_->modes->addItem(QStringLiteral("RF")); - ui_->modes->blockSignals(false); - - // connect status timer - connect(&timer_, &QTimer::timeout, [this]() - { - CusStatusInfo st; - if (solumStatusInfo(&st) == 0) - { - QString teeTime; - if (teeConnected_) - teeTime = QStringLiteral(", TEE: %1%").arg(st.teeTimeRemaining); - - ui_->probeStatus->setText(QStringLiteral("Battery: %1%, Temp: %2%, FR: %3 Hz%4") - .arg(st.battery).arg(st.temperature).arg(QString::number(st.frameRate, 'f', 0)).arg(teeTime)); - } - }); - - // connect ble device list - connect(&ble_, &Ble::devices, [this](const QStringList& devs) - { - ui_->bleprobes->clear(); - for (auto d : devs) - ui_->bleprobes->addItem(d); - if (ui_->bleprobes->count()) - ui_->bleprobes->setCurrentIndex(0); - }); - - // power service ready - connect(&ble_, &Ble::powerReady, [this](bool en) - { - ui_->poweron->setEnabled(en); - ui_->poweroff->setEnabled(en); - ui_->ring->setEnabled(en); - }); - - // wifi service ready - connect(&ble_, &Ble::wifiReady, [this](bool en) - { - ui_->wifi->setEnabled(en); - ui_->ap->setEnabled(en); - }); - - // power status sent - connect(&ble_, &Ble::powered, [this](bool en) - { - ui_->status->showMessage(QStringLiteral("Powered: %1").arg(en ? QStringLiteral("On") : QStringLiteral("Off"))); - }); - - // wifi info sent - connect(&ble_, &Ble::wifiInfo, [this](const QString& info) - { - // yaml formatted network information - QStringList network = info.split(QStringLiteral("\n")); - auto getField = [&network](const QString& field) -> QString - { - QString ret; - auto f = network.filter(field); - if (f.size()) - { - ret = f[0]; - ret.replace(field + QStringLiteral(" "), QString{}); - } - return ret; - }; - auto ip = getField(QStringLiteral("ip4:")); - auto port = getField(QStringLiteral("ctl:")); - auto ssid = getField(QStringLiteral("ssid:")); - ui_->ip->setText(ip); - ui_->port->setText(port); - if (!ip.isEmpty() && !port.isEmpty()) - ui_->status->showMessage(QStringLiteral("Wi-Fi: %1 (%2) [SSID: %3]").arg(ip).arg(port).arg(ssid)); - }); -} - -/// destructor -Solum::~Solum() -{ - timer_.stop(); - delete ui_; -} - -/// loads a list of probes into the selection box -/// @param[in] probes the probes list -void Solum::loadProbes(const QStringList& probes) -{ - ui_->probes->clear(); - for (auto p : probes) - ui_->probes->addItem(p); - if (ui_->probes->count()) - ui_->probes->setCurrentIndex(0); -} - -/// loads a list of applications into selection box -/// @param[in] apps the applications list -void Solum::loadApplications(const QStringList& apps) -{ - ui_->workflows->clear(); - for (auto a : apps) - ui_->workflows->addItem(a); - if (ui_->workflows->count()) - ui_->workflows->setCurrentIndex(0); -} - -/// called when the window is closing to clean up the library -void Solum::closeEvent(QCloseEvent*) -{ - if (connected_) - solumDisconnect(); - - solumDestroy(); -} - -/// called for starting a cloud request to retrieve the probe credentials -void Solum::onRetrieve() -{ - auto token = ui_->token->text(); - if (!token.isEmpty()) - { - settings_->setValue("token", token); - QNetworkRequest request(QUrl("https://cloud.clarius.com/api/public/v0/devices/oem/?limit=300&format=json")); - request.setTransferTimeout(5000); - QByteArray auth(QString("OEM-API-Key %1").arg(token).toUtf8()); - request.setRawHeader("Authorization", auth); - cloud_.get(request); - } -} - -/// initiates ble search -void Solum::onBleSearch() -{ - ble_.search(); -} - -/// called when a ble probe is selected -void Solum::onBleProbe(int index) -{ - ui_->bleconnect->setEnabled(index >= 0); -} - -/// called when a ble connect is initiated -void Solum::onBleConnect() -{ - ble_.connectToProbe(ui_->bleprobes->currentText()); -} - -/// tries to power on probe -void Solum::onPowerOn() -{ - ble_.power(true); -} - -/// tries to power off probe -void Solum::onPowerOff() -{ - ble_.power(false); -} - -/// rings the probe -void Solum::onRing() -{ - ble_.ring(); -} - -/// tries to reprogram probe to a new wifi network (router) -void Solum::onWiFi() -{ - auto ssid = ui_->ssid->text(); - auto pw = ui_->password->text(); - if (ssid.isEmpty()) - return; - - QString req(QStringLiteral("ap: false\n")); - req += QStringLiteral("ssid: %1\n").arg(ssid); - if (!pw.isEmpty()) - req += QStringLiteral("pw: %1\n").arg(pw); - ble_.requestWifi(req); -} - -/// tries to repgram probe to it's own access point wifi -void Solum::onAp() -{ - ble_.requestWifi(QStringLiteral("ap: true\nch: auto\n")); -} - -/// handles custom events posted by solum api callbacks -/// @param[in] event the event to parse -/// @return handling status -bool Solum::event(QEvent *event) -{ - if (event->type() == CONNECT_EVENT) - { - auto evt = static_cast(event); - setConnected(evt->result_, evt->port_, evt->message_); - return true; - } - else if (event->type() == CERT_EVENT) - { - auto evt = static_cast(event); - certification(evt->daysValid_); - return true; - } - else if (event->type() == POWER_EVENT) - { - auto evt = static_cast(event); - poweringDown(evt->res_, evt->timeOut_); - return true; - } - else if (event->type() == SWUPDATE_EVENT) - { - auto evt = static_cast(event); - softwareUpdate(evt->res_); - return true; - } - else if (event->type() == LIST_EVENT) - { - auto evt = static_cast(event); - if (evt->probes_) - loadProbes(evt->list_); - else - loadApplications(evt->list_); - return true; - } - else if (event->type() == IMAGE_EVENT) - { - auto evt = static_cast(event); - newProcessedImage(evt->data_, evt->width_, evt->height_, evt->bpp_, evt->format_, evt->size_, evt->overlay_, evt->imu_); - return true; - } - else if (event->type() == PRESCAN_EVENT) - { - auto evt = static_cast(event); - newPrescanImage(evt->data_, evt->width_, evt->height_, evt->bpp_, evt->size_, evt->format_); - return true; - } - else if (event->type() == SPECTRUM_EVENT) - { - auto evt = static_cast(event); - newSpectrumImage(evt->data_, evt->lines_, evt->samples_, evt->bps_); - return true; - } - else if (event->type() == RF_EVENT) - { - auto evt = static_cast(event); - newRfImage(evt->data_, evt->width_, evt->height_, evt->bpp_ / 8); - return true; - } - else if (event->type() == IMAGING_EVENT) - { - auto evt = static_cast(event); - imagingState(evt->state_, evt->imaging_); - return true; - } - else if (event->type() == BUTTON_EVENT) - { - auto evt = static_cast(event); - onButton(evt->button_, evt->clicks_); - return true; - } - else if (event->type() == PROGRESS_EVENT) - { - setProgress((static_cast(event))->progress_); - return true; - } - else if (event->type() == ERROR_EVENT) - { - setError((static_cast(event))->error_); - return true; - } - else if (event->type() == TEE_EVENT) - { - auto evt = static_cast(event); - onTee(evt->connected_, evt->serial_, evt->timeRemaining_); - return true; - } - - return QMainWindow::event(event); -} - -/// called when the api returns an error -/// @param[in] err the error message -void Solum::setError(const QString& err) -{ - ui_->status->showMessage(QStringLiteral("Error: %1").arg(err)); -} - -/// called when there's a new connection event -/// @param[in] res the connection result -/// @param[in] port the connection port -/// @param[in] msg the associated message -void Solum::setConnected(CusConnection res, int port, const QString& msg) -{ - if (res == ProbeConnected) - { - timer_.start(1000); - connected_ = true; - ui_->status->showMessage(QStringLiteral("Connected on port: %1").arg(port)); - ui_->connect->setText("Disconnect"); - ui_->update->setEnabled(true); - ui_->load->setEnabled(true); - - // load the certificate if it was already retrieved from the cloud - QString serial = ui_->bleprobes->currentText(); - if (certified_.count(serial)) - solumSetCert(certified_[serial].toLatin1()); - } - else if (res == ProbeDisconnected) - { - timer_.stop(); - connected_ = false; - ui_->status->showMessage(QStringLiteral("Disconnected")); - ui_->connect->setText(QStringLiteral("Connect")); - ui_->cert->clear(); - ui_->freeze->setEnabled(false); - ui_->update->setEnabled(false); - ui_->load->setEnabled(false); - // disable controls upon disconnect - imagingState(ImagingNotReady, false); - } - else if (res == ConnectionFailed || res == ConnectionError) - ui_->status->showMessage(QStringLiteral("Error connecting: %1").arg(msg)); - else if (res == SwUpdateRequired) - ui_->status->showMessage(QStringLiteral("Software update required prior to imaging")); -} - -/// called when a new certification message has been sent -/// @param[in] daysValid # of days valid for certificate -void Solum::certification(int daysValid) -{ - if (daysValid == CERT_INVALID) - ui_->cert->setText(QStringLiteral("Invalid")); - else if (!daysValid) - ui_->cert->setText(QStringLiteral("Expired")); - else - ui_->cert->setText(QStringLiteral("%1 Days").arg(daysValid)); -} - -/// called when there's a power down event -/// @param[in] res the power down reason -/// @param[in] tm the associated timeout -void Solum::poweringDown(CusPowerDown res, int tm) -{ - if (res == Idle) - ui_->status->showMessage(QStringLiteral("Idle power down in: %1s").arg(tm)); - else if (res == TooHot) - ui_->status->showMessage(QStringLiteral("Heating power down in: %1s").arg(tm)); - else if (res == LowBattery) - ui_->status->showMessage(QStringLiteral("Battery low power down in: %1s").arg(tm)); - else if (res == ButtonOff) - ui_->status->showMessage(QStringLiteral("Button press power down in: %1s").arg(tm)); -} - -/// called when there's a software update notification -/// @param[in] res the software update result -void Solum::softwareUpdate(CusSwUpdate res) -{ - if (res == SwUpdateSuccess) - ui_->status->showMessage(QStringLiteral("Successfully updated software")); - else if (res == SwUpdateCurrent) - ui_->status->showMessage(QStringLiteral("Software already up to date")); - else - ui_->status->showMessage(QStringLiteral("Software not updated: %1").arg(res)); -} - -/// called when the imaging state changes -/// @param[in] state the imaging ready code -/// @param[in] imaging the imaging state -void Solum::imagingState(CusImagingState state, bool imaging) -{ - bool ready = (state != ImagingNotReady); - ui_->freeze->setEnabled(ready ? true : false); - ui_->autogain->setEnabled(ready ? true : false); - ui_->autofocus->setEnabled(ready ? true : false); - ui_->decdepth->setEnabled(ready ? true : false); - ui_->incdepth->setEnabled(ready ? true : false); - ui_->gain->setEnabled(ready ? true : false); - ui_->focus->setEnabled((ready && !ui_->autofocus->isChecked()) ? true : false); - ui_->cfigain->setEnabled(ready ? true : false); - ui_->opacity->setEnabled(ready ? true : false); - ui_->rfzoom->setEnabled(ready ? true : false); - ui_->rfStream->setEnabled(ready ? true : false); - ui_->prescan->setEnabled(ready ? true : false); - ui_->split->setEnabled(ready ? true : false); - ui_->imu->setEnabled(ready ? true : false); - bool ag = ui_->autogain->isChecked(); - ui_->tgctop->setEnabled((ready && !ag) ? true : false); - ui_->tgcmid->setEnabled((ready && !ag) ? true : false); - ui_->tgcbottom->setEnabled((ready && !ag) ? true : false); - ui_->modes->setEnabled(ready ? true : false); - - ui_->status->showMessage(QStringLiteral("Image: %1").arg(imaging ? QStringLiteral("Running") : QStringLiteral("Frozen"))); - if (ready) - { - ui_->freeze->setText(imaging ? QStringLiteral("Stop") : QStringLiteral("Run")); - imaging_ = imaging; - getParams(); - image_->checkRoi(); - image_->checkGate(); - } - else if (state == CertExpired) - ui_->status->showMessage(QStringLiteral("Certificate needs updating prior to imaging")); -} - -/// called when there is a button press on the ultrasound -/// @param[in] btn the button pressed -/// @param[in] clicks # of clicks used -void Solum::onButton(CusButton btn, int clicks) -{ - QString text; - switch (btn) - { - case ButtonDown: text = QStringLiteral("Down"); break; - case ButtonUp: text = QStringLiteral("Up"); break; - case ButtonHandle: text = QStringLiteral("Handle"); break; - } - - ui_->status->showMessage(QStringLiteral("Button %1 Pressed, %2 Clicks").arg(text).arg(clicks)); -} - -/// called when there is a tee connect or disconnect -/// @param[in] connected flag if the probe is connected or not -/// @param[in] serial the serial number if the probe is connected -/// @param[in] timeRemaining the time remaining in percent if the probe is connected -void Solum::onTee(bool connected, const QString& serial, double timeRemaining) -{ - teeConnected_ = connected; - if (connected) - ui_->status->showMessage(QStringLiteral("TEE Connected: %1 @ %2% Remaining").arg(serial).arg(timeRemaining)); - else - ui_->status->showMessage(QStringLiteral("TEE Disconnected")); -} - -/// called when the download progress changes -/// @param[in] progress the current progress -void Solum::setProgress(int progress) -{ - ui_->progress->setValue(progress); -} - -/// called when a new image has been sent -/// @param[in] img the image data -/// @param[in] w width of the image -/// @param[in] h height of the image -/// @param[in] bpp the bits per pixel -/// @param[in] format the image format -/// @param[in] sz size of the image in bytes -/// @param[in] imu the imu data if valid -void Solum::newProcessedImage(const void* img, int w, int h, int bpp, CusImageFormat format, int sz, bool overlay, const QQuaternion& imu) -{ - if (overlay) - image2_->loadImage(img, w, h, bpp, format, sz); - else - image_->loadImage(img, w, h, bpp, format, sz); - - if (!imu.isNull()) - render_->update(imu); -} - -/// called when a new pre-scan image has been sent -/// @param[in] img the image data -/// @param[in] w width of the image -/// @param[in] h height of the image -/// @param[in] bpp the bits per pixel -/// @param[in] sz size of the image in bytes -/// @param[in] format the format of the prescan image -void Solum::newPrescanImage(const void* img, int w, int h, int bpp, int sz, CusImageFormat format) -{ - prescan_->loadImage(img, w, h, bpp, format, sz); -} - -/// called when a new spectrum image has been sent -/// @param[in] img the image data -/// @param[in] l # of lines -/// @param[in] s # of samples -/// @param[in] bps the bits per sample -void Solum::newSpectrumImage(const void* img, int l, int s, int bps) -{ - spectrum_->loadImage(img, l, s, bps); -} - -/// called when new rf data has been sent -/// @param[in] rf the rf data -/// @param[in] l # of rf lines -/// @param[in] s # of rf samples per line -/// @param[in] ss sample size (should always be 2) -void Solum::newRfImage(const void* rf, int l, int s, int ss) -{ - signal_->loadSignal(rf, l, s, ss); -} - -/// called when the connect/disconnect button is clicked -void Solum::onConnect() -{ - if (!connected_) - { - if (solumConnect(ui_->ip->text().toStdString().c_str(), ui_->port->text().toInt()) < 0) - ui_->status->showMessage(QStringLiteral("Connection failed")); - else - ui_->status->showMessage(QStringLiteral("Trying connection")); - - settings_->setValue("ip", ui_->ip->text()); - settings_->setValue("port", ui_->port->text()); - } - else - { - if (solumDisconnect() < 0) - ui_->status->showMessage(QStringLiteral("Disconnect failed")); - } -} - -/// called when the freeze button is clicked -void Solum::onFreeze() -{ - if (!connected_) - return; - - if (solumRun(imaging_ ? 0 : 1) < 0) - ui_->status->showMessage(QStringLiteral("Error requesting imaging run/stop")); - else - { - imagingState(ImagingReady, !imaging_); - if (imaging_) - spectrum_->reset(); - } -} - -/// initiates a software update -void Solum::onUpdate() -{ - if (!connected_) - return; - - auto filePath = QFileDialog::getOpenFileName(this, - QStringLiteral("Choose Firmware Package"), QString(), QStringLiteral("Zip Files (*.zip)")); - if (filePath.isEmpty()) - return; - - if (solumSoftwareUpdate( - filePath.toStdString().c_str(), - // software update result - [](CusSwUpdate res) - { - QApplication::postEvent(_me, new event::SwUpdate(res)); - }, - // download progress - [](int progress) - { - QApplication::postEvent(_me, new event::Progress(progress)); - }, 0) < 0) - ui_->status->showMessage(QStringLiteral("Error requesting software update")); -} - -/// called to load a certificate -void Solum::onUpdateCert() -{ - auto cert = QFileDialog::getOpenFileName(this, - QStringLiteral("Load Certificate"), QString(), QStringLiteral("Certs (*.pem *.crt);;All Files (*)")); - if (cert.isEmpty()) - return; - - QFile f(cert); - if (f.open(QIODevice::ReadOnly | QIODevice::Text)) - { - QTextStream stream(&f); - auto text = stream.readAll(); - solumSetCert(text.toStdString().c_str()); - } -} - -/// initiates a workflow load -void Solum::onLoad() -{ - if (!connected_) - return; - - if (solumLoadApplication(ui_->probes->currentText().toStdString().c_str(), ui_->workflows->currentText().toStdString().c_str()) < 0) - ui_->status->showMessage(QStringLiteral("Error requesting application load")); - // update depth range on a successful load - else - { - // wait a second for the application load to propagate internally before fetching the range - // ideally the api would provide a callback for when the application is fully loaded (ofi) - QTimer::singleShot(1000, this, [this] () - { - CusRange range; - if (solumGetRange(ImageDepth, &range) == 0) - { - ui_->maxdepth->setText(QStringLiteral("Max: %1cm").arg(range.max)); - } - }); - } -} - -/// called when user selects a new probe definition -/// @param[in] probe the probe selected -void Solum::onProbeSelected(const QString &probe) -{ - if (!probe.isEmpty()) - { - solumApplications(probe.toStdString().c_str(), [](const char* list, int) - { - QApplication::postEvent(_me, new event::List(list, false)); - }); - settings_->setValue("probe", probe); - } -} - -/// increases the depth -void Solum::incDepth() -{ - auto v = solumGetParam(ImageDepth); - if (v != -1) - solumSetParam(ImageDepth, v + 1.0); -} - -/// decreases the depth -void Solum::decDepth() -{ - auto v = solumGetParam(ImageDepth); - if (v > 1.0) - solumSetParam(ImageDepth, v - 1.0); -} - -/// called when gain adjusted -/// @param[in] gn the gain level -void Solum::onGain(int gn) -{ - solumSetParam(Gain, gn); -} - -/// called when manual focus adjusted -/// @param[in] fd the focus depth -void Solum::onFocus(int fd) -{ - auto v = solumGetParam(ImageDepth); - if (fd < v) - solumSetParam(FocusDepth, fd); -} - -/// called when color gain adjusted -/// @param[in] gn the gain level -void Solum::onColorGain(int gn) -{ - solumSetParam(ColorGain, gn); -} - -/// called when strain opacity adjusted -/// @param[in] gn the opacity level -void Solum::onOpacity(int gn) -{ - solumSetParam(StrainOpacity, gn); -} - -/// called when auto gain enable adjusted -/// @param[in] state checkbox state -void Solum::onAutoGain(int state) -{ - bool en = (state == Qt::Checked); - solumSetParam(AutoGain, en ? 1 : 0); - ui_->tgctop->setEnabled(en ? false: true); - ui_->tgcmid->setEnabled(en ? false: true); - ui_->tgcbottom->setEnabled(en ? false: true); - // reset the tgc sliders - ui_->tgctop->setValue(0); - ui_->tgcmid->setValue(0); - ui_->tgcbottom->setValue(0); -} - -/// called when auto focus enable adjusted -/// @param[in] state checkbox state -void Solum::onAutoFocus(int state) -{ - bool en = (state == Qt::Checked); - solumSetParam(AutoFocus, en ? 1 : 0); - ui_->focus->setEnabled(en ? false: true); -} - -/// called when imu enable adjusted -/// @param[in] state checkbox state -void Solum::onImu(int state) -{ - ui_->_tabs->setTabEnabled(IMU_TAB, (state == Qt::Checked)); - solumSetParam(ImuStreaming, (state == Qt::Checked) ? 1 : 0); -} - -/// called when rf stream enable adjusted -/// @param[in] state checkbox state -void Solum::onRfStream(int state) -{ - solumSetParam(RfStreaming, (state == Qt::Checked) ? 1 : 0); -} - -/// called when separate overlays is changed -/// @param[in] state checkbox state -void Solum::onSplit(int state) -{ - bool en = (state == Qt::Checked); - solumSeparateOverlays(en ? 1 : 0); - image2_->setVisible(en); -} - -/// called when separate overlays is changed -/// @param[in] state checkbox state -void Solum::onPrescan(int state) -{ - bool en = (state == Qt::Checked); - prescan_->setVisible(en); -} - -/// sets the tgc top -/// @param[in] v the tgc value -void Solum::tgcTop(int v) -{ - CusTgc t; - t.top = v; - t.mid = ui_->tgcmid->value(); - t.bottom = ui_->tgcbottom->value(); - solumSetTgc(&t); -} - -/// sets the tgc mid -/// @param[in] v the tgc value -void Solum::tgcMid(int v) -{ - CusTgc t; - t.top = ui_->tgctop->value(); - t.mid = v; - t.bottom = ui_->tgcbottom->value(); - solumSetTgc(&t); -} - -/// sets the tgc bottom -/// @param[in] v the tgc value -void Solum::tgcBottom(int v) -{ - CusTgc t; - t.top = ui_->tgctop->value(); - t.mid = ui_->tgcmid->value(); - t.bottom = v; - solumSetTgc(&t); -} - -/// get the initial parameter values -void Solum::getParams() -{ - auto v = solumGetParam(ImageDepth); - if (v != -1 && image_) - image_->setDepth(v); - - v = solumGetParam(AutoGain); - ui_->autogain->setChecked(v > 0); - v = solumGetParam(AutoFocus); - ui_->autofocus->setChecked(v > 0); - v = solumGetParam(ImuStreaming); - ui_->imu->setChecked(v > 0); - v = solumGetParam(RfStreaming); - ui_->rfStream->setChecked(v > 0); - - CusTgc t; - if (solumGetTgc(&t) == 0) - { - ui_->tgctop->setValue(static_cast(t.top)); - ui_->tgcmid->setValue(static_cast(t.mid)); - ui_->tgcbottom->setValue(static_cast(t.bottom)); - } -} - -/// called on a mode change -void Solum::onMode(int mode) -{ - auto m = static_cast(mode); - if (solumSetMode(m) < 0) - ui_->status->showMessage(QStringLiteral("Error setting imaging mode")); - else - { - spectrum_->setVisible(m == MMode || m == PwMode); - signal_->setVisible(m == RfMode); - ui_->cfigain->setVisible(m == ColorMode || m == PowerMode); - ui_->velocity->setVisible(m == ColorMode || m == PwMode); - ui_->opacity->setVisible(m == Strain); - ui_->rfzoom->setVisible(m == RfMode); - ui_->rfStream->setVisible(m == RfMode); - ui_->split->setVisible(m == ColorMode || m == PowerMode || m == Strain); - - updateVelocity(m); - } -} - -/// updates the velocity range on the interface -/// @param[in] mode the current imaging mode -/// @note called on a mode change, but should also be called if a prf adjustment occurs -void Solum::updateVelocity(CusMode mode) -{ - // wait a second for the mode load to propagate internally before fetching the velociy - if (mode == ColorMode || mode == PwMode) - { - QTimer::singleShot(1000, this, [this] () - { - auto v = solumGetParam(DopplerVelocity); - if (v) - { - ui_->velocity->setText(QStringLiteral("+/- %1cm/s").arg(v)); - } - }); - } -} - -/// called when rf zoom adjusted -void Solum::onZoom(int zoom) -{ - signal_->setZoom(zoom); -} diff --git a/include/solum/solum.h b/include/solum/solum.h index 133069e..b6821c4 100644 --- a/include/solum/solum.h +++ b/include/solum/solum.h @@ -1,39 +1,64 @@ #pragma once + #include "solum_export.h" #include "solum_cb.h" -extern "C" +/// probe connection parameters for solumConnect +typedef struct _CusConnectionParams +{ + const char* ipAddress; ///< the ip address of the probe + unsigned int port; ///< the probe's tcp port to connect to + long long int networkId; ///< the wifi network id obtained when auto-joining wifi on android. optional, 0 by default + +} CusConnectionParams; + +/// initialization parameters for solumInit +typedef struct _CusInitParams { + struct Args + { + int argc; ///< the argument count for input parameters to pass to the library + char** argv; ///< the arguments to pass to the library, possibly required for qt graphics buffer initialization + } + args; + const char* storeDir; ///< the directory to store security keys + CusConnectFn connectFn; ///< connection status callback + CusCertFn certFn; ///< certificate status callback + CusPowerDownFn powerDownFn; ///< probe power down callback + CusImagingFn imagingFn; ///< imaging state callback + CusButtonFn buttonFn; ///< button press callback + CusErrorFn errorFn; ///< error message callback + CusNewProcessedImageFn newProcessedImageFn; ///< new processed image callback (scan-converted image) + CusNewRawImageFn newRawImageFn; ///< new raw image callback (pre scan-converted image or rf data) + CusNewSpectralImageFn newSpectralImageFn; ///< new processed spectral image callback + CusNewImuPortFn newImuPortFn; ///< new imu udp port callback + CusNewImuDataFn newImuDataFn; ///< new imu data callback + int width; ///< the width of the output buffer + int height; ///< the height of the output buffer + +} CusInitParams; + +#ifdef __cplusplus +extern "C" { +#endif + /// initializes the solum module - /// @param[in] argc the argument count for input parameters to pass to the library - /// @param[in] argv the arguments to pass to the library, possibly required for qt graphics buffer initialization - /// @param[in] dir the directory to store security keys - /// @param[in] connect connection status callback - /// @param[in] cert certificate status callback - /// @param[in] power probe power down callback - /// @param[in] newProcessedImage new processed image callback (scan-converted image) - /// @param[in] newRawImage new raw image callback - (pre scan-converted image) - /// @param[in] newSpectralImage new processed spectral image callback - /// @param[in] imaging imaging state callback - /// @param[in] btn button press callback - /// @param[in] err error message callback - /// @param[in] width the width of the output buffer - /// @param[in] height the height of the output buffer + /// @param[in] params the sdk configuration parameters /// @return success of the call /// @retval 0 the initialization was successful /// @retval -1 the initialization was not successful /// @note must be called before any other functions will succeed - SOLUM_EXPORT int solumInit(int argc, char** argv, const char* dir, - CusConnectFn connect, CusCertFn cert, CusPowerDownFn power, - CusNewProcessedImageFn newProcessedImage, CusNewRawImageFn newRawImage, - CusNewSpectralImageFn newSpectralImage, CusImagingFn imaging, CusButtonFn btn, CusErrorFn err, - int width, int height); + SOLUM_EXPORT int solumInit(const CusInitParams* params); + + /// get init params with default values + /// @return a zero initialized struct + SOLUM_EXPORT CusInitParams solumDefaultInitParams(void); /// cleans up memory allocated by the solum module /// @retval 0 the destroy attempt was successful /// @retval -1 the destroy attempt was not successful /// @note should be called prior to exiting the application - SOLUM_EXPORT int solumDestroy(); + SOLUM_EXPORT int solumDestroy(void); /// sets a callback for the tee connectivity function /// @param[in] tee the callback function @@ -43,34 +68,39 @@ extern "C" SOLUM_EXPORT int solumSetTeeFn(CusTeeConnectFn tee); /// retrieves the firmware version for a given platform + /// @note this is the version supported by the sdk, not the version of any connected probe, + /// use this string to download the firmware binary from clarius cloud and update the probe /// @param[in] platform the platform to retrieve the firmware version for /// @param[out] version holds the firmware version for the given platform - /// @param[in] sz size of the version string buffer, suggest at least 32 bytes allocated + /// @param[in] sz size of the version string buffer, with at least 128 bytes allocated /// @return success of the call /// @retval 0 the information was retrieved /// @retval -1 the information could not be retrieved SOLUM_EXPORT int solumFwVersion(CusPlatform platform, char* version, int sz); + /// get connection params with default values + /// @return a zero initialized struct + SOLUM_EXPORT CusConnectionParams solumDefaultConnectionParams(void); + /// connects to a probe that is on the same network as the caller - /// @param[in] ipAddress the ip address of the probe - /// @param[in] port the probe's tcp port to connect to + /// @param[in] params the connection parameters /// @return success of the call /// @retval 0 the connection attempt was successful /// @retval -1 the connection attempt was not successful - SOLUM_EXPORT int solumConnect(const char* ipAddress, unsigned int port); + SOLUM_EXPORT int solumConnect(const CusConnectionParams* params); /// disconnects from an existing connection /// @return success of the call /// @retval 0 disconnection was successful /// @retval -1 the disconnection was unsuccessful - SOLUM_EXPORT int solumDisconnect(); + SOLUM_EXPORT int solumDisconnect(void); /// retrieves the current connected state of the module /// @return the connected state of the module /// @retval 0 there is currently no connection /// @retval 1 there is currently a connection /// @retval -1 the module is not initialized - SOLUM_EXPORT int solumIsConnected(); + SOLUM_EXPORT int solumIsConnected(void); /// sets the certificate for the probe to be connected with /// @param[in] cert the certificate provided by clarius @@ -158,7 +188,7 @@ extern "C" /// @retval -1 the shutdown request could not be made /// @note it is typically desirable to disconnect from bluetooth once the tcp connection has been established /// instead of relying on the power service, this function can be used to power down the probe over tcp - SOLUM_EXPORT int solumPowerDown(); + SOLUM_EXPORT int solumPowerDown(void); /// sets the internal probe settings to be applied upon a connection or when an existing connection exists /// @param[in] settings the structure containing the probe settings @@ -203,6 +233,14 @@ extern "C" /// @retval -1 tgc set request could not be made SOLUM_EXPORT int solumGetTgc(CusTgc* tgc); + /// retrieves the active region for the grayscale image + /// @param[out] points holds a vector of points in x/y format + /// @param[in] count the number of points to generate (points buffer must be count x 2 or larger) + /// @return success of the call + /// @retval 0 roi was retrieved + /// @retval -1 roi could not be retrieved + SOLUM_EXPORT int solumGetActiveRegion(double* points, int count); + /// retrieves the roi for the current mode if valid /// @param[out] points holds a vector of points in x/y format /// @param[in] count the number of points to generate (points buffer must be count x 2 or larger) @@ -224,7 +262,7 @@ extern "C" /// @return success of the call /// @retval 0 roi could be adjusted /// @retval -1 roi could not be adjusted - SOLUM_EXPORT int solumMaximizeRoi(); + SOLUM_EXPORT int solumMaximizeRoi(void); /// retrieves the gate for the current mode if valid /// @param[out] lines holds the lines that can be drawn to portray the gate on the image @@ -250,7 +288,7 @@ extern "C" /// retrieves the current imaging mode /// @return the current imaging mode - SOLUM_EXPORT CusMode solumGetMode(); + SOLUM_EXPORT CusMode solumGetMode(void); /// enables the 5v output on or off /// @param[in] en the enable state, set to 1 to turn 5v on, or 0 to turn off @@ -284,26 +322,35 @@ extern "C" /// @retval -1 the reset could not be performed SOLUM_EXPORT int solumResetProbe(CusProbeReset reset); + /// makes a request to return the availability of all the raw data currently buffered on the probe + /// @param[in] fn result callback function that will return all the timestamps of the data blocks that are buffered + /// @return success of the call + /// @retval 0 the request was successfully made + /// @retval -1 the request could not be made + /// @note the probe must be frozen with raw data buffering enabled prior to calling the function + SOLUM_EXPORT int solumRawDataAvailability(CusRawAvailabilityFn fn); + /// makes a request for raw data from the probe /// @param[in] start the first frame to request, as determined by timestamp in nanoseconds, set to 0 along with end to requests all data in buffer /// @param[in] end the last frame to request, as determined by timestamp in nanoseconds, set to 0 along with start to requests all data in buffer - /// @param[in] res result callback function, will return size of buffer required upon success, 0 if no raw data was buffered, or -1 if request could not be made, + /// @param[in] lzo flag to specify a tarball with lzo compressed raw data inside (default) vs no compression of raw data + /// @param[in] fn result callback function, will return size of buffer required upon success, 0 if no raw data was buffered, or -1 if request could not be made /// @return success of the call /// @retval 0 the request was successfully made /// @retval -1 the request could not be made /// @note the probe must be frozen and in a raw data buffering mode in order for the call to succeed - SOLUM_EXPORT int solumRequestRawData(long long int start, long long int end, CusRawFn res); + SOLUM_EXPORT int solumRequestRawData(long long int start, long long int end, int lzo, CusRawRequestFn fn); /// retrieves raw data from a previous request /// @param[out] data a pointer to a buffer that has been allocated to read the raw data into, this must be pre-allocated with /// the size returned from a previous call to solumRequestRawData - /// @param[in] res result callback function, will return size of buffer required upon success, 0 if no raw data was buffered, or -1 if request could not be made, + /// @param[in] fn result callback function, will return size of buffer required upon success, 0 if no raw data was buffered, or -1 if request could not be made, /// @param[in] progress download progress callback function that outputs the progress in percent /// @return success of the call /// @retval 0 the read request was successfully made /// @retval -1 the read request could not be made /// @note the probe must be frozen and a successful call to solumRequestRawData must have taken place in order for the call to succeed - SOLUM_EXPORT int solumReadRawData(void** data, CusRawFn res, CusProgressFn progress); + SOLUM_EXPORT int solumReadRawData(void** data, CusRawFn fn, CusProgressFn progress); /// sets a low level parameter to a specific value to gain access to lower level device control /// @param[in] prm the parameter to change @@ -312,6 +359,7 @@ extern "C" /// @retval 0 the call was successful /// @retval -1 the call was not successful /// @note see external documentation for supported parameters + /// @warning changing parameters through this function may result in unstable operation, degradation of image quality, or operation outside of the safety limits that clarius tests to SOLUM_EXPORT int solumSetLowLevelParam(const char* prm, double val); /// enables or disables a low level parameter to gain access to lower device control @@ -321,6 +369,7 @@ extern "C" /// @retval 0 the call was successful /// @retval -1 the call was not successful /// @note see external documentation for supported parameters + /// @warning changing parameters through this function may result in unstable operation, degradation of image quality, or operation outside of the safety limits that clarius tests to SOLUM_EXPORT int solumEnableLowLevelParam(const char* prm, int en); /// sets a pulse shape parameter to a specific value to gain access to lower level device control @@ -330,6 +379,7 @@ extern "C" /// @retval 0 the call was successful /// @retval -1 the call was not successful /// @note see external documentation for supported parameters + /// @warning changing parameters through this function may result in unstable operation, degradation of image quality, or operation outside of the safety limits that clarius tests to SOLUM_EXPORT int solumSetLowLevelPulse(const char* prm, const char* shape); /// retrieves a low level parameter value @@ -338,6 +388,13 @@ extern "C" /// @retval -1 if the parameter value retrieval could not be made SOLUM_EXPORT double solumGetLowLevelParam(const char* prm); + /// retrieves the acoustic indices for the loaded application, imaging mode, and parameter settings + /// @param[out] indices the acoustic index values + /// @return success of the call + /// @retval 0 the call was successful + /// @retval -1 the call was not successful + SOLUM_EXPORT int solumGetAcousticIndices(CusAcoustic* indices); + /// set the tee exam info for a connected probe /// @param[in] id the patient id /// @param[in] name the patient name @@ -346,4 +403,7 @@ extern "C" /// @retval 0 the function was successful /// @retval -1 the function was not successful SOLUM_EXPORT int solumSetTeeExamInfo(const char* id, const char* name, const char* exam); + +#ifdef __cplusplus } +#endif diff --git a/include/solum/solum_cb.h b/include/solum/solum_cb.h index 676d7f3..5044a1b 100644 --- a/include/solum/solum_cb.h +++ b/include/solum/solum_cb.h @@ -1,6 +1,7 @@ #pragma once #include "solum_def.h" +#include /// string list callback function /// @param[in] list the string list @@ -16,7 +17,7 @@ typedef void (*CusConnectFn)(CusConnection res, int port, const char* status); typedef void (*CusCertFn)(int daysValid); /// powering down callback function /// @param[in] res the power down reason -/// @param[in] tm time for when probe is powering down, 0 for immediately +/// @param[in] tm time in seconds for when probe is powering down, 0 for immediately typedef void (*CusPowerDownFn)(CusPowerDown res, int tm); /// software update callback function /// @param[in] res the software update result @@ -38,7 +39,12 @@ typedef void (*CusNewProcessedImageFn)(const void* img, const CusProcessedImageI /// @param[in] nfo image information associated with the image data typedef void (*CusNewSpectralImageFn)(const void* img, const CusSpectralImageInfo* nfo); /// imaging callback function -/// @param[in] state the imaging ready state +/// used primarily to denote 4 different scenarios: +/// 1. when imaging is ready after an application load or parameter update (ImagingReady state) +/// 2. when there is an error after trying to load an application or updating a parameter (ImagingNotReady state) +/// 3. when the low bandwidth flag has changed to denote that imaging has been re-optimized for the network performance (LowBandwidth state) +/// 4. when the probe has frozen or unfrozen due to an internal state change (all other states) +/// @param[in] state the imaging state /// @param[in] imaging 1 = running , 0 = stopped typedef void (*CusImagingFn)(CusImagingState state, int imaging); /// button callback function @@ -48,12 +54,24 @@ typedef void (*CusButtonFn)(CusButton btn, int clicks); /// progress callback function /// @param[in] progress the current progress in percent typedef void (*CusProgressFn)(int progress); +/// raw data availability callback function +/// @param[in] res the request result: 0 on success, -1 on error +/// @param[in] n_b the number of b timestamps within the array of b +/// @param[in] b an array of timestamps for raw b data, null on error +/// @param[in] n_iqrf the number of iq/rf timestamps within the array of iqrf +/// @param[in] iqrf an array of timestamps for raw iq/rf data, null on error +typedef void (*CusRawAvailabilityFn)(int res, int n_b, const long long* b, int n_iqrf, const long long* iqrf); +/// raw data request callback function +/// @param[in] res the raw data result, typically the size of the data package requested or actually downloaded +/// @param[in] extension the file extension of the packaged data +typedef void (*CusRawRequestFn)(int res, const char* extension); /// raw data callback function /// @param[in] res the raw data result, typically the size of the data package requested or actually downloaded typedef void (*CusRawFn)(int res); /// error callback function +/// @param[in] code error code to associate with the error /// @param[in] msg the error message with associated error that occurred -typedef void (*CusErrorFn)(const char* msg); +typedef void (*CusErrorFn)(CusErrorCode code, const char* msg); /// tee connection callback function /// @param[in] connected flag associated with the tee having a disposable probe connection /// @param[in] serial if a probe is connected, the serial number of the probe @@ -62,3 +80,9 @@ typedef void (*CusErrorFn)(const char* msg); /// @param[in] name patient name if burned in to the probe /// @param[in] exam exam id if burned in to the probe typedef void (*CusTeeConnectFn)(bool connected, const char* serial, double timeRemaining, const char* id, const char* name, const char* exam); +/// new imu data streaming port function +/// @param[in] port the new imu data UDP streaming port +typedef void (*CusNewImuPortFn)(int port); +/// new imu data callback function +/// @param[in] pos the positional information data tagged with the image +typedef void (*CusNewImuDataFn)(const CusPosInfo* pos); diff --git a/include/solum/solum_def.h b/include/solum/solum_def.h index 6f3d746..78c66bd 100644 --- a/include/solum/solum_def.h +++ b/include/solum/solum_def.h @@ -1,7 +1,7 @@ #pragma once // SDK: solum -// Version: 11.0.0 +// Version: 12.0.2 #define CUS_MAXTGC 10 #define CUS_SUCCESS 0 @@ -84,6 +84,7 @@ typedef enum _CusConnection ProbeDisconnected, ///< Disconnected from probe ConnectionFailed, ///< Failed to connect to probe SwUpdateRequired, ///< Software update required + OSUpdateRequired, ///< Scanner O/S update required } CusConnection; @@ -182,6 +183,8 @@ typedef enum _CusPowerDown TooHot, ///< Probe got too hot LowBattery, ///< Low battery ButtonOff, ///< User held button to shut down probe + ChargingInDock, ///< Probe was docked in charger + SoftwareShutdown, ///< Solum software sent shutdown command } CusPowerDown; @@ -205,6 +208,19 @@ typedef enum _CusSwUpdate } CusSwUpdate; +/// Error codes +typedef enum _CusErrorCode +{ + ErrorGeneric, ///< Generic error + ErrorSetup, ///< Setup error + ErrorProbe, ///< Probe error + ErrorApplication, ///< Application load error + ErrorSwUpdate, ///< Software update error + ErrorGl, ///< GL error + ErrorRawData, ///< Raw data error + +} CusErrorCode; + /// Wireless optimization methods /// /// Available channels differ based on locale. @@ -337,6 +353,16 @@ typedef struct _CusTgc } CusTgc; +/// Acoustic index values to send to the API +typedef struct _CusAcoustic +{ + double mi; ///< mechanical index + double tib; ///< thermal index bone + double tic; ///< thermal index cranial + double tis; ///< thermal index soft tissue + +} CusAcoustic; + /// Status information typedef struct _CusStatusInfo { @@ -357,7 +383,9 @@ typedef struct _CusProbeSettings int autoFreeze; ///< The number of seconds to engage freezing imaging after no contact mode has been engaged, valid range is 0 - 120, where 0 turns the function off int keepAwake; ///< The number of minutes to power down the device once imaging has been frozen, valid range is 0 - 120, where 0 turns the function off int deepSleep; ///< The number of hours for probe to go into deep sleep, valid range is 0 - 96, where 0 disables deep sleep - int stationary; ///< The number of seconds to engage freezing imaging after being stationary for a specific time frame + int stationary; ///< The number of seconds to engage freezing imaging after being stationary for a specific time frame, valid range is 0 - 120, where 0 turns the function off + int powerFan; ///< Flag for the ability to use the power fan + int autoBoot; ///< Auto boot probe when it comes out of deep sleep int wifiOptimization; ///< Flag allowing the probe to automatically freeze when poor wifi connectivity is detected int wifiSearch; ///< Flag to force the probe to scan the networks and choose the appropriate channel before bringing up its Wi-Fi int htWifi; ///< Flag to enable 40 MHz bands for the probe's Wi-Fi network @@ -366,6 +394,9 @@ typedef struct _CusProbeSettings int sounds; ///< Flag allowing the probe to make beeping sounds int wakeOnShake; ///< Flag allowing the probe to start imaging when it is picked up while frozen int bandwidthOptimization; ///< Flag allowing the system to adjust bandwidth parameters automatically when lag or dropped frames are determined + int forceLogSend; ///< Flag allowing the probe to send logs while imaging + int imageOnUndock; ///< Start imaging when probe comes out of charging dock + int alarmOnUndock; ///< Sound an alarm when probe comes out of charging dock CusButtonSetting up; ///< Button up setting CusButtonSetting down; ///< Button down setting CusButtonSetting handle; ///< Button handle setting diff --git a/include/solum/solum_export.h b/include/solum/solum_export.h index 9fcc8dc..dba8175 100644 --- a/include/solum/solum_export.h +++ b/include/solum/solum_export.h @@ -9,30 +9,34 @@ # ifndef SOLUM_EXPORT # ifdef solum_EXPORTS /* We are building this library */ -# ifdef _MSC_VER +# if defined(_WIN32) # define SOLUM_EXPORT __declspec(dllexport) -# else +# elif defined(__APPLE__) # define SOLUM_EXPORT __attribute__((visibility("default"))) # endif # else /* We are using this library */ -# ifdef _MSC_VER +# if defined(_WIN32) # define SOLUM_EXPORT __declspec(dllimport) -# else +# elif defined(__APPLE__) # define SOLUM_EXPORT __attribute__((visibility("default"))) # endif # endif # endif # ifndef SOLUM_NO_EXPORT -# define SOLUM_NO_EXPORT __attribute__((visibility("hidden"))) +# if defined(_WIN32) +# define SOLUM_NO_EXPORT +# elif defined(__APPLE__) +# define SOLUM_NO_EXPORT __attribute__((visibility("hidden"))) +# endif # endif #endif #ifndef SOLUM_DEPRECATED -# ifdef _MSC_VER +# if defined(_WIN32) # define SOLUM_DEPRECATED __declspec(deprecated) -# else +# elif defined(__APPLE__) # define SOLUM_DEPRECATED __attribute__ ((__deprecated__)) # endif #endif @@ -45,6 +49,7 @@ # define SOLUM_DEPRECATED_NO_EXPORT SOLUM_NO_EXPORT SOLUM_DEPRECATED #endif +/* NOLINTNEXTLINE(readability-avoid-unconditional-preprocessor-if) */ #if 0 /* DEFINE_NO_DEPRECATED */ # ifndef SOLUM_NO_DEPRECATED # define SOLUM_NO_DEPRECATED diff --git a/include/solum/solum_export_12.0.2_macos.arm64.h b/include/solum/solum_export_12.0.2_macos.arm64.h new file mode 100644 index 0000000..269b2d1 --- /dev/null +++ b/include/solum/solum_export_12.0.2_macos.arm64.h @@ -0,0 +1,43 @@ + +#ifndef SOLUM_EXPORT_H +#define SOLUM_EXPORT_H + +#ifdef SOLUM_STATIC_DEFINE +# define SOLUM_EXPORT +# define SOLUM_NO_EXPORT +#else +# ifndef SOLUM_EXPORT +# ifdef solum_EXPORTS + /* We are building this library */ +# define SOLUM_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define SOLUM_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef SOLUM_NO_EXPORT +# define SOLUM_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef SOLUM_DEPRECATED +# define SOLUM_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef SOLUM_DEPRECATED_EXPORT +# define SOLUM_DEPRECATED_EXPORT SOLUM_EXPORT SOLUM_DEPRECATED +#endif + +#ifndef SOLUM_DEPRECATED_NO_EXPORT +# define SOLUM_DEPRECATED_NO_EXPORT SOLUM_NO_EXPORT SOLUM_DEPRECATED +#endif + +/* NOLINTNEXTLINE(readability-avoid-unconditional-preprocessor-if) */ +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef SOLUM_NO_DEPRECATED +# define SOLUM_NO_DEPRECATED +# endif +#endif + +#endif /* SOLUM_EXPORT_H */ diff --git a/include/solum/solum_export_winX64_12.0.2.h b/include/solum/solum_export_winX64_12.0.2.h new file mode 100644 index 0000000..bd2eb16 --- /dev/null +++ b/include/solum/solum_export_winX64_12.0.2.h @@ -0,0 +1,43 @@ + +#ifndef SOLUM_EXPORT_H +#define SOLUM_EXPORT_H + +#ifdef SOLUM_STATIC_DEFINE +# define SOLUM_EXPORT +# define SOLUM_NO_EXPORT +#else +# ifndef SOLUM_EXPORT +# ifdef solum_EXPORTS + /* We are building this library */ +# define SOLUM_EXPORT __declspec(dllexport) +# else + /* We are using this library */ +# define SOLUM_EXPORT __declspec(dllimport) +# endif +# endif + +# ifndef SOLUM_NO_EXPORT +# define SOLUM_NO_EXPORT +# endif +#endif + +#ifndef SOLUM_DEPRECATED +# define SOLUM_DEPRECATED __declspec(deprecated) +#endif + +#ifndef SOLUM_DEPRECATED_EXPORT +# define SOLUM_DEPRECATED_EXPORT SOLUM_EXPORT SOLUM_DEPRECATED +#endif + +#ifndef SOLUM_DEPRECATED_NO_EXPORT +# define SOLUM_DEPRECATED_NO_EXPORT SOLUM_NO_EXPORT SOLUM_DEPRECATED +#endif + +/* NOLINTNEXTLINE(readability-avoid-unconditional-preprocessor-if) */ +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef SOLUM_NO_DEPRECATED +# define SOLUM_NO_DEPRECATED +# endif +#endif + +#endif /* SOLUM_EXPORT_H */ diff --git a/lib/libsolum.dylib b/lib/libsolum.dylib new file mode 100755 index 0000000..2086aab Binary files /dev/null and b/lib/libsolum.dylib differ diff --git a/lib/solum.dll b/lib/solum.dll new file mode 100644 index 0000000..36a29e3 Binary files /dev/null and b/lib/solum.dll differ diff --git a/lib/solum.lib b/lib/solum.lib new file mode 100644 index 0000000..16e25f3 Binary files /dev/null and b/lib/solum.lib differ diff --git a/openigtlink/igtlConfigure.h b/openigtlink/igtlConfigure.h new file mode 100644 index 0000000..780a5fb --- /dev/null +++ b/openigtlink/igtlConfigure.h @@ -0,0 +1,45 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $HeadURL: http://svn.na-mic.org/NAMICSandBox/trunk/OpenIGTLink/igtlConfigure.h.in $ + Language: C + Date: $Date: 2010-06-09 16:16:36 -0400 (Wed, 09 Jun 2010) $ + Version: $Revision: 6525 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_CONFIGURE_H +#define __IGTL_CONFIGURE_H + +#ifdef _WIN32 + #define OpenIGTLink_PLATFORM_WIN32 + #define OpenIGTLink_USE_WIN32_THREADS + #define IGTLCommon_EXPORTS +#endif + +/* #undef OpenIGTLink_USE_SPROC */ +/* #undef OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T */ +#define OpenIGTLink_HAVE_STRNLEN +/* #undef OpenIGTLink_USE_H264 */ +/* #undef OpenIGTLink_USE_VP9 */ +/* #undef OpenIGTLink_USE_X265 */ +/* #undef OpenIGTLink_USE_OpenHEVC */ +/* #undef OpenIGTLink_USE_AV1 */ +/* #undef OpenIGTLink_USE_WEBSOCKET */ +/* #undef OpenIGTLink_ENABLE_VIDEOSTREAMING */ + +#define OpenIGTLink_PROTOCOL_VERSION_1 1 +#define OpenIGTLink_PROTOCOL_VERSION_2 2 +#define OpenIGTLink_PROTOCOL_VERSION_3 3 +#define OpenIGTLink_PROTOCOL_VERSION 3 +#define OpenIGTLink_HEADER_VERSION 2 +#endif /*__IGTL_CONFIGURE_H*/ + + + diff --git a/openigtlink/igtlTypeConfig.h b/openigtlink/igtlTypeConfig.h new file mode 100644 index 0000000..a085d36 --- /dev/null +++ b/openigtlink/igtlTypeConfig.h @@ -0,0 +1,77 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TYPECONFIG_H +#define __IGTL_TYPECONFIG_H + +#define CMAKE_SIZEOF_CHAR +#ifdef CMAKE_SIZEOF_CHAR + #define IGTL_SIZEOF_CHAR 1 +#endif + +#define CMAKE_SIZEOF_INT +#ifdef CMAKE_SIZEOF_INT + #define IGTL_SIZEOF_INT 4 +#endif + +#define CMAKE_SIZEOF_SHORT +#ifdef CMAKE_SIZEOF_SHORT + #define IGTL_SIZEOF_SHORT 2 +#endif + +#define CMAKE_SIZEOF_LONG +#ifdef CMAKE_SIZEOF_LONG + #define IGTL_SIZEOF_LONG 4 +#endif + +#define CMAKE_SIZEOF_FLOAT +#ifdef CMAKE_SIZEOF_FLOAT + #define IGTL_SIZEOF_FLOAT 4 +#endif + +#define CMAKE_SIZEOF_DOUBLE +#ifdef CMAKE_SIZEOF_DOUBLE + #define IGTL_SIZEOF_DOUBLE 8 +#endif + +#define CMAKE_SIZEOF_LONG_LONG +#define CMAKE_SIZEOF___INT64 +#define CMAKE_SIZEOF_INT64_T +#ifdef CMAKE_SIZEOF_LONG_LONG + #define IGTL_TYPE_USE_LONG_LONG 1 + #define IGTL_SIZEOF_LONG_LONG 8 +#elif defined(CMAKE_SIZEOF___INT64) + #define IGTL_TYPE_USE___INT64 1 + #define IGTL_SIZEOF___INT64 8 +#elif defined(CMAKE_SIZEOF_INT64_T) + #define IGTL_TYPE_USE_INT64_T 1 + #define IGTL_SIZEOF_INT64_T 8 +#endif + +#define CMAKE_SIZEOF_VOID_P + +#define OpenIGTLink_PLATFORM_WIN32 +#ifdef OpenIGTLink_PLATFORM_WIN32 + #ifndef _WIN32 + #define _WIN32 + #endif + #ifndef WIN32 + #define WIN32 + #endif + #define IGTLCommon_EXPORTS +#endif + +#endif /*__IGTL_TYPECONFIG_H*/ + + + diff --git a/openigtlink/igtl_typeconfig.h b/openigtlink/igtl_typeconfig.h new file mode 100644 index 0000000..1415439 --- /dev/null +++ b/openigtlink/igtl_typeconfig.h @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TYPECONFIG_H +#define __IGTL_TYPECONFIG_H + +#define CMAKE_SIZEOF_CHAR +#ifdef CMAKE_SIZEOF_CHAR + #define IGTL_SIZEOF_CHAR 1 +#endif + +#define CMAKE_SIZEOF_INT +#ifdef CMAKE_SIZEOF_INT + #define IGTL_SIZEOF_INT 4 +#endif + +#define CMAKE_SIZEOF_SHORT +#ifdef CMAKE_SIZEOF_SHORT + #define IGTL_SIZEOF_SHORT 2 +#endif + +#define CMAKE_SIZEOF_LONG +#ifdef CMAKE_SIZEOF_LONG + #define IGTL_SIZEOF_LONG 4 +#endif + +#define CMAKE_SIZEOF_FLOAT +#ifdef CMAKE_SIZEOF_FLOAT + #define IGTL_SIZEOF_FLOAT 4 +#endif + +#define CMAKE_SIZEOF_DOUBLE +#ifdef CMAKE_SIZEOF_DOUBLE + #define IGTL_SIZEOF_DOUBLE 8 +#endif + +#define CMAKE_SIZEOF_LONG_LONG +#define CMAKE_SIZEOF___INT64 +#define CMAKE_SIZEOF_INT64_T +#ifdef CMAKE_SIZEOF_LONG_LONG + #define IGTL_TYPE_USE_LONG_LONG 1 + #define IGTL_SIZEOF_LONG_LONG 8 +#elif defined(CMAKE_SIZEOF___INT64) + #define IGTL_TYPE_USE___INT64 1 + #define IGTL_SIZEOF___INT64 8 +#elif defined(CMAKE_SIZEOF_INT64_T) + #define IGTL_TYPE_USE_INT64_T 1 + #define IGTL_SIZEOF_INT64_T 8 +#endif + +#define CMAKE_SIZEOF_VOID_P + +#define OpenIGTLink_PLATFORM_WIN32 +#ifdef OpenIGTLink_PLATFORM_WIN32 + #ifndef _WIN32 + #define _WIN32 + #endif + #ifndef WIN32 + #define WIN32 + #endif + #define IGTLCommon_EXPORTS +#endif + +#endif /*__IGTL_TYPECONFIG_H*/ diff --git a/openigtlink/openigtlink.pri b/openigtlink/openigtlink.pri new file mode 100644 index 0000000..1633325 --- /dev/null +++ b/openigtlink/openigtlink.pri @@ -0,0 +1,26 @@ +INCLUDEPATH += \ + $$PWD/ \ + $$PWD/repo/Source/ \ + $$PWD/repo/Source/igtlutil/ \ + +# Consuming the library +!equals(TARGET, openigtlink) { + DEPENDPATH += $$PWD + LIBS += -lopenigtlink + + win32: LIBS += -lws2_32 + + # This mess is what Qt Creator auto-generates when adding an internal + # library to a project. This is the only remaining possible way to reliably + # do this; the `link_prl` CONFIG option that is supposed to automate this + # requires just as much manual configuration for correctly pointing to the + # Debug and Release directories in Visual Studio builds. + win32:CONFIG(release, debug|release): LIBS += -L$$PWD/release/ + else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/debug/ + else:unix: LIBS += -L$$PWD/ + win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/release/libopenigtlink.a + else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/debug/libopenigtlink.a + else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/release/openigtlink.lib + else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/debug/openigtlink.lib + else:unix: PRE_TARGETDEPS += $$PWD/libopenigtlink.a +} diff --git a/openigtlink/openigtlink.pro b/openigtlink/openigtlink.pro new file mode 100644 index 0000000..07e6ead --- /dev/null +++ b/openigtlink/openigtlink.pro @@ -0,0 +1,74 @@ +TEMPLATE = lib +CONFIG += c++20 staticlib warn_off +CONFIG -= qt +CONFIG(release, debug|release): CONFIG += ltcg + +include(openigtlink.pri) + +# Needs to be kept in sync with all file lists in repo/Source/CMakeLists.txt. +SOURCES += \ + repo/Source/igtlBindMessage.cxx \ + repo/Source/igtlCapabilityMessage.cxx \ + repo/Source/igtlClientSocket.cxx \ + repo/Source/igtlColorTableMessage.cxx \ + repo/Source/igtlCommandMessage.cxx \ + repo/Source/igtlConditionVariable.cxx \ + repo/Source/igtlFastMutexLock.cxx \ + repo/Source/igtlGeneralSocket.cxx \ + repo/Source/igtlImageMessage.cxx \ + repo/Source/igtlImageMessage2.cxx \ + repo/Source/igtlImageMetaMessage.cxx \ + repo/Source/igtlLabelMetaMessage.cxx \ + repo/Source/igtlLightObject.cxx \ + repo/Source/igtlMath.cxx \ + repo/Source/igtlMessageBase.cxx \ + repo/Source/igtlMessageFactory.cxx \ + repo/Source/igtlMessageRTPWrapper.cxx \ + repo/Source/igtlMultiThreader.cxx \ + repo/Source/igtlMutexLock.cxx \ + repo/Source/igtlNDArrayMessage.cxx \ + repo/Source/igtlObject.cxx \ + repo/Source/igtlObjectFactoryBase.cxx \ + repo/Source/igtlOSUtil.cxx \ + repo/Source/igtlPointMessage.cxx \ + repo/Source/igtlPolyDataMessage.cxx \ + repo/Source/igtlPositionMessage.cxx \ + repo/Source/igtlQuaternionTrackingDataMessage.cxx \ + repo/Source/igtlQueryMessage.cxx \ + repo/Source/igtlSensorMessage.cxx \ + repo/Source/igtlServerSocket.cxx \ + repo/Source/igtlSessionManager.cxx \ + repo/Source/igtlSimpleFastMutexLock.cxx \ + repo/Source/igtlSocket.cxx \ + repo/Source/igtlStatusMessage.cxx \ + repo/Source/igtlStringMessage.cxx \ + repo/Source/igtlTimeStamp.cxx \ + repo/Source/igtlTrackingDataMessage.cxx \ + repo/Source/igtlTrajectoryMessage.cxx \ + repo/Source/igtlTransformMessage.cxx \ + repo/Source/igtlUDPClientSocket.cxx \ + repo/Source/igtlUDPServerSocket.cxx \ + repo/Source/igtlUnit.cxx \ + repo/Source/igtlutil/igtl_bind.c \ + repo/Source/igtlutil/igtl_capability.c \ + repo/Source/igtlutil/igtl_colortable.c \ + repo/Source/igtlutil/igtl_command.c \ + repo/Source/igtlutil/igtl_header.c \ + repo/Source/igtlutil/igtl_image.c \ + repo/Source/igtlutil/igtl_imgmeta.c \ + repo/Source/igtlutil/igtl_lbmeta.c \ + repo/Source/igtlutil/igtl_ndarray.c \ + repo/Source/igtlutil/igtl_point.c \ + repo/Source/igtlutil/igtl_polydata.c \ + repo/Source/igtlutil/igtl_position.c \ + repo/Source/igtlutil/igtl_qtdata.c \ + repo/Source/igtlutil/igtl_qtrans.c \ + repo/Source/igtlutil/igtl_query.c \ + repo/Source/igtlutil/igtl_sensor.c \ + repo/Source/igtlutil/igtl_status.c \ + repo/Source/igtlutil/igtl_string.c \ + repo/Source/igtlutil/igtl_tdata.c \ + repo/Source/igtlutil/igtl_trajectory.c \ + repo/Source/igtlutil/igtl_transform.c \ + repo/Source/igtlutil/igtl_unit.c \ + repo/Source/igtlutil/igtl_util.c \ diff --git a/openigtlink/repo/.gitattributes b/openigtlink/repo/.gitattributes new file mode 100644 index 0000000..1b08709 --- /dev/null +++ b/openigtlink/repo/.gitattributes @@ -0,0 +1,17 @@ +.git* export-ignore +.hooks* export-ignore + +*.sh crlf=input +newalpha crlf=input +newversion crlf=input +pre-commit crlf=input + +*.c whitespace=tab-in-indent +*.h whitespace=tab-in-indent +*.cxx whitespace=tab-in-indent +*.hxx whitespace=tab-in-indent +*.txx whitespace=tab-in-indent +*.txt whitespace=tab-in-indent +*.cmake whitespace=tab-in-indent + +*.md whitespace=tab-in-indent conflict-marker-size=30 diff --git a/openigtlink/repo/.github/workflows/cmake.yml b/openigtlink/repo/.github/workflows/cmake.yml new file mode 100644 index 0000000..b8b9feb --- /dev/null +++ b/openigtlink/repo/.github/workflows/cmake.yml @@ -0,0 +1,73 @@ +name: CMake + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally + # well on Windows or Mac. You can convert this to a matrix build if you need + # cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04, ubuntu-22.04, macos-latest] + + steps: + - uses: actions/checkout@v2 + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DOpenIGTLink_PROTOCOL_VERSION_3=ON -DOpenIGTLink_SUPERBUILD=OFF -DOpenIGTLink_USE_VP9=ON -DBUILD_TESTING=ON + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} + ######################### + # Test for version2 build + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DOpenIGTLink_PROTOCOL_VERSION_3=OFF -DOpenIGTLink_SUPERBUILD=OFF -DOpenIGTLink_USE_VP9=OFF -DBUILD_TESTING=ON + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} + + ######################### + # Test for super build + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/SuperBuildTest -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DOpenIGTLink_PROTOCOL_VERSION_3=ON -DOpenIGTLink_SUPERBUILD=ON -DOpenIGTLink_USE_VP9=ON -DBUILD_TESTING=ON + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/SuperBuildTest --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{github.workspace}}/SuperBuildTest/OpenIGTLink-bin + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} diff --git a/openigtlink/repo/.gitrepo b/openigtlink/repo/.gitrepo new file mode 100644 index 0000000..0da6401 --- /dev/null +++ b/openigtlink/repo/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/ingydotnet/git-subrepo#readme +; +[subrepo] + remote = https://github.com/openigtlink/OpenIGTLink + branch = master + commit = c512727425c2b7a594fabb9cd1fbfac512bf376e + parent = 2d0901c16500ebe9fe208af805173ffc5cd50976 + method = merge + cmdver = 0.4.6 diff --git a/openigtlink/repo/.hooks-config.bash b/openigtlink/repo/.hooks-config.bash new file mode 100644 index 0000000..ebe56ea --- /dev/null +++ b/openigtlink/repo/.hooks-config.bash @@ -0,0 +1,6 @@ +# Loaded by .git/hooks/(pre-commit|commit-msg|prepare-commit-msg) +# during git commit after local hooks have been installed. + +hooks_chain_pre_commit="Utilities/Scripts/pre-commit" +hooks_chain_commit_msg="Utilities/Scripts/commit-msg" +hooks_chain_prepare_commit_msg="Utilities/Scripts/prepare-commit-msg" \ No newline at end of file diff --git a/openigtlink/repo/.travis.yml b/openigtlink/repo/.travis.yml new file mode 100644 index 0000000..83bcfe8 --- /dev/null +++ b/openigtlink/repo/.travis.yml @@ -0,0 +1,59 @@ +os: + - linux + - osx + +language: cpp + +compiler: + - gcc + - clang + + +install: + ############################################################################ + # Install a recent CMake (unless already installed on OS X) + ############################################################################ + - | + if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then + DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" + mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR} + CMAKE_URL="http://www.cmake.org/files/v3.5/cmake-3.5.2-Linux-x86_64.tar.gz" + mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake + export PATH=${DEPS_DIR}/cmake/bin:${PATH} + cd .. + else + if ! brew ls --version cmake &>/dev/null; then brew install cmake; fi + fi + - | + if [ "${TRAVIS_OS_NAME}" == "linux" ] ; then + sudo apt-get -y install yasm; + fi + if [ "${TRAVIS_OS_NAME}" == "osx" ]; then + brew update; + brew install yasm; + fi + +before_script: + - mkdir build + - cd build + +script: + - cmake -DOpenIGTLink_PROTOCOL_VERSION_3=ON -DOpenIGTLink_SUPERBUILD=OFF -DOpenIGTLink_USE_VP9=ON -DBUILD_TESTING=ON .. + - make + - make test + ######################### + # Test for version2 build + - cmake -DOpenIGTLink_PROTOCOL_VERSION_3=OFF -DOpenIGTLink_SUPERBUILD=OFF -DOpenIGTLink_USE_VP9=OFF -DBUILD_TESTING=ON .. + - make + - make test + ######################### + # Test for Super build + - cd .. + - mkdir SuperBuildTest + - cd SuperBuildTest + - cmake -DOpenIGTLink_PROTOCOL_VERSION_3=ON -DOpenIGTLink_SUPERBUILD=ON -DOpenIGTLink_USE_VP9=ON -DBUILD_TESTING=ON .. + - make + - cd OpenIGTLink-bin + - make test + + diff --git a/openigtlink/repo/BUILD.md b/openigtlink/repo/BUILD.md new file mode 100644 index 0000000..7136efa --- /dev/null +++ b/openigtlink/repo/BUILD.md @@ -0,0 +1,137 @@ +The OpenIGTLink Library Build Instruction +========================================= + +Linux / Mac OS X +---------------- + +First, obtain the source code from the repository using Git. To simply download +the code, run the following command from a terminal: + +~~~~ +$ git clone https://github.com/openigtlink/OpenIGTLink.git +~~~~ + +Then configure using CMake. The library requires CMake version higher than 2.4. + +~~~~ +$ mkdir OpenIGTLink-build +$ cd OpenIGTLink-build +$ cmake -DBUILD_EXAMPLES:BOOL=ON ../OpenIGTLink +$ make +~~~~ + +You may install the library into your disk (optional). The default target +directory is /usr/local, but you can configure it from the CMake configuration +screen. To install the files, run + +~~~~ +$ make install +~~~~ + +You might need super user access. + +Windows +------- +* Download the source code from Git repository. +* URL of repository: git://github.com/openigtlink/OpenIGTLink.git +* Run CMake +* Where is the source code: C:\Devel\OpenIGT\OpenIGTLink +* Where to build the binaries: C:\Devel\OpenIGT\OpenIGTLink-build +* Click "Configure" and select your compiler (usually just click "OK") +* Message: "Build directory does not exit, should I create it?" - click "OK" +* Click "Configure" +* Click "OK" to close CMake +* Start Visual C and compile the project (C:\Devel\OpenIGT\OpenIGTLink-build\OpenIGTLink.sln) +If all went OK you will have the executable and the library: +* C:\Devel\OpenIGT\OpenIGTLink-build\bin\debug\igtlSocketTest.exe +* C:\Devel\OpenIGT\OpenIGTLink-build\bin\debug\OpenIGTLink.lib + +VideoStreaming +--------------- +You might want to use OpenIGTLink library to perform video streaming. Currently OpenH264, H265, VP9 and AV1 are supported in the OpenIGTLink. + +* Prerequisites + +In the case of H264 build, NASM is needed for assembly code: workable version 2.10.06 or above for 32 bit, nasm can downloaded from http://www.nasm.us/ +For Mac OSX 64-bit NASM needed to be below version 2.11.08 as nasm 2.11.08 +will introduce error when using RIP-relative addresses in Mac OSX 64-bit. If you have another NASM version installed, try to unlink the wrong version of NASM, +and link to the version to below 2.11.08. Afterwards, check the nasm version with comman "which nasm" and "nasm -v". + +In the case of VP9 build, The Yasm assembler is required to build optimized libraries for x86 platforms. +Version 0.8.0 or newer is required, except Version 1.0.0. + +In the case of H265 build, H265 have many implementations, the encoder used in library is x265 and the decoder is OpenHEVC. +OpenIGTLink library doesn't build H265 libraries, so the users need to download and compile the libraries by themselves. +Afterwards, set the variables-"X265_INCLUDE_DIR, X265_LIBRARY_DIR, OPENHEVC_INCLUDE_DIR, OpenHEVC_LIBRARY"-correctly in cmake configuration. + +In the case of AV1 build, the AV1 codec is cmakefied. Once the OpenIGTLink_USE_AV1 option is selected, the openigtlink libray will superbuild the codec and link automatically. +* Linux / Mac OS X + +In the case of Linux and Mac, after installing the required program in the Prerequisites section, +the build of openigtlink with codec is very straightforward: + +~~~~ +$ cmake -DBUILD_VIDEOSTREAM:BOOL=ON -DLINK_H264:BOOL=ON -DOpenIGTLink_PROTOCOL_VERSION_3:BOOL=ON ../OpenIGTLink +$ make +~~~~ + +or for VP9 configuration: + +~~~~ +$ cmake -DBUILD_VIDEOSTREAM:BOOL=ON -DOpenIGTLink_USE_VP9:BOOL=ON -DOpenIGTLink_PROTOCOL_VERSION_3:BOOL=ON ../OpenIGTLink +$ make +~~~~ + +* Windows Build + +In the case of windows build, please refer to the following websites for H264, X265 and VP9 respectively. +Useful H264 build instructions: + +https://github.com/cisco/openh264 + +Useful VP9 build instructions: + +https://www.webmproject.org/code/build-prerequisites/ +http://wiki.webmproject.org/ffmpeg/building-with-libvpx + +OpenIGTLink provides binary library files for visual studio 12 2013 and visual studio 14 2015. +The libray will be automatically downloaded during the project build when user configure OpenIGTLink library using these cmake generators: +"Visual Studio 12 2013", "Visual Studio 12 2013 Win64", "Visual Studio 14 2015" and "Visual Studio 14 2015 Win64". +For the rest cmake generators, the user need to provide the VP9_INCLUDE_DIR and VP9_BINARY_DIR, otherwize the video streaming feature will be deactivated. + +Useful X265 build intructions: + +https://bitbucket.org/multicoreware/x265/wiki/CrossCompile + +Useful OpenHEVC build intructions: + +http://openhevc.github.io/openHEVC/ + +WebSocket +--------------- +You might want to use OpenIGTLink library to perform websocket communication. + +* Prerequisites +This functionality is only tested for Mac OSX platform and Windows platform (VS 2015, boost version 1.62). The websocketpp project needs to be build and installed first, below is a build example for Mac OSX platform, Windows build uses CMAKE GUI for configuration. +~~~~ +$ git clone https://github.com/zaphoyd/websocketpp +$ mkdir websocketpp-build +$ cd websocketpp-build +$ cmake -DCMAKE_INSTALL_PREFIX=${path-to-your-installation} ../websocketpp +$ make & make install +~~~~ + +Then go to the build directory of the OpenIGTLink, run these commands: + +~~~~ +$ cmake -DOpenIGTLink_USE_WEBSOCKET=ON -DBUILD_EXAMPLES=ON -Dwebsocketpp_DIR:PATH=${path-to-your-installation}/lib/cmake/websocketpp ${your-openigtlink_source} +$ make +$ ./bin/WebSocketServer ${your-openigtlink_source}/Examples/WebSocket 9002 +~~~~ + +Open your browser and type: localhost:9002, there will be a connect button on the page, simply click it and you will see updating tracking data. + +Other Platforms +--------------- + +Please see [Build Instruction](http://openigtlink.org/library/build.html). diff --git a/openigtlink/repo/CMake/DartConfig.cmake b/openigtlink/repo/CMake/DartConfig.cmake new file mode 100644 index 0000000..db49d45 --- /dev/null +++ b/openigtlink/repo/CMake/DartConfig.cmake @@ -0,0 +1,55 @@ +# Dashboard is opened for submissions for a 24 hour period starting at +# the specified NIGHLY_START_TIME. Time is specified in 24 hour format. +SET (NIGHTLY_START_TIME "0:30:00 EDT") + +# USE HTTP for submittion + +IF(NOT DROP_METHOD) + SET(DROP_METHOD http) +ENDIF(NOT DROP_METHOD) + +# Dart server to submit results (used by client) +IF(DROP_METHOD MATCHES http) + SET (DROP_SITE "public.kitware.com") + SET (DROP_LOCATION "/cgi-bin/HTTPUploadDartFile.cgi") +ELSE(DROP_METHOD MATCHES http) + SET (DROP_SITE "public.kitware.com") + SET (DROP_LOCATION "/incoming") + SET (DROP_SITE_USER "ftpuser") + SET (DROP_SITE_PASSWORD "public") +ENDIF(DROP_METHOD MATCHES http) + +SET (TRIGGER_SITE + "http://${DROP_SITE}/cgi-bin/Submit-OpenIGTLink-TestingResults.pl") + +# Project Home Page +#SET (PROJECT_URL "http://${DROP_SITE}/IFSTK") + +# Dart server configuration +SET (ROLLUP_URL "http://${DROP_SITE}/cgi-bin/OpenIGTLink-rollup-dashboard.sh") +SET (CVS_WEB_URL "http://${DROP_SITE}/cgi-bin/viewcvs.cgi/") +SET (CVS_WEB_CVSROOT "OpenIGTLink") + +SET (USE_DOXYGEN "On") +SET (DOXYGEN_URL "http://public.kitware.com/OpenIGTLink/NightlyDoc/" ) + +SET (USE_GNATS "On") +SET (GNATS_WEB_URL "http://public.kitware.com/Bug/index.php") + +# Continuous email delivery variables +SET (CONTINUOUS_FROM "luis.ibanez@kitware.com") +SET (SMTP_MAILHOST "public.kitware.com") +SET (CONTINUOUS_MONITOR_LIST "luis.ibanez@kitware.com") +SET (CONTINUOUS_BASE_URL "http://public.kitware.com/OpenIGTLink") + +SET (DELIVER_BROKEN_BUILD_EMAIL_WITH_TEST_FAILURES ON) +SET (DELIVER_BROKEN_BUILD_EMAIL "Continuous Nightly") +SET (EMAIL_FROM "cmake-dashboard@public.kitware.com") +SET (DARTBOARD_BASE_URL "http://public.kitware.com/OpenIGTLink") + +SET (DELIVER_BROKEN_BUILD_EMAIL_WITH_CONFIGURE_FAILURES 1) +SET (DELIVER_BROKEN_BUILD_EMAIL_WITH_BUILD_ERRORS 1) +SET (DELIVER_BROKEN_BUILD_EMAIL_WITH_BUILD_WARNINGS 1) +SET (DELIVER_BROKEN_BUILD_EMAIL_WITH_TEST_NOT_RUNS 1) +SET (DELIVER_BROKEN_BUILD_EMAIL_WITH_TEST_FAILURES 1) + diff --git a/openigtlink/repo/CMake/GenerateOpenIGTLinkConfig.cmake b/openigtlink/repo/CMake/GenerateOpenIGTLinkConfig.cmake new file mode 100644 index 0000000..40e28ff --- /dev/null +++ b/openigtlink/repo/CMake/GenerateOpenIGTLinkConfig.cmake @@ -0,0 +1,89 @@ +# Generate the OpenIGTLinkConfig.cmake file in the build tree. Also configure +# one for installation. The file tells external projects how to use +# OpenIGTLink. + +#----------------------------------------------------------------------------- +# Settings specific to the build tree. + +# Generate CMake lines that will define the OpenIGTLink_SOURCE_DIR in the OpenIGTLinkConfig.cmake. +# We want this to happen only in the OpenIGTLinkConfig.cmake of the build dir, not in the +# installed or relocatable one. +SET(OpenIGTLink_CONFIG_CODE " +# The OpenIGTLink source tree. +# For backward compatibility issues we still need to define this variable, although +# it is highly probable that it will cause more harm than being useful. +# Use OpenIGTLink_INCLUDE_DIRS instead, since OpenIGTLink_SOURCE_DIR may point to non-existent directory +IF(NOT OpenIGTLink_LEGACY_REMOVE) + SET(OpenIGTLink_SOURCE_DIR \"${OpenIGTLink_SOURCE_DIR}\") +ENDIF(NOT OpenIGTLink_LEGACY_REMOVE)" +) + +# The "use" file. +SET(OpenIGTLink_USE_FILE ${OpenIGTLink_BINARY_DIR}/UseOpenIGTLink.cmake) + +# The build settings file. +SET(OpenIGTLink_BUILD_SETTINGS_FILE ${OpenIGTLink_BINARY_DIR}/OpenIGTLinkBuildSettings.cmake) + +# Library directory. +SET(OpenIGTLink_LIBRARY_DIRS_CONFIG ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) + +# Determine the include directories needed. +SET(OpenIGTLink_INCLUDE_DIRS_CONFIG + ${OpenIGTLink_INCLUDE_DIRS} +) + +#----------------------------------------------------------------------------- +# Configure OpenIGTLinkConfig.cmake for the build tree. +CONFIGURE_FILE(${OpenIGTLink_SOURCE_DIR}/OpenIGTLinkConfig.cmake.in + ${OpenIGTLink_BINARY_DIR}/OpenIGTLinkConfig.cmake @ONLY IMMEDIATE) + +#----------------------------------------------------------------------------- +# Settings specific to the install tree. + +# store old OpenIGTLink_LIBRARY_TARGETS_FILE +SET(OpenIGTLink_LIBRARY_TARGETS_FILE_BUILDTREE ${OpenIGTLink_LIBRARY_TARGETS_FILE}) + +# The library dependencies file. +SET(OpenIGTLink_LIBRARY_TARGETS_FILE "\${OpenIGTLink_INSTALL_PREFIX}/${OpenIGTLink_INSTALL_PACKAGE_DIR}/OpenIGTLinkTargets.cmake") + +# The "use" file. +SET(OpenIGTLink_USE_FILE \${OpenIGTLink_INSTALL_PREFIX}/${OpenIGTLink_INSTALL_PACKAGE_DIR}/UseOpenIGTLink.cmake) + +# The build settings file. +SET(OpenIGTLink_BUILD_SETTINGS_FILE \${OpenIGTLink_INSTALL_PREFIX}/${OpenIGTLink_INSTALL_PACKAGE_DIR}/OpenIGTLinkBuildSettings.cmake) + +# Include directories. +SET(OpenIGTLink_INCLUDE_DIRS_CONFIG \${OpenIGTLink_INSTALL_PREFIX}/${OpenIGTLink_INSTALL_INCLUDE_DIR}) +FOREACH(DIR ${OpenIGTLink_INCLUDE_RELATIVE_DIRS}) + LIST(APPEND OpenIGTLink_INCLUDE_DIRS_CONFIG \${OpenIGTLink_INSTALL_PREFIX}/${OpenIGTLink_INSTALL_INCLUDE_DIR}/${DIR}) +ENDFOREACH(DIR) +IF(OpenIGTLink_INCLUDE_DIRS_SYSTEM) + LIST(APPEND OpenIGTLink_INCLUDE_DIRS_CONFIG ${OpenIGTLink_INCLUDE_DIRS_SYSTEM}) +ENDIF() + +# Link directories. +SET(OpenIGTLink_LIBRARY_DIRS_CONFIG "\${OpenIGTLink_INSTALL_PREFIX}/${OpenIGTLink_INSTALL_LIB_DIR}") + +#----------------------------------------------------------------------------- +# Configure OpenIGTLinkConfig.cmake for the install tree. + +# Construct the proper number of GET_FILENAME_COMPONENT(... PATH) +# calls to compute the installation prefix. +STRING(REGEX REPLACE "/" ";" OpenIGTLink_INSTALL_PACKAGE_DIR_COUNT + "${OpenIGTLink_INSTALL_PACKAGE_DIR}") +SET(OpenIGTLink_CONFIG_CODE " +# Compute the installation prefix from this OpenIGTLinkConfig.cmake file location. +GET_FILENAME_COMPONENT(OpenIGTLink_INSTALL_PREFIX \"\${CMAKE_CURRENT_LIST_FILE}\" PATH)") +FOREACH(p ${OpenIGTLink_INSTALL_PACKAGE_DIR_COUNT}) + SET(OpenIGTLink_CONFIG_CODE + "${OpenIGTLink_CONFIG_CODE}\nGET_FILENAME_COMPONENT(OpenIGTLink_INSTALL_PREFIX \"\${OpenIGTLink_INSTALL_PREFIX}\" PATH)" + ) +ENDFOREACH(p) + + +CONFIGURE_FILE(${OpenIGTLink_SOURCE_DIR}/OpenIGTLinkConfig.cmake.in + ${OpenIGTLink_BINARY_DIR}/Utilities/OpenIGTLinkConfig.cmake @ONLY IMMEDIATE) + +# restore old OpenIGTLink_LIBRARY_TARGETS_FILE +SET(OpenIGTLink_LIBRARY_TARGETS_FILE ${OpenIGTLink_LIBRARY_TARGETS_FILE_BUILDTREE}) + diff --git a/openigtlink/repo/CMake/OpenIGTLinkCMakeTests.cmake b/openigtlink/repo/CMake/OpenIGTLinkCMakeTests.cmake new file mode 100644 index 0000000..9def7c6 --- /dev/null +++ b/openigtlink/repo/CMake/OpenIGTLinkCMakeTests.cmake @@ -0,0 +1,51 @@ +# See if we need to link the socket library +INCLUDE(CheckLibraryExists) +INCLUDE(CheckSymbolExists) +INCLUDE(CheckFunctionExists) + +CHECK_LIBRARY_EXISTS("socket" getsockname "" OpenIGTLink_HAVE_LIBSOCKET) +IF( NOT OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T ) + IF(OpenIGTLink_HAVE_LIBSOCKET) + SET(OpenIGTLink_GETSOCKNAME_LIBS "socket") + ELSE() + SET(OpenIGTLink_GETSOCKNAME_LIBS) + ENDIF() + + MESSAGE(STATUS "Checking for getsockname with socklen_t") + TRY_COMPILE(OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T + ${OpenIGTLink_BINARY_DIR}/CMakeTmp/SocklenT + ${OpenIGTLink_CMAKE_DIR}/igtlTestSocklenT.cxx + CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=${OpenIGTLink_GETSOCKNAME_LIBS}" + OUTPUT_VARIABLE OUTPUT) + + IF(OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T) + MESSAGE(STATUS "Checking for getsockname with socklen_t -- yes") + SET(OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T 1 CACHE INTERNAL "Support for getsockname with socklen_t") + WRITE_FILE(${OpenIGTLink_BINARY_DIR}/CMakeFiles/CMakeOutput.log + "Determining if getsockname accepts socklen_t type " + "passed with the following output:\n" + "${OUTPUT}\n" APPEND) + ELSE() + MESSAGE(STATUS "Checking for getsockname with socklen_t -- no") + SET(OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T 0 CACHE INTERNAL "Support for getsockname with socklen_t") + WRITE_FILE(${OpenIGTLink_BINARY_DIR}/CMakeFiles/CMakeError.log + "Determining if getsockname accepts socklen_t type " + "failed with the following output:\n" + "${OUTPUT}\n" APPEND) + ENDIF() +ENDIF() + +# e.g. Mac OS X Snow Leopard does not have strnlen(). +CHECK_FUNCTION_EXISTS(strnlen OpenIGTLink_HAVE_STRNLEN) + +# e.g. IBM BlueGene/L doesn't have SO_REUSEADDR, because "setsockopt is not needed for +# BlueGene/L applications" according to the BlueGene/L Application Development handbook +CHECK_SYMBOL_EXISTS(SO_REUSEADDR "sys/types.h;sys/socket.h" OpenIGTLink_HAVE_SO_REUSEADDR) + +SET(HAVE_SOCKETS TRUE) +# Cray Xt3/ Catamount doesn't have any socket support +# this could also be determined by doing something like +# check_symbol_exists(socket "sys/types.h;sys/socket.h" HAVE_SOCKETS) +IF(CMAKE_SYSTEM MATCHES Catamount) + SET(HAVE_SOCKETS FALSE) +ENDIF(CMAKE_SYSTEM MATCHES Catamount) \ No newline at end of file diff --git a/openigtlink/repo/CMake/OpenIGTLinkConfigPlatform.cmake b/openigtlink/repo/CMake/OpenIGTLinkConfigPlatform.cmake new file mode 100644 index 0000000..d39c058 --- /dev/null +++ b/openigtlink/repo/CMake/OpenIGTLinkConfigPlatform.cmake @@ -0,0 +1,116 @@ +#----------------------------------------------------------------------------- +# Check platform and generate igtlConfigure.h +#----------------------------------------------------------------------------- + +# +# The platform is determined by CMAKE_SYSTEM_NAME variable. +# CMake set CMAKE_SYSTEM_NAME based on "uname -s" on unix or just set "Windows" +# on windows. +# The list of "uname -s" is available in CMake/Modules/CMakeDetermineSystem.cmake +# + + +# Thread parameters +STRING(FIND ${CMAKE_SYSTEM_NAME} "Windows" _win_string_pos) +# Use pthread in default except Windows +if(NOT _win_string_pos EQUAL -1) + SET(OpenIGTLink_USE_WIN32_THREADS 1) +else() + SET(OpenIGTLink_USE_PTHREADS 1) +endif() + +# Windows +if(NOT _win_string_pos EQUAL -1) + SET(OpenIGTLink_PLATFORM_WIN32 1) +endif() + +# Mac OS X +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + SET(OpenIGTLink_PLATFORM_MACOSX 1) +endif() + +# Linux +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + SET(OpenIGTLink_PLATFORM_LINUX 1) +endif() + +# Sun OS +if(CMAKE_SYSTEM_NAME MATCHES "SunOS") +# SET(OpenIGTLink_USE_SPROC 1) + SET(OpenIGTLink_PLATFORM_SUNOS 1) + # Set OpenIGTLink_STD_LINK_LIBRARIES + + SET(OpenIGTLink_STD_LINK_LIBRARIES + ${OpenIGTLink_STD_LINK_LIBRARIES} + rt + nsl + socket + ) + IF(CMAKE_COMPILER_IS_GNUCXX) + SET(OpenIGTLink_STD_LINK_LIBRARIES + ${OpenIGTLink_STD_LINK_LIBRARIES} + stdc++ + ) + ELSE(CMAKE_COMPILER_IS_GNUCXX) + #FIND_LIBRARY(OpenIGTLink_SUNCC_CSTD_LIBRARY Cstd /opt/SUNWspro/lib) + #IF(OpenIGTLink_SUNCC_CSTD_LIBRARY) + # SET(OpenIGTLink_STD_LINK_LIBRARIES + # ${OpenIGTLink_STD_LINK_LIBRARIES} + # Cstd + # ) + #ENDIF(OpenIGTLink_SUNCC_CSTD_LIBRARY) + #FIND_LIBRARY(OpenIGTLink_SUNCC_CRUN_LIBRARY Crun /opt/SUNWspro/lib) + #IF(OpenIGTLink_SUNCC_CRUN_LIBRARY) + # SET(OpenIGTLink_STD_LINK_LIBRARIES + # ${OpenIGTLink_STD_LINK_LIBRARIES} + # Crun + # ) + #ENDIF(OpenIGTLink_SUNCC_CRUN_LIBRARY) + ENDIF(CMAKE_COMPILER_IS_GNUCXX) +endif(CMAKE_SYSTEM_NAME MATCHES "SunOS") + +# QNX +if(CMAKE_SYSTEM_NAME STREQUAL "QNX") + SET(OpenIGTLink_PLATFORM_QNX 1) +endif() + + +#----------------------------------------------------------------------------- +# Type Check +# + +include(CheckTypeSize) +check_type_size(int CMAKE_SIZEOF_INT) +check_type_size(long CMAKE_SIZEOF_LONG) +check_type_size("void*" CMAKE_SIZEOF_VOID_P) +check_type_size(char CMAKE_SIZEOF_CHAR) +check_type_size(short CMAKE_SIZEOF_SHORT) +check_type_size(float CMAKE_SIZEOF_FLOAT) +check_type_size(double CMAKE_SIZEOF_DOUBLE) +check_type_size("long long" CMAKE_SIZEOF_LONG_LONG) +check_type_size("__int64" CMAKE_SIZEOF___INT64) +check_type_size("int64_t" CMAKE_SIZEOF_INT64_T) + +#ADD_DEFINITIONS(-DIGTL_SIZEOF_CHAR=${CMAKE_SIZEOF_CHAR}) +#ADD_DEFINITIONS(-DIGTL_SIZEOF_DOUBLE=${CMAKE_SIZEOF_DOUBLE}) +#ADD_DEFINITIONS(-DIGTL_SIZEOF_FLOAT=${CMAKE_SIZEOF_FLOAT}) +#ADD_DEFINITIONS(-DIGTL_SIZEOF_INT=${CMAKE_SIZEOF_INT}) +#ADD_DEFINITIONS(-DIGTL_SIZEOF_LONG=${CMAKE_SIZEOF_LONG}) +#ADD_DEFINITIONS(-DIGTL_SIZEOF_SHORT=${CMAKE_SIZEOF_SHORT}) +#ADD_DEFINITIONS(-DIGTL_SIZEOF_FLOAT=${CMAKE_SIZEOF_FLOAT}) +#ADD_DEFINITIONS(-DIGTL_SIZEOF_DOUBLE=${CMAKE_SIZEOF_DOUBLE}) + +#IF(CMAKE_SIZEOF_LONG_LONG) +# ADD_DEFINITIONS(-DIGTL_TYPE_USE_LONG_LONG=1) +# ADD_DEFINITIONS(-DIGTL_SIZEOF_LONG_LONG=${CMAKE_SIZEOF_LONG_LONG}) +#ELSE(CMAKE_SIZEOF_LONG_LONG) +# IF(CMAKE_SIZEOF___INT64) +# ADD_DEFINITIONS(-DIGTL_TYPE_USE___INT64=1) +# ADD_DEFINITIONS(-DIGTL_SIZEOF___INT64=${CMAKE_SIZEOF___INT64}) +# ELSE(CMAKE_SIZEOF___INT64) +# IF(CMAKE_SIZEOF_INT64_T) +# ADD_DEFINITIONS(-DIGTL_TYPE_USE_INT64_T=1) +# ADD_DEFINITIONS(-DIGTL_SIZEOF_INT64_T=${CMAKE_SIZEOF_INT64_T}) +# ENDIF(CMAKE_SIZEOF_INT64_T) +# ENDIF(CMAKE_SIZEOF___INT64) +#ENDIF(CMAKE_SIZEOF_LONG_LONG) \ No newline at end of file diff --git a/openigtlink/repo/CMake/igtlTestSocklenT.cxx b/openigtlink/repo/CMake/igtlTestSocklenT.cxx new file mode 100755 index 0000000..f3ee7ed --- /dev/null +++ b/openigtlink/repo/CMake/igtlTestSocklenT.cxx @@ -0,0 +1,14 @@ +#include +#include +#if !defined(_WIN32) || defined(__CYGWIN__) +# include +# include +#endif + +int main() +{ + /* Test whether getsockname takes socklen_t. */ + if(getsockname(0, 0, (socklen_t*)0)) return 0; + if(sizeof (socklen_t)) return 0; + return 0; +} diff --git a/openigtlink/repo/CMakeLists.txt b/openigtlink/repo/CMakeLists.txt new file mode 100644 index 0000000..117b11d --- /dev/null +++ b/openigtlink/repo/CMakeLists.txt @@ -0,0 +1,314 @@ +PROJECT(OpenIGTLink) + +CMAKE_MINIMUM_REQUIRED(VERSION 3.1) + +INCLUDE(ExternalProject) + +IF(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +ENDIF(COMMAND cmake_policy) + +set (CMAKE_CXX_STANDARD 11) +#----------------------------------------------------------------------------- +# OpenIGTlink version number. +SET(OpenIGTLink_VERSION_MAJOR "3") +SET(OpenIGTLink_VERSION_MINOR "1") +SET(OpenIGTLink_VERSION_PATCH "0") + +OPTION(OpenIGTLink_PROTOCOL_VERSION_2 "Build Library for Protocol Version 2" ON) +OPTION(OpenIGTLink_PROTOCOL_VERSION_3 "Build Library for Protocol Version 3" ON) + +SET(OpenIGTLink_HEADER_VERSION "1") +IF(OpenIGTLink_PROTOCOL_VERSION_3) + SET(OpenIGTLink_PROTOCOL_VERSION "3") + SET(OpenIGTLink_HEADER_VERSION "2") +ELSEIF(OpenIGTLink_PROTOCOL_VERSION_2) + SET(OpenIGTLink_PROTOCOL_VERSION "2") +ELSE() + SET(OpenIGTLink_PROTOCOL_VERSION "1") +ENDIF() + +#----------------------------------------------------------------------------- +# Configure VideoStreaming +# Create the link to the VideoStreaming libraries +OPTION(OpenIGTLink_USE_H264 "Link the OpenH264 tree." OFF) +OPTION(OpenIGTLink_USE_VP9 "Link the VP9 tree." OFF) +OPTION(OpenIGTLink_USE_X265 "Link the X265 tree." OFF) +OPTION(OpenIGTLink_USE_OpenHEVC "Link the OpenHEVC tree." OFF) +OPTION(OpenIGTLink_USE_AV1 "Link the AV1 tree." OFF) + +#----------------------------------------------------------------------------- +# Configure WebSocket +OPTION(OpenIGTLink_USE_WEBSOCKET "Build the Websocket." OFF) + +#----------------------------------------------------------------------------- +# OpenIGTLink build configuration options. +OPTION(BUILD_SHARED_LIBS "Build OpenIGTLink with shared libraries." OFF) +SET(OpenIGTLink_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) + +IF(NOT OpenIGTLink_BUILD_SHARED_LIBS) + OPTION(BUILD_GENERATE_PIC "Generate position independent code (for static)." ON) + SET(OpenIGTLink_BUILD_GENERATE_PIC ${BUILD_GENERATE_PIC}) +ENDIF() + +#----------------------------------------------------------------------------- +if(NOT DEFINED OpenIGTLink_BUILD_DOCUMENTATION) + option(BUILD_DOCUMENTATION "Build OpenIGTLink Documentation" OFF) + set(OpenIGTLink_BUILD_DOCUMENTATION ${BUILD_DOCUMENTATION}) +endif() + +#----------------------------------------------------------------------------- +if(NOT DEFINED OpenIGTLink_BUILD_EXAMPLES) + option(BUILD_EXAMPLES "Build OpenIGTLink example programs." OFF) + set(OpenIGTLink_BUILD_EXAMPLES ${BUILD_EXAMPLES}) +endif() + +#----------------------------------------------------------------------------- +if(NOT DEFINED OpenIGTLink_BUILD_TESTING) + option(BUILD_TESTING "Build the testing tree." ON) + set(OpenIGTLink_BUILD_TESTING ${BUILD_TESTING}) +endif() + +#----------------------------------------------------------------------------- +if(NOT DEFINED OpenIGTLink_USE_GTEST) + option(USE_GTEST "Use googletest for testing" ON) + set(OpenIGTLink_USE_GTEST ${USE_GTEST}) +endif() +#link to google test library tend to fail https://github.com/openigtlink/OpenIGTLink/issues/122 +IF(OpenIGTLink_BUILD_SHARED_LIBS) + SET(OpenIGTLink_USE_GTEST OFF) +ENDIF() + +#----------------------------------------------------------------------------- +# Output directories. +IF(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OpenIGTLink_BINARY_DIR}/bin CACHE INTERNAL "Single output directory for building all libraries.") +ENDIF() +IF(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) + SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OpenIGTLink_BINARY_DIR}/bin CACHE INTERNAL "Single output directory for building all executables.") +ENDIF() +IF(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY) + SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OpenIGTLink_BINARY_DIR}/lib CACHE INTERNAL "Single output directory for building all archives.") +ENDIF() + +SET(OpenIGTLink_CMAKE_DIR "${OpenIGTLink_SOURCE_DIR}/CMake") +SET(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH} ${OpenIGTLink_SOURCE_DIR}/CMake/Modules") + +#----------------------------------------------------------------------------- +# Installation vars. +# OpenIGTLink_INSTALL_BIN_DIR - binary dir (executables) +# OpenIGTLink_INSTALL_LIB_DIR - library dir (libs) +# OpenIGTLink_INSTALL_DATA_DIR - share dir (say, examples, data, etc) +# OpenIGTLink_INSTALL_INCLUDE_DIR - include dir (headers) +# OpenIGTLink_INSTALL_PACKAGE_DIR - package/export configuration files +# OpenIGTLink_INSTALL_NO_DEVELOPMENT - do not install development files +# OpenIGTLink_INSTALL_NO_RUNTIME - do not install runtime files +# OpenIGTLink_INSTALL_NO_DOCUMENTATION - do not install documentation files + +IF(NOT OpenIGTLink_INSTALL_BIN_DIR) + SET(OpenIGTLink_INSTALL_BIN_DIR "bin") +ENDIF() + +IF(NOT OpenIGTLink_INSTALL_LIB_DIR) + SET(OpenIGTLink_INSTALL_LIB_DIR "lib/igtl") +ENDIF() + +IF(NOT OpenIGTLink_INSTALL_DATA_DIR) + SET(OpenIGTLink_INSTALL_DATA_DIR "share/igtl") +ENDIF() + +IF(NOT OpenIGTLink_INSTALL_INCLUDE_DIR) + SET(OpenIGTLink_INSTALL_INCLUDE_DIR "include/igtl") +ENDIF() + +IF(NOT igtlutil_INSTALL_INCLUDE_DIR) + SET(igtlutil_INSTALL_INCLUDE_DIR "include/igtl/igtlutil") +ENDIF() + +IF(NOT OpenIGTLink_INSTALL_PACKAGE_DIR) + SET(OpenIGTLink_INSTALL_PACKAGE_DIR "${OpenIGTLink_INSTALL_LIB_DIR}/cmake/igtl-${OpenIGTLink_VERSION_MAJOR}.${OpenIGTLink_VERSION_MINOR}" + CACHE INTERNAL "") +ENDIF() + +IF(NOT OpenIGTLink_INSTALL_NO_DOCUMENTATION) + SET(OpenIGTLink_INSTALL_NO_DOCUMENTATION 0) +ENDIF() + +SET(OpenIGTLink_DIR "${OpenIGTLink_BINARY_DIR}" CACHE INTERNAL "OpenIGTLink dir to be used by subprojects") + +#----------------------------------------------------------------------------- +# OpenIGTLink requires special compiler flags on some platforms. +INCLUDE(FindThreads) + +IF(CMAKE_COMPILER_IS_GNUCXX) + # '-fno-tree-vectorize' option is added to avoid segmentation fault that occurs in + # igtl_image_convert_byte_order() (Source/igtlutil/igtl_image.c) built with 'Release' + # option on 64-bit Linux. + INCLUDE(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG("-fno-tree-vectorize" OpenIGTLink_GNUCXX_TREE_VECTORIZE_SUPPORT) + IF(OpenIGTLink_GNUCXX_TREE_VECTORIZE_SUPPORT) + SET(OpenIGTLink_REQUIRED_C_FLAGS "${OpenIGTLink_REQUIRED_C_FLAGS} -w -fno-tree-vectorize") + SET(OpenIGTLink_REQUIRED_CXX_FLAGS "${OpenIGTLink_REQUIRED_CXX_FLAGS} -fno-tree-vectorize") + ENDIF() + + # If the library is built as a static library, pass -fPIC option to the compiler + IF(OpenIGTLink_BUILD_GENERATE_PIC) + SET(OpenIGTLink_REQUIRED_C_FLAGS "${OpenIGTLink_REQUIRED_C_FLAGS} -fPIC") + SET(OpenIGTLink_REQUIRED_CXX_FLAGS "${OpenIGTLink_REQUIRED_CXX_FLAGS} -fPIC") + ENDIF() + + # pthread + IF(CMAKE_HAVE_THREADS_LIBRARY) + SET(OpenIGTLink_REQUIRED_LINK_FLAGS "${OpenIGTLink_REQUIRED_LINK_FLAGS} ${CMAKE_THREAD_LIBS_INIT}") + ENDIF() +ENDIF() + + +# for the gnu compiler a -D_PTHREADS is needed on sun +# for the native compiler a -mt flag is needed on the sun +IF(CMAKE_USE_PTHREADS) + IF(CMAKE_SYSTEM MATCHES "SunOS.*") + IF(CMAKE_COMPILER_IS_GNUCXX) + SET(OpenIGTLink_REQUIRED_CXX_FLAGS "${OpenIGTLink_REQUIRED_CXX_FLAGS} -D_PTHREADS") + ELSE() + SET(OpenIGTLink_REQUIRED_CXX_FLAGS "${OpenIGTLink_REQUIRED_CXX_FLAGS} -mt") + SET(OpenIGTLink_REQUIRED_C_FLAGS "${OpenIGTLink_REQUIRED_C_FLAGS} -mt") + ENDIF() + ENDIF() +ENDIF() + +OPTION(OpenIGTLink_ENABLE_VIDEOSTREAMING "Video stream feature activated." OFF) +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "2") + IF (OpenIGTLink_USE_H264 OR OpenIGTLink_USE_VP9 OR OpenIGTLink_USE_X265 OR OpenIGTLink_USE_OpenHEVC OR OpenIGTLink_USE_AV1) + SET(OpenIGTLink_ENABLE_VIDEOSTREAMING ON) + ENDIF() +ENDIF() +#----------------------------------------------------------------------------- +# Run superbuild script instead of library script +IF (NOT (${CMAKE_VERSION} VERSION_LESS 3.4)) + #MESSAGE ("Cmake version is not less than 3.4, super build available") + OPTION(OpenIGTLink_SUPERBUILD "Superbuild or not." OFF) + IF(OpenIGTLink_SUPERBUILD) + INCLUDE(SuperBuild/Superbuild.cmake) + RETURN() + ENDIF() +ELSE() + message(WARNING "CMake >= 3.4.0 recommended to enable the superbuild option") +ENDIF() + +#----------------------------------------------------------------------------- +# Add compiler flags OpenIGTLink needs to work on this platform +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenIGTLink_REQUIRED_C_FLAGS}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenIGTLink_REQUIRED_CXX_FLAGS}") +SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenIGTLink_REQUIRED_LINK_FLAGS}") +SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${OpenIGTLink_REQUIRED_LINK_FLAGS}") +SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${OpenIGTLink_REQUIRED_LINK_FLAGS}") + +#----------------------------------------------------------------------------- +# Configure Subdirectories +SET(igtlutil_INCLUDE_DIRS CACHE STRING "") +MARK_AS_ADVANCED(igtlutil_INCLUDE_DIRS) +SET(OpenIGTLink_INCLUDE_DIRS CACHE STRING "") +MARK_AS_ADVANCED(OpenIGTLink_INCLUDE_DIRS) +ADD_SUBDIRECTORY(Source/igtlutil) +ADD_SUBDIRECTORY(Source) +ADD_SUBDIRECTORY(Tools) + +#----------------------------------------------------------------------------- +# Platform configuration tests. +INCLUDE(${OpenIGTLink_CMAKE_DIR}/OpenIGTLinkCMakeTests.cmake) +SET(OpenIGTLink_LIBRARY_TARGETS_FILE "${OpenIGTLink_BINARY_DIR}/OpenIGTLinkTargets.cmake") + +#----------------------------------------------------------------------------- +# Generate Configuration Header files. +INCLUDE(${OpenIGTLink_SOURCE_DIR}/CMake/OpenIGTLinkConfigPlatform.cmake) + +CONFIGURE_FILE(${OpenIGTLink_SOURCE_DIR}/igtlConfigure.h.in + ${OpenIGTLink_BINARY_DIR}/igtlConfigure.h) + +CONFIGURE_FILE(${OpenIGTLink_SOURCE_DIR}/igtl_typeconfig.h.in + ${OpenIGTLink_BINARY_DIR}/igtl_typeconfig.h) + +CONFIGURE_FILE(${OpenIGTLink_SOURCE_DIR}/igtlTypeConfig.h.in + ${OpenIGTLink_BINARY_DIR}/igtlTypeConfig.h) + +#----------------------------------------------------------------------------- +# Help other projects use OpenIGTLink. + +# Copy the UseOpenIGTLink.cmake file to the binary tree for backward compatability. +CONFIGURE_FILE(${OpenIGTLink_SOURCE_DIR}/UseOpenIGTLink.cmake.in + ${OpenIGTLink_BINARY_DIR}/UseOpenIGTLink.cmake COPYONLY IMMEDIATE) + +# Create the OpenIGTLinkConfig.cmake file containing the OpenIGTLink configuration. +INCLUDE(${OpenIGTLink_SOURCE_DIR}/CMake/GenerateOpenIGTLinkConfig.cmake) + +# Create the OpenIGTLinkVersion.cmake file containing the OpenIGTLink version. +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + ${OpenIGTLink_BINARY_DIR}/OpenIGTLinkConfigVersion.cmake + VERSION "${OpenIGTLink_VERSION_MAJOR}.${OpenIGTLink_VERSION_MINOR}.${OpenIGTLink_VERSION_PATCH}" + COMPATIBILITY SameMajorVersion) + +# Save the compiler settings so another project can import them. +# The functionality of this module has been dropped as of CMake 2.8. It was +# deemed harmful (confusing users by changing their compiler). CMAKE_EXPORT_BUILD_SETTINGS should be removed +# INCLUDE(${CMAKE_ROOT}/Modules/CMakeExportBuildSettings.cmake) +# CMAKE_EXPORT_BUILD_SETTINGS(${OpenIGTLink_BINARY_DIR}/OpenIGTLinkBuildSettings.cmake) + +INSTALL(FILES + ${OpenIGTLink_BINARY_DIR}/UseOpenIGTLink.cmake + ${OpenIGTLink_BINARY_DIR}/Utilities/OpenIGTLinkConfig.cmake + ${OpenIGTLink_BINARY_DIR}/OpenIGTLinkConfigVersion.cmake + DESTINATION ${OpenIGTLink_INSTALL_PACKAGE_DIR} + COMPONENT Development + ) + +INSTALL(FILES + ${OpenIGTLink_BINARY_DIR}/igtlConfigure.h + DESTINATION ${OpenIGTLink_INSTALL_INCLUDE_DIR} + COMPONENT Development + ) + +INSTALL(FILES + ${OpenIGTLink_BINARY_DIR}/igtl_typeconfig.h + DESTINATION ${OpenIGTLink_INSTALL_INCLUDE_DIR} + COMPONENT Development + ) + +INSTALL(FILES + ${OpenIGTLink_BINARY_DIR}/igtlTypeConfig.h + DESTINATION ${OpenIGTLink_INSTALL_INCLUDE_DIR} + COMPONENT Development + ) + +#----------------------------------------------------------------------------- +# Export targets +EXPORT(TARGETS OpenIGTLink + FILE "${OpenIGTLink_LIBRARY_TARGETS_FILE}" + ) + +# Export targets for install +INSTALL(EXPORT OpenIGTLink + DESTINATION "${OpenIGTLink_INSTALL_PACKAGE_DIR}" + FILE "OpenIGTLinkTargets.cmake" + ) + +#----------------------------------------------------------------------------- +# Tests +IF(OpenIGTLink_BUILD_TESTING) + ENABLE_TESTING() + ADD_SUBDIRECTORY(Testing) + INCLUDE(${CMAKE_ROOT}/Modules/Dart.cmake) +ENDIF() + +#----------------------------------------------------------------------------- +# Examples +IF(OpenIGTLink_BUILD_EXAMPLES) + ADD_SUBDIRECTORY(Examples) +ENDIF() + +#----------------------------------------------------------------------------- +# Build Doxygen documentation +IF(OpenIGTLink_BUILD_DOCUMENTATION) + ADD_SUBDIRECTORY(Documents/Doxygen) +ENDIF() diff --git a/openigtlink/repo/Documents/Doxygen/CMakeLists.txt b/openigtlink/repo/Documents/Doxygen/CMakeLists.txt new file mode 100644 index 0000000..4140781 --- /dev/null +++ b/openigtlink/repo/Documents/Doxygen/CMakeLists.txt @@ -0,0 +1,24 @@ +#-- Add an Option to toggle the generation of the API documentation +if(OpenIGTLink_BUILD_DOCUMENTATION) + + FIND_PACKAGE(Doxygen QUIET) + if (NOT DOXYGEN_FOUND) + message(FATAL_ERROR "Doxygen is needed to build the documentation. Please install it correctly") + endif() + + #IF (BUILD_DOXYGEN) + CONFIGURE_FILE(${OpenIGTLink_SOURCE_DIR}/Utilities/Doxygen/doxygen.config.in + ${OpenIGTLink_BINARY_DIR}/Utilities/Doxygen/doxygen.config) + + CONFIGURE_FILE(${OpenIGTLink_SOURCE_DIR}/Utilities/Doxygen/igtldoxygen.pl.in + ${OpenIGTLink_BINARY_DIR}/Utilities/Doxygen/igtldoxygen.pl) + + ADD_CUSTOM_TARGET(Documentation + COMMAND ${DOXYGEN_EXECUTABLE} ${OpenIGTLink_BINARY_DIR}/Utilities/Doxygen/doxygen.config + MAIN_DEPENDENCY ${OpenIGTLink_BINARY_DIR}/Utilities/Doxygen/doxygen.config + DEPENDS ${OpenIGTLink_BINARY_DIR}/Utilities/Doxygen/igtldoxygen.pl + WORKING_DIRECTORY ${OpenIGTLink_BINARY_DIR}/Utilities/Doxygen + ) + #ENDIF (BUILD_DOXYGEN) + +endif() diff --git a/openigtlink/repo/Documents/Doxygen/DoxygenFooter.html b/openigtlink/repo/Documents/Doxygen/DoxygenFooter.html new file mode 100644 index 0000000..e6624e5 --- /dev/null +++ b/openigtlink/repo/Documents/Doxygen/DoxygenFooter.html @@ -0,0 +1,8 @@ +
+Generated at $datetime for $projectname by doxygen + $doxygenversion written by Dimitri van Heesch, + © 1997-2012
+ + diff --git a/openigtlink/repo/Documents/Doxygen/DoxygenHeader.html b/openigtlink/repo/Documents/Doxygen/DoxygenHeader.html new file mode 100644 index 0000000..489643e --- /dev/null +++ b/openigtlink/repo/Documents/Doxygen/DoxygenHeader.html @@ -0,0 +1,24 @@ + + + +$title + + + + + +
+Main Page   + +Namespace List   +Class Hierarchy   +Alphabetical List   +Compound List   +File List   +Namespace Members   +Compound Members   +File Members   + +
+ + diff --git a/openigtlink/repo/Documents/Doxygen/DoxygenStyle.css b/openigtlink/repo/Documents/Doxygen/DoxygenStyle.css new file mode 100644 index 0000000..347be7a --- /dev/null +++ b/openigtlink/repo/Documents/Doxygen/DoxygenStyle.css @@ -0,0 +1,358 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +BODY,TD { + font-size: 90%; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} +CAPTION { font-weight: bold } +DIV.qindex { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.nav { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.navtab { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +TD.navtab { + font-size: 70%; +} +A.qindex { + text-decoration: none; + font-weight: bold; + color: #1A419D; +} +A.qindex:visited { + text-decoration: none; + font-weight: bold; + color: #1A419D +} +A.qindex:hover { + text-decoration: none; + background-color: #ddddff; +} +A.qindexHL { + text-decoration: none; + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #6666cc; + color: #ffffff; +} +A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } +A.el { text-decoration: none; font-weight: bold } +A.elRef { font-weight: bold } +A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} +A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} +A.codeRef:link { font-weight: normal; color: #0000FF} +A.codeRef:visited { font-weight: normal; color: #0000FF} +A:hover { text-decoration: none; background-color: #f2f2ff } +DL.el { margin-left: -1cm } +.fragment { + font-family: monospace, fixed; + font-size: 95%; +} +PRE.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } + +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } +BODY { + background: white; + color: black; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #e8eef2; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TD.indexvalue { + background-color: #e8eef2; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 80%; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +TD.tiny { font-size: 75%; +} +a { + color: #1A41A8; +} +a:visited { + color: #2A3798; +} +.dirtab { padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} +TH.dirtab { background: #e8eef2; + font-weight: bold; +} +HR { height: 1px; + border: none; + border-top: 1px solid black; +} + +/* Style for detailed member documentation */ +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; +} +.memnav { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +.memitem { + padding: 4px; + background-color: #eef3f5; + border-width: 1px; + border-style: solid; + border-color: #dedeee; + -moz-border-radius: 8px 8px 8px 8px; +} +.memname { + white-space: nowrap; + font-weight: bold; +} +.memdoc{ + padding-left: 10px; +} +.memproto { + background-color: #d5e1e8; + width: 100%; + border-width: 1px; + border-style: solid; + border-color: #84b0c7; + font-weight: bold; + -moz-border-radius: 8px 8px 8px 8px; +} +.paramkey { + text-align: right; +} +.paramtype { + white-space: nowrap; +} +.paramname { + color: #602020; + font-style: italic; + white-space: nowrap; +} +/* End Styling for detailed member documentation */ + +/* for the tree view */ +.ftvtree { + font-family: sans-serif; + margin:0.5em; +} +.directory { font-size: 9pt; font-weight: bold; } +.directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } +.directory > h3 { margin-top: 0; } +.directory p { margin: 0px; white-space: nowrap; } +.directory div { display: none; margin: 0px; } +.directory img { vertical-align: -30%; } diff --git a/openigtlink/repo/Documents/Doxygen/MainPage.dox b/openigtlink/repo/Documents/Doxygen/MainPage.dox new file mode 100644 index 0000000..187d2ba --- /dev/null +++ b/openigtlink/repo/Documents/Doxygen/MainPage.dox @@ -0,0 +1,38 @@ +/** + * + * \mainpage The OpenIGTLink Library + * + * \section intro Introduction + * + * The OpenIGTLink protocol is a simple but extensible network communication protocol + * to exchange various types of data among software and devices for image-guided therapy + * (IGT) e.g. surgical navigation software, tracking device, robotic device, imaging scanner. + * The protocol can handle images, tool positions, transforms, commands, device status, + * monitoring command, and other user-defined data types. + * It is designed to work in the application layer of the TCP/IP stack. + * + * The goal of the OpenIGTLink protocol is to make system integration for IGT application easier + * and faster. To achieve this objective, we set the following rules: + * + * \arg \c Open. The protocol and the OpenIGTLink library is provided free of charge for + * any purpose including commercial use. This would encourage engineers and researchers + * to participate the community and help making the protocol more universal, compatible and + * reliable. + * + * \arg \c Simple. The protocol only defines a limited number of simple memory layouts + * for messaging and does not require interface software to handle the all types of messages. + * Such simple specification allows implementing OpenIGTLink interface for wide variety of + * computer systems ranging from embedded systems to high-performance computers. + * + * \arg \c Extensible. The protocol has a mechanism to define a user-defined message + * type. + * + * \section homepage More Information + * + * The Home Page of the OpenIGTLink is + * + * http://openigtlink.org/ + * + * + */ + diff --git a/openigtlink/repo/Documents/Doxygen/Modules.dox b/openigtlink/repo/Documents/Doxygen/Modules.dox new file mode 100644 index 0000000..e69de29 diff --git a/openigtlink/repo/Documents/Protocol/bind.md b/openigtlink/repo/Documents/Protocol/bind.md new file mode 100644 index 0000000..9a00124 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/bind.md @@ -0,0 +1,161 @@ +[Back to Index](/Documents/Protocol/index.md) + +Bind Message +============ + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +The Bind message is designed to bind any OpenIGTLink messages into a single +message. Messages bound in a BIND message are called 'child messages.' The BIND +message format is useful, when one needs to care about synchronization of +multiple messages (e.g. multi-channel sensors), or sending associative array +(pairs of key string and value). The bind message format consists of the bind +header section, which contains types and sizes of child messages, the child +message name table section, and the child message body section. + +Message Types +============= + +BIND +---- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + N_CHLID | uint16 | Number of child messages + BIND_HEADER | BIND HEADER | Types and sizes of child messages + NAME_TABLE | NAME TABLE | Name tables for child messages + DATA | DATA | Child messages + + +- BIND HEADER Section + + Data | Type | Description +------------------|-----------|------------------------------------------------- + CTYPE_0 | char[12] | Device type string for child message 0 + CSIZE_0 | uint64 | Data size for child message 0 + ... | ... | + CTYPE_(N_CHILD-1)| char[12] | Device type string for child message (N_CHILD-1) + CSIZE_(N_CHILD-1)| uint 64 | Data size for child message (N_CHILD-1) + + +- NAME TABLE Section (NULL-separated values) + + Data | Type | Description +----------------|---------------|----------------------------------------------- + NTABLE_SIZE | uint16 | Size of name table (including the padding) + NAME_0 | char[*] | Name for child message 0 + (null) | uint8 | separator + ... | ... | + NAME_(N_CM-1) | char[*] | Name for child message (N_CHILD-1) + (null) | uint8 | Separator + (Padding*) | uint8 or none | Padding to align with WORD + + +* Padding field is inserted only if the previous field does not aligned with WORD border. + +- DATA Section + + Data | Type | Description +------------------|---------------|----------------------------------------------- + CDATA 0 | CTYPE_0 | Data array for child message 0 (size: CSIZE_0) + (Padding*) | uint8 or none | Padding to align DATA with WORD + CDATA 1 | CTYPE_1 | Data array for child message 1 (size: CSIZE_1) + (Padding*) | uint8 or none | Padding to align DATA with WORD + ... | ... | + CDATA_(N_CHILD-1)| CTYPE_(N_CHILD-1)|Data array for child message (N_CHILD-1) + (Padding*) | uint8 or none | Padding to align DATA with WORD + + +GET_BIND +-------- + +GET_BIND is used to request the receiver for associative array data. +If a GET_BIND message does not have a body, it requests all data. + + Data | Type | Description +--------------|---------------|------------------------------------------------- + N_CHLID | uint16 | Number of child messages + BIND_HEADER_2| BIND HEADER 2 | Types and sizes of child messages + NAME_TABLE | NAME TABLE | Name tables for child messages + +- BIND HEADER 2 Section + + Data | Type | Description +------------------|-----------|------------------------------------------------- + CTYPE_0 | char[12] | Device type string for child message 0 + ... | ... | + CTYPE_(N_CHILD-1)| char[12] | Device type string for child message (N_CHILD-1) + +- NAME_TABLE (see BIND message) + + +STT_BIND +-------- + +GET_BIND is used to request the receiver for associative array data. +If a GET_BIND message does not have a body, it requests all data. + + + Data | Type | Description +--------------|---------------|------------------------------------------------- + RESOL | uint64 | Minimum interval between message (ns)* + +See [Time Stamp](timestamp.md) + +or + + Data | Type | Description +--------------|---------------|------------------------------------------------- + N_CHLID | uint16 | Number of child messages + BIND_HEADER_2| BIND HEADER 2 | Types and sizes of child messages + NAME_TABLE | NAME TABLE | Name tables for child messages + +- BIND HEADER 2 Section (see BIND message) +- NAME_TABLE Section (see BIND message) + + +STP_BIND +-------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +RTS_BIND +-------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +Implementations +=================== + +* [igtlBindMessage.h](/Source/igtlBindMessage.h) +* [igtlBindMessage.cxx](/Source/igtlBindMessage.cxx) + + +Contributors +=================== + +* Junichi Tokuda + + + + + + + + + + + + + + + diff --git a/openigtlink/repo/Documents/Protocol/capability.md b/openigtlink/repo/Documents/Protocol/capability.md new file mode 100644 index 0000000..34e1ed2 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/capability.md @@ -0,0 +1,71 @@ +[Back to Index](/Documents/Protocol/index.md) + +Capability Message +================== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +The CAPABILITY type lists the names of message types that the receiver can +interpret. Although the OpenIGTLink protocol guarantees that any receiver can at +least skip messages with unknown type and continue to interpret the following +messages, it is a good idea to get the capability information at system startup +to ensure application-level compatibility of various devices. In a CAPABILITY +message type, each message type name comes with format version number. If the +receiver can interpret multiple versions for a certain message type, they should +be listed as independent types. + +Message Types +=================== + +CAPABILITY +---------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + TYPE_0 | uint8[12] | Type name #0 + ... | ... | + TYPE_(N_TYPE)| uint8[12] | Type name #(N_TYPE) + +* Number of type names (N_TYPE) is calculated by BODY_SIZE / 12. + +GET_CAPABIL +----------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_CAPABIL +----------- + +N/A + +STP_CAPABIL +------------------- + +N/A + +RTS_CAPABIL +------------------- + +N/A + +Implementations +=================== + +* [igtlCapabilityMessage.h](/Source/igtlCapabilityMessage.h) +* [igtlCapabilityMessage.cxx](/Source/igtlCapabilityMessage.cxx) + + +Contributors +=================== + +Junichi Tokuda + + + + diff --git a/openigtlink/repo/Documents/Protocol/colortable.md b/openigtlink/repo/Documents/Protocol/colortable.md new file mode 100644 index 0000000..bf01f9e --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/colortable.md @@ -0,0 +1,65 @@ + +ColorTable Message +================== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +=================== + +COLORT is used to transfer a color table. + +Message Types +=================== + +COLORT +------ + + Data | Type | Description +--------------|---------------|------------------------------------------------- + INDEX_TYPE | uint8 | Index type (3:uint8 5:uint16) + MAP_TYPE | uint8 | Map type (3:uint8 5:uint16 19:RGB color) + TABLE | uint8[] | Color index table + +GET_COLORT +------------------- + +To get the COLORT, GET_COLORT is used with the Id in the device name field. + + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_COLORT +------------------- + +N/A + +STP_COLORT +------------------- + +N/A + +RTS_COLORT +------------------- + +N/A + +Implementations +=================== + +* [igtlColorTableMessage.h](/Source/igtlColorTableMessage.h) +* [igtlColorTableMessage.cxx](/Source/igtlColorTableMessage.cxx) + +Contributors +=================== + +* Alexander Schaal + + + + + + diff --git a/openigtlink/repo/Documents/Protocol/command.md b/openigtlink/repo/Documents/Protocol/command.md new file mode 100644 index 0000000..4c290f6 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/command.md @@ -0,0 +1,47 @@ +[Back to Index](/Documents/Protocol/index.md) + +Command Message +=============== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 +- Available: 3.0 and later + + +Summary +======= + +The COMMAND is a message type that can be used to transfer a command string +structured in XML. While STRING offers a similar functionality, COMMAND has +additional fields to include command ID and name providing an easy way to +reference previous messages exchanged between the two hosts during the session. + +IGSIO (http://igsio.github.io/) demonstrates representative usage of the COMMAND +type. + + +Message Types +============= + +COMMAND +------- + +Data | Type | Description +---------------|------------------------|--------------------------------------- +COMMAND_ID | uint32 | The unique ID of this command +COMMAND_NAME | uint8[IGT_COMMAND_SIZE]| The name of the command +ENCODING | uint16 | Character encoding type as MIBenum + | | (defined by IANA). Default=3 +LENGTH | uint32 | The length of command +COMMAND | uint8[LENGTH] | The command encoded with ENCODING + + +For MIBenum values, please refer http://www.iana.org/assignments/character-sets + +Implementations +=============== + +* [igtlCommandMessage.h](/Source/igtlCommandMessage.h) +* [igtlCommandMessage.cxx](/Source/igtlCommandMessage.cxx) + + diff --git a/openigtlink/repo/Documents/Protocol/header.md b/openigtlink/repo/Documents/Protocol/header.md new file mode 100644 index 0000000..cedbbec --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/header.md @@ -0,0 +1,122 @@ +[Back to Index](/Documents/Protocol/index.md) + +Message Header +============== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Header Fields +============= + + Data | Type | Description +--------------|---------------|------------------------------------------------- + V | uint16 | Header version number (2 for version 2 and 3) + TYPE | char[12] | Type name of data + DEVICE_NAME | char[20] | Unique device name + TIME_STAMP | uint64 | Timestamp or 0 if unused + BODY_SIZE | uint64 | Size of the body in bytes + CRC | uint64 | 64 bit CRC for body data + + +Header version number +--------------------- + +The header version number field specifies the Header Version. Please note +that the *Header Version* is not the same as the *Protocol Version*, as +the Protocol Version reflects not only the format of the header but also +the available message types. Two header versions exist as of Protocol Version 3.x: + +- _Header Version 1_ is used in Protocol Version 1 and 2. +- _Header Version 2_ is used in Protocol Version 3.x. + +The major difference between header versions 1 and 2 is the mechanism to include +the extended header and meta data in the message. This feature has been introduced +in Protocol Version 3. + +Type name +--------- + +The type name field is an ASCII character string specifying the type of the data +contained in the message body e.g. "TRANSFORM". The length of the type name must +be within 12 characters. + +Device name +----------- + +The device name field contains an ASCII character string specifying the name of +the the message. + +Timestamp +--------- + +The timestamp field contains a 64-bit timestamp indicating when the data is +generated. Please refer [Timestamp](timestamp.html) for the format of the 64-bit +timestamp. + +Body size +--------- + +The body size field contains the size of the body in bytes. The Body is a section +of the OpenIGTLink message following the Header. Until Version 2, the Body +only contains the message content, and hence many old programs assumed that +the Body size represents the content size. Since Version 3, the Body is redefined +as a set of Extended Header, Content, and Metadata. The content size must be +calculated by BODY_SIZE - (EXT_HEADER_SIZE + METADAT_SIZE). + +CRC +--- +The 64-bit CRC used in OpenIGTLink protocol is based on +[ECMA-182 standard](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-182.pdf). +An example code is available in [igtl_util.c](/Source/igtlutil/igtl_util.c) +in the OpenIGTLink library. + +Extended Header Fields +====================== + + Data | Type | Description +-----------------|---------------|---------------------------------------------- + EXT_HEADER_SIZE | uint16 | Length of Extended Header section + METADATA_SIZE | uint16 | Length of Metadata section + MSG_ID | uint32 | Message ID + (Reserved) | Uint32 | (Reserved) + + +Metadata Fields +=============== + + Data | Type | Description +----------------------------|-------------|------------------------------------- + INDEX_COUNT | uint16 | Number of meta data + META_HEADER_0 | META_HEADER | Header for metadata 0 + ... | ... | ... + META_HEADER_(INDEX_COUNT-1)| META_HEADER | Header for metadata (INDEX_COUNT-1) + META_DATA_0 | META_DATA | Content for metadata 0 + ... | ... | ... + META_DATA_(INDEX_COUNT-1) | META_DATA | Content for metadata (INDEX_COUNT-1) + +- META_HEADER + + Data | Type | Description +----------------|-------------|-------------------------------------------------- + KEY_SIZE | uint16 | Size of key (bytes) + VALUE_ENCODING | uint16 | Character encoding type for value as MIBenum value. + VALUE_SIZE | uint32 | Size of value (bytes) + +- META_DATA + + Data | Type | Description +-------|----------------------|-------------------------------------------------- + KEY | uint16[KEY_SIZE] | Key (ASCII) + VALUE | uint16[VALUE_SIZE] | Value (Encoded according to VALUE_ENCODING) + +* For MIBenum character encoding, please refer [IANA Character Sets](http://www.iana.org/assignments/character-sets). US-ASCII (ANSI-X3.4-1968; MIBenum = 3) is strongly recommended. + +Byte Order +========== + +Big endian should be used for all [numerical values](http://www.opengroup.org/onlinepubs/007908799/xns/htonl.html) +(version, body size, crc). Unused spaces are padded with 0 (binary). + + + diff --git a/openigtlink/repo/Documents/Protocol/image.md b/openigtlink/repo/Documents/Protocol/image.md new file mode 100644 index 0000000..9836481 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/image.md @@ -0,0 +1,97 @@ +[Back to Index](/Documents/Protocol/index.md) + +Image Message +============= + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + + +Summary +=================== + +The IMAGE format supports 2D or 3D images with metric information including image matrix size, +voxel size, coordinate system type, position, and orientation. The body section of the IMAGE +data consists of two parts: image header to transfer the metric information and image body +to transfer the array of pixel or voxel values. The data type of pixel or voxel can be +either scalar or vector, and numerical values can be 8-, 16-, 32-bit integer, or 32- +or 64-bit floating point. The pixel values can be either big-endian or little-endian, +since the sender software can specify the byte order in the image header. The format +also supports "partial image transfer", in which a region of the image is transferred +instead of the whole image. This mechanism is suitable for real-time applications, +in which images are updated region-by-region. The sub-volume must be box-shaped and +defined by 6 parameters consisting of the indices for the corner voxel of the sub-volume +and matrix size of the sub-volume. + + +Message Types +=================== + +IMAGE +------------------- + + Data | Type | Description +--------------|-----------|----------------------------------------------------- +V | uint16 | version number +T | uint8 | Number of Image Components (1:Scalar, >1:Vector). (NOTE: Vector data is stored fully interleaved.) +S | uint8 | Scalar type (2:int8 3:uint8 4:int16 5:uint16 6:int32 7:uint32 10:float32 11:float64) +E | uint8 | Endian for image data (1:BIG 2:LITTLE) (NOTE: values in image header is fixed to BIG endian) +O | uint8 | Image coordinate (1:RAS 2:LPS) +RI, RJ, RK | uint16[3] | Number of pixels in each direction +TX, TY, TZ | float32[3]| Transverse vector (direction for 'i' index) / The length represents pixel size in 'i' direction in millimeter +SX, SY, SZ | float32[3]| Transverse vector (direction for 'j' index) / The length represents pixel size in 'j' direction in millimeter +NX, NY, NZ | float32[3]| Normal vector of image plane(direction for 'k' index) / The length represents pixel size in 'z' direction or slice thickness in millimeter +PX, PY, PZ | float32[3]| Center position of the image (in millimeter) (*) +DI, DJ, DK | uint16[3] | Starting index of subvolume +DRI, DRJ, DRK | uint16[3] | Number of pixels of subvolume +IMAGE_DATA | uint8[] | Binary image data () Image data (Endian is determined by "E" field) + + +GET_IMAGE +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +STT_IMAGE +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +STP_IMAGE +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +RTS_IMAGE +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + STATUS | uint8 | 0: Success; 1: Error + +Notes +=================== + +The example application of vector type is: +* Vector field +* Image with complex pixel values (e.g. MRI raw data) +* Color image +* Vector data is stored fully interleaved. For example, if you are storing RGB color image, the order should be RGBRGBRGB... (not RRR....GGG...BBB...) + +Implementations +=================== + +* [igtlImageMessage.h](/Source/igtlImageMessage.h) +* [igtlImageMessage.cxx](/Source/igtlImageMessage.cxx) + +Contributors +=================== +* Junichi Tokuda diff --git a/openigtlink/repo/Documents/Protocol/imagemeta.md b/openigtlink/repo/Documents/Protocol/imagemeta.md new file mode 100644 index 0000000..39c5da2 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/imagemeta.md @@ -0,0 +1,73 @@ +[Back to Index](/Documents/Protocol/index.md) + +ImageMeta Message +================= + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + + +Summary +======= + +The IMGMETA message is used to transfer image meta information which is not +available in IMAGE message type, such as patient name, medical record number, +modality etc. An IMGMETA message can contain meta-data for multiple images. +This message type may be used to obtain a list of images available in the remote +system, such as image database or commercial image-guided surgery (IGS) system. + +Message Types +============= + +IMGMETA +------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + NAME | char[64] | Name or description of the image + ID | char[20] | ID to query the IMAGE and COLORT + MODALITY | char[32] | String which specifies the modality + PATIENT_NAME | char[64] | Name of the patient + PATIENT_ID | char[64] | ID of the patient + TIMESTMP | uint64 | Scan time, see [Timestamp](timestamp.md) + RI, RJ, RK | uint16[3] | Number of pixels in each direction (same as in IMAGE) + S | uint8 | Scalar type (e.g. 3:uint8, 5:uint16, same as in IMAGE) + -- | uint8 | Reserved + +* More than one item can be transmitted. The number is bodySize/itemSize. +* To get the IMAGE, GET_IMAGE is used with the Id in the device name field. + + +GET_IMGMETA +------------------- + +GET_IMGMETA is used to query for meta data of image sets. If DEVICE_NAME in the +header is empty, a list of meta data for all available images is returned. + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_IMGMETA +------------------- + +N/A + +STP_IMGMETA +------------------- + +N/A + + +Implementations +=================== + +* [igtlImageMetaMessage.h](/Source/igtlImageMetaMessage.h) +* [igtlImageMetaMessage.cxx](/Source/igtlImageMetaMessage.cxx) + +Contributors +=================== + +* Alexander Schaal + + diff --git a/openigtlink/repo/Documents/Protocol/index.md b/openigtlink/repo/Documents/Protocol/index.md new file mode 100644 index 0000000..1eefc4d --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/index.md @@ -0,0 +1,269 @@ +[Back to Index](/Documents/Protocol/index.md) + + +OpenIGTLink Protocol Description +================================ + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + + +Overview +======== + +OpenIGTLink is an open-source network communication interface specifically +designed for image-guided interventions. It aims to provide a plug-and-play +unified real-time communications (URTC) in operating rooms (ORs) for image-guided +interventions, where imagers, sensors, surgical robots,and computers from +different vendors work cooperatively. This URTC will ensure the seamless data +flow among those components and enable a closed-loop process of planning, control, +delivery, and feedback. The specification of OpenIGTLink is open, and can be +used without any license fee; hence OpenIGTLink is suitable for both industrial +and academic developers. + +We provide [the OpenIGTLink C/C++ library](https://github.com/openigtlink/OpenIGTLink) +as free open-source software under the BSD-style license. The OpenIGTLink library +provides application program interface (API) to communicate with other software +over the network. The OpenIGTLink library supports major platforms including +Microsoft Windows, Linux, and macOS (Mac OS X). Those open-interface and +multi-platform strategies will lead to the widespread use of OpenIGTLink, and +ultimately help to establish the interoperability among a wide variety of +components developed by different groups and companies in the community. + + +Message Structure +================= + +The OpenIGTLink protocol defines a set of message formats for several data types +that are frequently used for image-guided and robot-assisted interventions. +Those formats are used to compose messages that are transferred from one device +to another over the local area network. The application developers can choose +their own transportation layer that fits for their application and environment +(e.g. TCP, UDP, WebSocket). + +While the developers are encouraged to use the data types defined in the +standard protocol, they have an option to define a new message format. +User-defined messages can be mixed with the standard message types, since the +protocol has a mechanism to skip a message, if the receiver does not know its +format. + +In OpenIGTLink Version 3, each OpenIGTLink message consists of the following +four sections: + +~~~~ + Bytes + 0 58 72 + +----------+-------------+-------------------+-----------+ + | HEADER | EXT_HEADER | CONTENT | META_DATA | + +----------+-------------+-------------------+-----------+ + |<----------------- Body -------------------->| +~~~~ + +* Header (58 bytes) +* Extended Header (variable length) (New in Version 3) +* Content (variable length) +* Metadata (variable length) (New in Version 3) + +The last three sections are called "Body" for the sake of convention. Since +there were no Extended Header and Metadata in the older versions before to +Version 3, the Body section was solely used by the message content. +Therefore, the Body Size in the Header represented the size of the message +content as well as the size of the rest of the message. +As a result, many old applications assume that the Body Size in the Header +equals the size of the message content. + +When the message structure was revised for Version 3, we redefined the Body +Size as the total size of Extended Header, Content, and Metadata, because +this new definition allows the old OpenIGTLink programs can still tell the +size of the rest of the message, and skip reading the byte stream until the +beginning of the next message. The size of the content can be computed as: +BODY_SIZE - (EXT_HEADER_SIZE + METADATA_SIZE). + + +Header + Extended Header +------------------------ + +~~~~ + Bytes + 0 2 14 34 + +---+-----------------------+---------------------------------------+ + | V | TYPE | DEVICE_NAME | + +---+-----------------------+---------------------------------------+ + + 34 42 50 58 + +---------------+---------------+---------------+ + | TIME_STAMP | BODY_SIZE | CRC64 | + +---------------+---------------+---------------+ + + + 58 60 62 66 70 + +-----------------+----------------------+---------------+--------+ + | EXT_HEADER_SIZE | METADATA_HEADER_SIZE | METADATA_SIZE | MSG_ID | + +-----------------+----------------------+---------------+--------+ +~~~~ + +The formats of the Header and Extended Header sections are consistent among +all message types, and can be interpreted by any software that has an +OpenIGTLink interface. The Header contains device type (or data type) name, +which specifies the format of the body. The Extended Header section provides +a mechanism to attach application-specific meta-data to the message +along with the Metadata section. + +Content +------- + +The format of contenst section is type-dependent. Please see below for the +detail. + +Meta-Data +--------- + +Meta-data are given in the form of an associative array (i.e. pairs of "key" and +"value") in the protocol. The Content section contains the data. The format of +the Content section is defined +for each data type. + + +Metadata header: + +~~~~ + Bytes + 0 2 4 6 10 + +-------------+-------------+-------------------+---------------+---- + | INDEX_COUNT | KEY_SIZE_0 | VALUE_ENCODING_0 | VALUE_SIZE_0 | ... + +-------------+-------------+-------------------+---------------+---- + |<-------------- Metadata 0 --------------------->| + + + 10 12 14 18 + ----+-------------+-------------------+---------------+---- + ... | KEY_SIZE_1 | VALUE_ENCODING_1 | VALUE_SIZE_1 | ... + ----+-------------+-------------------+---------------+---- + |<--------------- Metadata 1 -------------------->| + + INDEX_COUNT*8+2 + ----+-------------+-------------------+---------------+ + ... |KEY_SIZE_N-1 |VALUE_ENCODING_N-1 |VALUE_SIZE_N-1 | + ----+-------------+-------------------+---------------+ + |<----------Metadata N-1 (=INDEX_COUNT-1)-------->| +~~~~ + +Metadata body: + +~~~~ + Bytes + +--------+---------+--------+----------+---- ----+--------+-----------+ + | KEY_0 | VALUE_0 | KEY_1 | VALUE_1 | ... |KEY_N-1 | VALUE_N-1 | + +--------+---------+--------+----------+---- ----+--------+-----------+ + |<-- Metadata 0 -->|<-- Metadata 1 --->| |<-- Metadata N-1 -->| +~~~~ + +Please refer to the [Header](header.md) pages for the detailed format of +the Header, Extended Header, and Meta-Data sections. + + +Content +======= + +The Content section contains the actual message data such as transforms, +images, strings, etc. The format of the Content section depends on the +type of the message, and it is specified in the TYPE section in the message +header. + +Whlie the OpenIGTLink protocol allows application developers to define +and use their own data types, it also provides a number of standard message +types listed below. Application developers should not use the type names of +these standard types for their own message types, because the receiver +programs are expected to de-serialize the Content section according to the +standard format. + +Message types inherited from version 1 +-------------------------------------- + +* [CAPABILITY](/Documents/Protocol/capability.md) +* [IMAGE](/Documents/Protocol/image.md) +* [POSITION](/Documents/Protocol/position.md) (alias of QTRANS) +* [QTRANS](/Documents/Protocol/qtransform.md) (formerly POSITION) +* [STATUS](/Documents/Protocol/status.md) +* [TRANSFORM](/Documents/Protocol/transform.md) + +Message types introduced in version 2 +------------------------------------- +* [BIND](/Documents/Protocol/bind.md) +* [COLORT](/Documents/Protocol/colortable.md) +* [IMGMETA](/Documents/Protocol/imagemeta.md) +* [LBMETA](/Documents/Protocol/labelmeta.md) +* [NDARRAY](/Documents/Protocol/ndarray.md) +* [POINT](/Documents/Protocol/point.md) +* [POLYDATA](/Documents/Protocol/polydata.md) +* [QTDATA](/Documents/Protocol/qtrackingdata.md) +* [SENSOR](/Documents/Protocol/sensordata.md) +* [STRING](/Documents/Protocol/string.md) +* [TDATA](/Documents/Protocol/trackingdata.md) +* [TRAJ](/Documents/Protocol/trajectory.md) + +Message types introduced in version 3 +------------------------------------- +* [COMMAND](/Documents/Protocol/command.md) +* [VIDEO](/Documents/Protocol/video.md) +* [VIDEOMETA](/Documents/Protocol/videometa.md) + +Query Mechanism +=============== + +See [Query Mechanism](query.md) for detail. + + +Protocol Compatibility +====================== + +The protocol has been revised several times since the OpenIGTLink protocol was +originally proposed. The current protocol version is Version 3. The differences +among versions 1, 2, and 3 are as follows: + +- Difference between Version 1 and 2 + - [Querying mechanism](query.md) was introduced in Version 2. + - More message types are supported in Version 2. + - The formats of the message types available in both Version 1 and 2 remained unchanged. +- Difference between Version 2 and 3.0 + - The header format was extended in Version 3. + - Version 3 messages consist of 4 sections (Header, Extended Header, Content, + and Metadata), while Version 2 messages consist of 2 sections (Header and Body). + - The formats of the message content remained unchanged. + +All OpenIGTLink interfaces are expected to be backward-compatible, and must be able +to handle older message formats. Older interfaces might not interpret a message +in a newer format, but they are expected to skip the content and continue to +read the following messages. + + +Version Numbers +=============== + +Protocol Version +---------------- + +Starting at Protocol/Library Version 3, we changed the versioning rule +for the protocol version as follows to make it easier to revise the protocol: + +- The protocol version may have a minor version number. +- The major version reflects a major change to the protocol such as: + - Change to the header format + - Major change to the message format + - Adding new rules in the message exchange scheme (e.g. querying) +- The minor version reflects a minior change to the format such as: + - Fixing minor issues of minor format in the prior versions. + - Adding new message types. + +Library Version +--------------- + +The Library's version number consists of major, minor, and patch versions +(e.g. 3.0.1 means major version 3, minor version 0, and revision 1). +Both major and minor versions match the protocol version after the +protocol/library version 3.0. In ealier protocol/header versions (i.e. 1 +and 2), Only the major versions should match the protocol version. + + + + diff --git a/openigtlink/repo/Documents/Protocol/labelmeta.md b/openigtlink/repo/Documents/Protocol/labelmeta.md new file mode 100644 index 0000000..dc909e2 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/labelmeta.md @@ -0,0 +1,61 @@ +[Back to Index](/Documents/Protocol/index.md) + +LabelMeta Message +================= + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +=================== + +The LBMETA is used to transfer meta information for label maps, which are not +available in the IMAGE message type. To retrieve voxel objects or a label map, +GET_IMAGE / IMAGE can be used. But the client should be able to get a list of +available structures. + +Message Types +=================== + +LBMETA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + NAME | char[64] | Name or description of the image + ID | char[20] | ID to query the IMAGE + LABEL | uint8 | Label of the structure (0 if unused) + -- | uint8 | Reserved. + R,G,B,A | uint8[4] | Color in RGBA (0 0 0 0 if no color is defined) + RI, RJ, RK | uint16[3] | Number of pixels in each direction (same as in IMAGE), bounding box of the structure(s) + OWNER_IMAGE | char[20] | ID of the owner image/sliceset. Voxel objects from different slicesets can be sent if slicesets are fused. Can be empty if n/a + + +GET_LBMETA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_LBMETA +------------------- + +N/A + +STP_LBMETA +------------------- + +N/A + +Implementations +=================== + +IMGMETA message type is implemented in the following source code. + +* [igtlLabelMetaMessage.h](/Source/igtlLabelMetaMessage.h) +* [igtlLabelMetaMessage.cxx](/Source/igtlLabelMetaMessage.cxx) + +Contributors +=================== +* Alexander Schaal diff --git a/openigtlink/repo/Documents/Protocol/ndarray.md b/openigtlink/repo/Documents/Protocol/ndarray.md new file mode 100644 index 0000000..720207c --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/ndarray.md @@ -0,0 +1,92 @@ +[Back to Index](/Documents/Protocol/index.md) + +NDArray Message +=============== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +NDARRAY is a data type, which is designed to transfer N-dimensional numerical +array. + + +Message Types +============= + +NDARRAY +------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + SCALAR_TYPE | uint8 | Scalar type (2:int8 3:uint8 4:int16 5:uint16 6:int32 7:uint32 10:float32 11:float64 13:complex float 64*) + DIM | uint8 | Dimension of array + SIZE | uint16[DIM] | Size of array + DATA | ARRAY | Array data. (Must be in the network byte order.) + +* ARRAY is a byte array SCALAR_TYPE[SIZE[0]][SIZE[1]]....[[SIZE[DIM-1]]] +* Complex is a 128-bit variable consisting of a real part in the first 64-bit and an imaginal part in the last 64-bit. + +GET_NDARRAY +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_NDARRAY +------------------- + +N/A + +STP_NDARRAY +------------------- + +N/A + +RTS_NDARRAY +------------------- + +N / A + + +Notes +=================== +Memory layout of DATA field +------------------- +Like multi-dimensional array in C/C++, DATA field is laid out in sequentially in a byte stream. For example, if the value of DATA is defined by: + + char data[3][3] = { {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9} + }; + +The layout in the byte stream can be visualized as follows: + + +-+-+-+-+-+-+-+-+-+ + |1|2|3|4|5|6|7|8|9| + +-+-+-+-+-+-+-+-+-+ + +Implementations +=================== + +The NDARRAY message type is implemented in the following source code. + +* [igtlNDArrayMessage.h](/Source/igtlNDArrayMessage.h) +* [igtlNDArrayMessage.cxx](/Source/igtlNDArrayMessage.cxx) + + +Contributors +=================== + +* Junichi Tokuda +* Yuichiro Hayashi + + + + + + + diff --git a/openigtlink/repo/Documents/Protocol/point.md b/openigtlink/repo/Documents/Protocol/point.md new file mode 100644 index 0000000..dff1be5 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/point.md @@ -0,0 +1,77 @@ +[Back to Index](/Documents/Protocol/index.md) + +Point Message +============= + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +The POINT message type is designed to transfer information about fiducials, +which are often used in surgical planning and navigation in the image-guided +therapy. + +Message Types +============= + +POINT +----- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + POINT_0 | POINT_DATA | Data for point 0 + ... | | + POINT_(N-1) | POINT_DATA | Data for point N-1 + +- POINT_DATA + + Data | Type | Description +--------------|---------------|------------------------------------------------- + NAME | char[64] | Name or description of the point + GROUP | char[32] | Can be "Labeled Point", "Landmark", "Fiducal", ... + R,G,B,A | uint8[4] | Color in RGBA + X,Y,Z | float32[3] | Coordinate of the point in millimeter + DIAMETER | float32 | Diameter of the point in millimeter. Diameter can be 0. + OWNER | char[20] | Id of the owner image/sliceset. Points from different slicesets can be sent if slicesets are fused. + +GET_POINT +--------- + +GET_POINT is used to query for meta data of label data. If the DEVICE_NAME field +in the header is empty, a list of all available point data is returned. + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_POINT +------------------- + +N / A + +STP_POINT +------------------- + +N/A + + +RTS_POINT +------------------- + +N/A + +Implementations +=================== + +IMGMETA message type is implemented in the following source code. + +* [igtlPointMessage.h](/Source/igtlPointMessage.h) +* [igtlPointMessage.cxx](/Source/igtlPointMessage.cxx) + +Contributors +=================== + +* Alexander Schaal + diff --git a/openigtlink/repo/Documents/Protocol/polydata.md b/openigtlink/repo/Documents/Protocol/polydata.md new file mode 100644 index 0000000..e8514fa --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/polydata.md @@ -0,0 +1,195 @@ +[Back to Index](/Documents/Protocol/index.md) + +PolyData Message +================ + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +POLYDATA is used to transfer 3D polygonal data. The message format is designed +based on the [POLY DATA format](http://www.vtk.org/VTK/img/file-formats.pdf) +defined in VTK file format and equivalent to +[VTK's vtkPolyData class](http://noodle.med.yale.edu/vtk5/classvtkPolyData.html). +The message also supports dataset attribute field in VTK, including scalars, +calar_scalars, vectors, vectors, normals, texture coordinates, and tensor, but +not lookup table. + + +Message Types +============= + +POLYDATA +-------- + + Data | Type | Description +----------------------|--------------|------------------------------------------ + NPOINTS | uint32 | Number of points + NVERTICES | uint32 | Number of vertices + SIZE_VERTICES | uint32 | Total size of vertices data + NLINES | uint32 | Number of lines + SIZE_LINES | uint32 | Total size of line data + NPOLYGONS | uint32 | Number of polygons + SIZE_POLYGONS | uint32 | Total size of polygon data + NTRIANGLE_STRIPS | uint32 | Number of triangle strips + SIZE_TRIANGLE_STRIPS | uint32 | Total size of triangle strips data + NATTRIBUTES | uint32 | Number of dataset attributes + POINTS | POINTS | Coordinates of point 0 - (NPOINTS-1) + VERTICES | STRUCT_ARRAY | Array of vertices + LINES | STRUCT_ARRAY | Array of lines + POLYGONS | STRUCT_ARRAY | Array of polygons + TRIANGLE_STRIPS | STRUCT_ARRAY | Array of triangle strips + ATTRIBUTES | ATTRIBUTES | Attributes + + +- POINTS + + Data | Type | Description +--------------|---------------|------------------------------------------------- + P0X,P0Y,P0Z | float32[3] | Coordinates for point 0 + ... | ... | ... + P(NPOINTS-1)X,P(NPOINTS-1)Y,P(NPOINTS-1)Z | float32[3] | Coordinates for point (NPOINTS-1) + + +- STRUCT_ARRAY + +STRUCT_ARRAY contains an array of point indices that represent a geometric +structure, including vertices, lines, polygons, and triangle strips. +The number of structures (N_STRUCT) are specified by either NVERTICES, NLINES, +NPOLYGONS, or NTRIANGLE_STRIPS (see the table above). + + Data | Type | Description +--------------------------|--------------|--------------------------------------- + STRUCT_0 | POINT_INDICES| Point indices for 0th structure + ... | ... | ... + STRUCT_(N_STRUCT-1) | POINT_INDICES| Point indices for N_STRUCT-1 th structure + +- POINT_INDICES + + Data | Type | Description +--------------------------|-------------|--------------------------------------- + NINDICES | uint32 | Number of point indices + POINT_INDEX_0 | uint32 | Index for point #0 + ... | ... | + POINT_INDEX_(NINDICES-1) | uint32 | Index for point # (NINDICES - 1) + + +- ATTRIBUTES + + Data | Type | Description +-------------------------|----------------|---------------------------------------- + ATTRIBUTE_HEADER |ATTRIBUTE_HEADER| Attribute header + ATTRIBUTE_NAMES | ATTRIBUTE_NAMES| List of attribute names + ATTRIBUTE_0 | ATTRIBUTE_DATA | Data for attribute #0 + ... | ... | ... + ATTRIBUTE_(NATTRIBUTE-1)| ATTRIBUTE_DATA | Data for attribute #(NATTRIBUTE-1) + + +- ATTRIBUTE_HEADER + + Data | Type | Description +----------------------|---------------|------------------------------------------ + TYPE_ATTRIBUTE_0 | uint16 | Type of dataset attribute #0 (including number of components for scalar type) + NATTRIBUTE_0 | uint32 | Number of data for attribute #0 + ... | ... | ... + ... | ... | ... + TYPE_ATTRIBUTE(NATTRIBUTES-1)| uint16| Type of dataset attribute #(NATTRIBUTES-1) + NATTRIBUTE(NATTRIBUTES-1)| uint32 | Number of data for attribute #(NATTRIBUTES-1) + + +- ATTRIBUTE_NAMES + + Data | Type | Description +----------------------|---------------|------------------------------------------ + NAME_ATTRIBUTE_0 | char[] | Name of attribute 0 + (null) | char | (null) + ... | ... | ... + ... | ... | ... + NAME_ATTRIBUTE_(NATTRIBUTES-1)| char[] | Name of attribute (NATTRIBUTES-1) + (null) | char | (null) + Padding | (int8) NULL | Padding (inserted to make the size of ATTRIBUTE_NAMES even) + + +- ATTRIBUTE_DATA + + Data | Type | Description +------|-------------------------------|------------------------------------------ + DATA | float32[NATTRIBUTE_0][NCOMP] | Attribute data + ... | ... | + DATA | float32[NATTRIBUTE_(NATTRIBUTES-1)][NCOMP] | Attribute data + + +* Values for TYPE_ATTRIBUTE (16-bit) + * 0-7 bit: Attribute Type: + * 0x00: POINT_DATA / Scalars + * 0x01: POINT_DATA / Vectors + * 0x02: POINT_DATA / Normals + * 0x03: POINT_DATA / Tensors + * 0x04: POINT_DATA / RGBA + * 0x10: CELL_DATA / Scalars + * 0x11: CELL_DATA / Vectors + * 0x12: CELL_DATA / Normals + * 0x13: CELL_DATA / Tensors + * 0x14: CELL_DATA / RGBA + * 8-15 bit: Number of components -- must be 3 for Vectors and Normal, 9 for Tensor, 4 for RGBA. +* Maximum length for attribute name is 255 +* If there are a pair of scalar and RGBA data with the same name and type (either POINT or CELL), those are used as scalar values and a look up table. + * elements in RGBA data must be in the rage of \[0.0, 1.0\] + +GET_POLYDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +STT_POLYDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +or + + Data | Type | Description +--------------|---------------|------------------------------------------------- + RESOL | uint64 | Minimum interval between message (ns)* + +See [Time Stamp](timestamp.md) + + +STP_POLYDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +RTS_POLYDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + STATUS | uint8 | 0: Success; 1: Error + + +Implementations +=================== + +* [igtlPolyDataMessage.h](/Source/igtlPolyDataMessage.h) +* [igtlPolyDataMessage.cxx](/Source/igtlPolyDataMessage.cxx) + + + + + + + + + + diff --git a/openigtlink/repo/Documents/Protocol/position.md b/openigtlink/repo/Documents/Protocol/position.md new file mode 100644 index 0000000..fbfe440 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/position.md @@ -0,0 +1,74 @@ +[Back to Index](/Documents/Protocol/index.md) + +Position Message +================ + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + + +Summary +======= + +The POSITION message type is used to transfer position and orientation +information. The data are a combination of three-dimensional vector for the position +and quaternion for the orientation. Although equivalent position and orientation +can be described with the TRANSFORM data type, the POSITION data type has the +advantage of smaller data size (19%). It is, therefore, more suitable for pushing +high frame-rate data from tracking devices. + +Message Types +============= + +POSITION +-------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + X | float32 | X position in millimeter + Y | float32 | Y position in millimeter + Z | float32 | Z position in millimeter + OX | float32 | X element in quaternion + OY | float32 | Y element in quaternion + OZ | float32 | Z element in quaternion + W | float32 | W element in quaternion + +GET_POSITION +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_POSITION +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STP_POSITION +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +RTS_POSITION +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + STATUS | uint8 | 0: Success; 1: Error + + +Implementations +=================== + +* [igtlPositionMessage.h](/Source/igtlPositionMessage.h) +* [igtlPositionMessage.cxx](/Source/igtlPositionMessage.cxx) + +Contributors +=================== + +* Junichi Tokuda diff --git a/openigtlink/repo/Documents/Protocol/qtrackingdata.md b/openigtlink/repo/Documents/Protocol/qtrackingdata.md new file mode 100644 index 0000000..044f65b --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/qtrackingdata.md @@ -0,0 +1,92 @@ +[Back to Index](/Documents/Protocol/index.md) + +QuaternionTrackingData Message +============================== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +=================== + +The QTDATA message type is intended for transferring 3D positions of surgical +tools, markers etc. Its role is almost identical to TDATA, except that QTDATA +describes orientation by using quaternion. + +Message Types +=================== + +QTDATA +------------------- + + Data | Type | Description +---------------|---------------|------------------------------------------------- + NAME_0 | char[20] | Name (=Id) of the instrument/tracker # 0 + TYPE_0 | uint8 | Type of instrument for #0 + (--) | uint8 | Researved + POSITION_0 | float32[3] | (X, Y, Z) + QUATERNION_0 | float32[4] |Quaternion (QX, QY, QZ, W) + ... | ... | ... + NAME_(N-1) | char[20] | Name (=Id) of the instrument/tracker + TYPE_(N-1) | uint8 | Type of instrument for #0 + (--) | uint8 | Reserved + POSITION_(N-1)| float32[3] | (X, Y, Z) + QUATERNION_(N-1)| float32[4] | Quaternion (QX, QY, QZ, W) + +- TYPE_X should be one of the followings: + - 1: tracker + - 2: 6D instrument (regular instrument) + - 3: 3D instrument (only tip of the instrument defined) + - 4: 5D instrument (tip and handle are defined, but not the normal vector) + +GET_QTDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_QTDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + STATUS | uint8 | 0: Success; 1: Error + RESOL | uint32 | Minimum time between two frames. Use 0 for as fast as possible. If e.g. 50 ms is specified, the maximum update rate will be 20 Hz. + COORD_NAME | char[32] | Name of coordinate system to use. Can be empty for default coordinate system. (not included if action = 2) + + +STP_QTDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +RTS_QDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + STATUS | uint8 | 0: Success; 1: Error + + +Implementations +=================== + +* [igtlQuaternionTrackingDataMessage.h](/Source/igtlQuaternionTrackingDataMessage.h) +* [igtlQuaternionTrackingDataMessage.cxx](/Source/igtlQuaternionTrackingDataMessage.cxx) + +Contributors +=================== + +* Alexander Schaal + + + + + + + + diff --git a/openigtlink/repo/Documents/Protocol/qtransform.md b/openigtlink/repo/Documents/Protocol/qtransform.md new file mode 100644 index 0000000..3fa093a --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/qtransform.md @@ -0,0 +1,74 @@ +[Back to Index](/Documents/Protocol/index.md) + +QuaternionTransform Message +=========================== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +The QTRANS data type is used to transfer position and orientation information. +The data are a combination of three-dimensional vector for the position and +quaternion for the orientation. Although equivalent position and orientation can +be described with the TRANSFORM data type, the QTRANS data type has the +advantage of smaller data size (19%). It is, therefore, more suitable for pushing +high frame-rate data from tracking devices. + +Message Types +============= + +QTRANS +------ + + Data | Type | Description +--------------|---------------|------------------------------------------------- + X | float32 | X position in millimeter + Y | float32 | Y position in millimeter + Z | float32 | Z position in millimeter + OX | float32 | X element in quaternion + OY | float32 | Y element in quaternion + OZ | float32 | Z element in quaternion + W | float32 | W element in quaternion + +GET_QTRANS +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_QTRANS +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STP_QTRANS +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +RTS_QTRANS +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + STATUS | uint8 | 0: Success; 1: Error + + +Implementations +=================== + +* [igtlPositionMessage.h](/Source/igtlPositionMessage.h) +* [igtlPositionMessage.cxx](/Source/igtlPositionMessage.cxx) + + +Contributors +=================== +Junichi Tokuda + diff --git a/openigtlink/repo/Documents/Protocol/query.md b/openigtlink/repo/Documents/Protocol/query.md new file mode 100644 index 0000000..942eb89 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/query.md @@ -0,0 +1,58 @@ +[Back to Index](/Documents/Protocol/index.md) + +Query Message +============= + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Simple Querying Mechanism +========================= + +In OpenIGTLink version 2, special prefixes GET_, STT_, STP_, and RTS_ are used +in the message type field in the header for messages to query and control data +flow. Those messages with those special prefix should be defined along with +primary message types (for example, STT_TDATA, STP_TDATA and RTS_TDATA should +be defined with TDATA). + +GET_ prefix: Query a single message +=================================== + +"GET_<datatype>" query message is used to request for a single message +with type <datatype>. The receiver of "GET_<datatype>" message must +return a message with type <datatype> and the same name as the query +message. A "GET_<datatype>" message without device name requests any +available data. If data is not available, a returned message must be null body +(data size = 0). A format of "GET_<datatype>" may be defined per data type, +if necessary. + +STT_ and STP_ prefixes: Control data flow +========================================= + +"STT_<datatype>" and "STP_<datatype>" query message is used to +request to start and stop sending a series of messages. The receiver of +"STT_<datatype>" or "STP_<datatype>" message must return +"RTS_<datatype>" message with the same name as the query message +to notify that the receiver receives the query. Formats of "STT_<datatype>", +"STP_<datatype>" and "RTS_<datatype>" may be defined per data type, +if necessary. + +Available Message Type (Including sub-types) +============================================ + +Type name | GET query | STT query | STP query | RTS message | Description +----------|-------------|-------------|-------------|--------------|-------------------------------------- +IMAGE | GET_IMAGE | STT_IMAGE | STP_IMAGE | RTS_IMAGE | 2D/3D image data +TRANSFORM | GET_TRANSFOR| STT_TRANSFOR| STP_TRANSFOR| RTS_TRANSFOR | Affine transform data. +POSITION | GET_POSITION| STT_POSITION| STP_POSITION| RTS_POSITION | Position and orientation (quaternion) +CAPABILITY| GET_CAPABIL | -- | -- | RTS_CAPABIL | Points or fiducials. +STATUS | GET_STATUS | -- | -- | RTS_STATUS | Device status +TDATA | GET_TDATA | STT_TDATA | STP_TDATA | RTS_TDATA | Tracking data +IMGMETA | GET_IMGMETA | -- | -- | RTS_IMGMETA | List of image meta data including patient name, ID (medical record number), size, etc. +LBMETA | GET_LBMETA | -- | -- | RTS_LBMETA | List of label meta data. +POINT | GET_POINT | -- | -- | RTS_POINT | Points or fiducials. +TRAJ | GET_TRAJ | -- | -- | RTS_TRAJ | Trajectory data (needle path etc.) +NDARRAY | GET_NDARRAY | STT_NDARRAY | STP_NDARRAY | RTS_NDARRAY | Associative array to transfer a set of values with key names. +COMMAND | -- | -- | -- | RTS_COMMAND | Command + + diff --git a/openigtlink/repo/Documents/Protocol/sensordata.md b/openigtlink/repo/Documents/Protocol/sensordata.md new file mode 100644 index 0000000..6b4f51c --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/sensordata.md @@ -0,0 +1,112 @@ +[Back to Index](/Documents/Protocol/index.md) + +SensorData Message +================== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +SENSOR is a message type, which is used to transfer sensor reading, 3-axis +position, velocity, acceleration, angle, angle velocity and angle acceleration. +The message format is intended for manipulator control and various types of +sensors. + +Message Types +=================== + +SENSOR +------------------- + + Data | Type | Description +--------------|----------------|------------------------------------------------- + LARRAY | uint8 | Length of array (0-255) + STATUS | uint8 | Sensor status (Reserved) + UNIT | uint64 | See [64-bit UNIT field](unit.md). + DATA | float64[LARRAY]| value array for sensor 0 + + +GET_SENSOR +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +STT_SENSOR +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +or + + Data | Type | Description +--------------|---------------|------------------------------------------------- + STATUS | uint8 | 0: Success; 1: Error + + +STP_SENSOR +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +RTS_SENSOR +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + STATUS | uint8 | 0: Success; 1: Error + + +Implementations +=================== + +* [igtlSensorMessage.h](/Source/igtlSensorMessage.h) +* [igtlSensorMessage.cxx](/Source/igtlSensorMessage.cxx) + +Contributors +=================== + +* Junichi Tokuda +* Yuichiro Hayashi + +Examples +=================== + +Sending 3-axis troque +--------------------- + +A device with 3-axis torque (N\*m) sensor is sending data to a data logger +program. The following table shows example data format to send 3-axis torque: + + Data | Type | Contents +--------------|---------------|------------------------------------------------- + LARRAY | uint8 | 3 + STATUS | uint8 | 0 + UNIT | uint64 | 00000010 11000000 00010000 00000000 00000000 00000000 00000000 00000000 + DATA | float64[3] | {0.0, 0.0, 0.0} + + +Sending 3-axis force, troque and acceleration +--------------------------------------------- + +By binding SENSOR data using BIND type, values from multiple types of sensors +can be transferred simultaneously. See [BIND](bind.md) message description page +for detail. + + + + + + + + + diff --git a/openigtlink/repo/Documents/Protocol/status.md b/openigtlink/repo/Documents/Protocol/status.md new file mode 100644 index 0000000..847da8b --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/status.md @@ -0,0 +1,91 @@ +[Back to Index](/Documents/Protocol/index.md) + +Status Message +============== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +The STATUS data type is used to notify the receiver about the current status of +the sender. The data consist of status code in a 16-bit unsigned integer, sub- +code in a 64-bit integer, error name in a 20-byte-length character string, and a +status message. The length of the status message is determined by the size +information in the general header. The status code is defined as a part of the +OpenIGTLink protocol specification listed bellow. The sub-code is device +specific and is defined by developers. In addition, developers can build their +own error name/code into the status message and additional optional description +in the following data field. + + +Message Types +============= + +STATUS +------ + + Data | Type | Description +------------|---------------|--------------------------------------------------- + C | uint16 | Status code groups: 1-Ok, 2-Generic Error, ... (see below) + SUB_CODE | int64 | Sub-code for the error (ex. 0x200 - file not found) + ERROR_NAME | char[20] | "Error", "OK", "Warning" - can be anything, don't relay on this + MESSAGE | char[BODY_SIZE-30]| Optional (English) description (ex. "File C:\test.ini not found") + +Status codes: +------------------- + +- 00: Invalid packet - 0 is not used +- 01: OK (Default status) +- 02: Unknown error +- 03: Panic mode (emergency) +- 04: Not found (file, configuration, device etc) +- 05: Access denied +- 06: Busy +- 07: Time out / Connection lost +- 08: Overflow / Can't be reached +- 09: Checksum error +- 10: Configuration error +- 11: Not enough resource (memory, storage etc) +- 12: Illegal/Unknown instruction (or feature not implemented / Unknown command received) +- 13: Device not ready (starting up) +- 14: Manual mode (device does not accept commands) +- 15: Device disabled +- 16: Device not present +- 17: Device version not known +- 18: Hardware failure +- 19: Exiting / shut down in progress + +GET_STATUS +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_STATUS +------------------- + +N/A + +STP_STATUS +------------------- + +N/A + +RTS_STATUS +------------------- + +N/A + +Implementations +=================== + +* [igtlStatusMessage.h](/Source/igtlStatusMessage.h) +* [igtlStatusMessage.cxx](/Source/igtlStatusMessage.cxx) + +Contributors +=================== + +* Junichi Tokuda diff --git a/openigtlink/repo/Documents/Protocol/string.md b/openigtlink/repo/Documents/Protocol/string.md new file mode 100644 index 0000000..2e03c5b --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/string.md @@ -0,0 +1,72 @@ +[Back to Index](/Documents/Protocol/index.md) + +String Message +============== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + + +Summary +======= + +The STRING message type is used for transferring a character string. It supports +character strings up to 65535 bytes. + +Message Types +============= + +STRING +------ + + Data | Type | Description +--------------|---------------|------------------------------------------------- + ENCODING | uint16 | Character encoding type as MIBenum value. Default=3. + LENGTH | uint16 | Length of string (bytes) + STRING | uint8[LENGTH] | Byte array of the string + +* For MIBenum character encoding, please refer [IANA Character Sets](http://www.iana.org/assignments/character-sets). US-ASCII (ANSI-X3.4-1968; MIBenum = 3) is strongly recommended. + +GET_STRING +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_STRING +------------------- + +N/A + +STP_STRING +------------------- + +N/A + + +RTS_STRING +------------------- + +N/A + +Implementations +=================== + +The TDATA message type is implemented in the following source code. + +* [igtlStringMessage.h](/Source/igtlStringMessage.h) +* [igtlStringMessage.cxx](/Source/igtlStringMessage.cxx) + +Contributors +=================== + +* Junichi Tokuda + + + + + + + + diff --git a/openigtlink/repo/Documents/Protocol/summary.md b/openigtlink/repo/Documents/Protocol/summary.md new file mode 100644 index 0000000..e226c6c --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/summary.md @@ -0,0 +1,175 @@ +[Back to Index](/Documents/Protocol/index.md) + +OpenIGTLink Protocol Summary +============================ + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + + +Overview +=================== + +The OpenIGTLink Protocol is ideal for building a research prototype system, because of its simple and standardized specification that requires less effort on design and development of communication mechanism for systems integration. By using OpenIGTLink, developers can save their time for more essential part of research. The OpenIGTLink's simple specification has been well accepted by the community, resulting a number of applications in the IGT research community, since it's initial release in early 2008. + +While we keep the protocol as simple as possible, it is also important to support as many IGT devices as possible to maximize the connectivity among software and devices, which potentially frees the developers from tedious coding just for system integration. There have been a number of feature requests that would benefit many IGT research projects, such as connectivity with commercial products, and connectivity with other major research tools, such as MATLAB. To respond to those request, and to increase the number of potential applications, we decided review the requests and release version 2 protocol during NA-MIC Summer Project Week 2010. The new protocol defines a set of new message types with new querying scheme, while maintaining a backward compatibility with version 1. This page summarizes the features in version 2. + +Simple Query Scheme +=================== + +OpenIGTLink V.2 defines a simple querying scheme on top of the existing message format, by introducing a few prefix to the device type field. + +Request a single message +=================== + +A client can request to send data contained in a single message, by issuing a query message with a device type string starting with "GET_". If specified data is not available, a message with a device type string starting with "RTS_" is returned. For example, when a client requests an IMAGE message to a server, it sends GET_IMAGE message to the server as a query. If the image exist, an IMAGE message is returned from the server to the client. Otherwise, a RTS_IMAGE message with error code is returned. + +Request a stream of messages (introduced in version 2) +=================== + +A client can start and stop data streaming (sent as a series of messages) from a server, by issuing a query message with a device type starting with "STT_" and "STP_" respectively. If data requested by a "STT_" message is not available, the server returns a message with a device type string starting with "RTS_" prefix. A STP_ message is also acknowledged by a "RTS_" message. + +This is useful to start and stop position tracking or real-time imaging remotely from the client. For example, once the server receives "STT_TDATA" message from the client, it start sending "TDATA" messages to the client. The server keep sending "TDATA" messages until it receives "STP_TDATA" from the client. + +New message types +=================== + +The following tables show lists of message types available in version 2. + +New Messages for image-guided systems +------------------- + + + + + + + + + + + + + + +
Type name +GET query +STT query +STP query +RTS message +Description +
TDATA +GET_TDATA +STT_TDATA +STP_TDATA +RTS_TDATA +Tracking data +
IMGMETA +GET_IMGMETA +-- +-- +RTS_IMGMETA +List of image meta data including patient name, ID (medical record number), size, etc. +
LBMETA +GET_LBMETA +-- +-- +RTS_LBMETA +List of label meta data. +
POINT +GET_POINT +-- +-- +RTS_POINT +Points or fiducials. +
TRAJ +GET_TRAJ +-- +-- +RTS_TRAJ +Trajectory data (needle path etc.) +
+ + +New Messages for general applications +------------------- + + + + + +
Type name +GET query +STT query +STP query +RTS message +Description +
NDARRAY +GET_NDARRAY +STT_NDARRAY +STP_NDARRAY +RTS_NDARRAY +Associative array to transfer a set of values with key names. +
+ + +Messages from version 1 +------------------- + + + + + + + + + + + + + +
Type name +GET query +STT query +STP query +RTS message +Description +
IMAGE +GET_IMAGE +STT_IMAGE +STP_IMAGE +RTS_IMAGE +2D/3D image data +
TRANSFORM +GET_TRANSFOR +STT_TRANSFOR +STP_TRANSFOR +RTS_TRANSFOR +Affine transform data. +
POSITION +GET_POSITION +STT_POSITION +STP_POSITION +RTS_POSITION +Position and orientation (quaternion) +
CAPABILITY +GET_CAPABIL +-- +-- +RTS_CAPABIL +Points or fiducials. +
STATUS +GET_STATUS +-- +-- +RTS_STATUS +Device status +
+ + + + + + + + diff --git a/openigtlink/repo/Documents/Protocol/timestamp.md b/openigtlink/repo/Documents/Protocol/timestamp.md new file mode 100644 index 0000000..be84259 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/timestamp.md @@ -0,0 +1,37 @@ +[Back to Index](/Documents/Protocol/index.md) + +Time Stamp Field in Header +========================== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + + +Timestamp field summary +=================== + +* *Big Endian format:* bits numbered in big-endian fashion from 0 starting at the left, or high-order, position. +* *Seconds and fraction of seconds:* timestamps are represented as a 64-bit unsigned fixed-point number, in seconds relative to 00:00:00 January 1, 1970, UTC. The integer part is in the first 32 bits (Unix-style timestamp) and the fraction part in the last 32 bits. In the fraction part, the non-significant low order can be set to 0. +* *Wrap around:* The first 32-bit field will overflow some time in 2106 (second 4,294,967,296) + +Obtaining timestamp +=================== +* [itk::RealTimeClock](http://www.itk.org/Doxygen34/html/classitk_1_1RealTimeClock.html) +* *Linux* / *Mac*: [ftime()](http://man7.org/linux/man-pages/man3/ftime.3.html) +* *Windows*: [ftime() - 10 ms resolution](http://msdn.microsoft.com/en-us/library/z54t9z5f.aspx) + * *Old Timestamp* - 1 sec resoultion: Now, [Time](http://msdn2.microsoft.com/en-us/library/1f4c8f33.aspx), Timer + * *System time* - 10 msec resolution: GetTickCount, [GetTickCount64](http://msdn2.microsoft.com/en-us/library/ms724411.aspx) or [timeGetTime()](http://msdn2.microsoft.com/en-us/library/ms713418.aspx) + * *Highres* - hardware dependent: [QueryPerformanceCounter](http://msdn2.microsoft.com/en-us/library/ms644904.aspx) (Intel IA32 instruction: [RDTSC](http://www.intel.com/design/pentium4/manuals/245471.htm)) + +Time synchronization +=================== +Two solutions: +0. Install NTP on all devices +0. Compute timestamp differences (local NTP can be used) + +Resources +=================== +* NTP4 Timestamp: [RFC 2030](http://www.faqs.org/rfcs/rfc2030.html) and [RFC 1305](http://www.faqs.org/rfcs/rfc1305.html). (See "3. NTP Timestamp Format") +* [Obtaining Accurate Timestamps under Windows XP](http://www.lochan.org/2005/keith-cl/useful/win32time.html) + + diff --git a/openigtlink/repo/Documents/Protocol/trackingdata.md b/openigtlink/repo/Documents/Protocol/trackingdata.md new file mode 100644 index 0000000..1bd7102 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/trackingdata.md @@ -0,0 +1,102 @@ +[Back to Index](/Documents/Protocol/index.md) + +TrackingData Message +==================== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + + +Summary +======= + +The TDATA message type is intended for transferring 3D positions of surgical +tools, markers etc. Those positions are often measured by the optical, +electromagnetic, or other types of 3D position sensor continuously and transferred +as series of messages. Since it is important for software that receives TDATA to +control data flow, STT_TDATA query data type has interval field to control the +frame rate of consecutive messages. + + +Message Types +============= + +TDATA +----- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + NAME_0 | char[20] | Name (=Id) of the instrument/tracker # 0 + TYPE_0 | uint8 | Type of instrument for #0 + (--) | uint8 | Researved + MATRIX_0 | float32[12] | Upper 3 rows of 4x4 transform matrix + ... | ... | ... + NAME_(N-1) | char[20] | Name (=Id) of the instrument/tracker + TYPE_(N-1) | uint8 | Type of instrument for # (N-1) + (--) | uint8 | Reserved + MATRIX_(N-1) | float32[12] | Upper 3 rows of 4x4 transform matrix + +- TYPE_X should be one of the followings: + - 1: tracker + - 2: 6D instrument (regular instrument) + - 3: 3D instrument (only tip of the instrument defined) + - 4: 5D instrument (tip and handle are defined, but not the normal vector) +- MATRIX follows the TRANSFORM message format. See [TRANSFORM message](transform.md). + + +GET_TDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_TDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + RESOL | uint32 | Minimum time between two frames. Use 0 for as fast as possible. If e.g. 50 ms is specified, the maximum update rate will be 20 Hz. + COORD_NAME | char[32] | Name of coordinate system to use. Can be empty for default coordinate system. (not included if action = 2) + +* All tracking data from one frame is included. +* Invisible/unavailable trackers/instruments are not included. +* Easy to develop. Sample pseudo code: while(true) { recv(trackingdata); updateView(trackingdata); } +* Usually the tracking data will be sent using the standard coordinate system, which is also used for POINT, IMAGE, ... But this does only work after patient registration. Therefore the body of START_PUSH has an optional field for specifing the coordinate system "CAMERA". To switch back to the standard coordinate system, one has to send STOP_PUSH and afterwards START_PUSH without explicitly specifing the camera coordinate system. + +STP_TDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +RTS_TDATA +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + STATUS | uint8 | 0: Success; 1: Error + + +Implementations +=================== + +* [igtlTrackingDataMessage.h](/Source/igtlTrackingDataMessage.h) +* [igtlTrackingDataMessage.cxx](/Source/igtlTrackingDataMessage.cxx) + +Contributors +=================== + +* Alexander Schaal + + + + + + + + + + + diff --git a/openigtlink/repo/Documents/Protocol/trajectory.md b/openigtlink/repo/Documents/Protocol/trajectory.md new file mode 100644 index 0000000..de64673 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/trajectory.md @@ -0,0 +1,68 @@ +[Back to Index](/Documents/Protocol/index.md) + +Trajectory Message +================== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +The TRAJECTORY message type support to transfer information about 3D trajectory, +which is often used for surgical planning and guidance in image-guided therapy. + +Message Types +============= + +TRAJ +---- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + NAME | char[64] | Name or description of the trajectory. + GROUP_NAME | char[32] | Can be "Trajectory", ... + TYPE | uint8 | 1: trajectory with only entry point, 2: trajectory with only target point, 3: trajectory with entry and target point + Reserved | uint8 | Reserved + R,G,B,A | uint8[4] | Color in RGBA + X1,Y1,Z1 | float32[3] | Entry point of the trajectory + X2,Y2,Z2 | float32[3] | Target point of a trajectory + DIAMETER | float32 | Diameter of trajectory, can be 0 + OWNER_IMAGE | char[20] | Id of the owner image/sliceset. Trajectories from different slicesets can be sent if slicesets are fused. + +GET_TRAJ +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_TRAJ +------------------- + +N/A + +STP_TRAJ +------------------- + +N/A + + +Implementations +=================== + +* [igtlTrajectoryMessage.h](/Source/igtlTrajectoryMessage.h) +* [igtlTrajectoryMessage.cxx](/Source/igtlTrajectoryMessage.cxx) + + +Contributors +=================== + +* Alexander Schaal + + + + + + + diff --git a/openigtlink/repo/Documents/Protocol/transform.md b/openigtlink/repo/Documents/Protocol/transform.md new file mode 100644 index 0000000..ad275e7 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/transform.md @@ -0,0 +1,82 @@ +[Back to Index](/Documents/Protocol/index.md) + +Transform Message +================= + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +The TRANSFORM data type is used to transfer a homogeneous linear transformation +in 4-by-4 matrix form. One such matrix was shown earlier in equation (1). Note +that if a device is sending only translation and rotation, then TRANSFORM is +equivalent to POSITION. But TRANSFORM can also be used to transfer affine +transformations or simple scaling. Like IMAGE and POSITION, TRANSFORM carries +information about the coordinate system used. + +Message Types +============= + +TRANSFORM +--------- + +The message contains the elements for the upper 3 rows of 4x4 linear transform matrix. + + Data | Type | Description +--------------|---------------|------------------------------------------------- + R11 | float32 | Element (1, 1) + R21 | float32 | Element (2, 1) + R31 | float32 | Element (3, 1) + R12 | float32 | Element (1, 2) + R22 | float32 | Element (2, 2) + R32 | float32 | Element (3, 2) + R13 | float32 | Element (1, 3) + R23 | float32 | Element (2, 3) + R33 | float32 | Element (3, 3) + TX | float32 | Element (1, 4) (translation along x-axis in millimeter) + TY | float32 | Element (2, 4) (translation along y-axis in millimeter) + TZ | float32 | Element (3, 4) (translation along z-axisin millimeter) + + +GET_TRANS +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +STT_TRANS +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +STP_TRANS +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + + +RTS_TRANS +------------------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + STATUS | uint8 | 0: Success; 1: Error + + +Implementations +=================== +* [igtlTransformMessage.h](/Source/igtlTransformMessage.h) +* [igtlTransformMessage.cxx](/Source/igtlTransformMessage.cxx) + +Contributors +=================== +* Junichi Tokuda diff --git a/openigtlink/repo/Documents/Protocol/unit.md b/openigtlink/repo/Documents/Protocol/unit.md new file mode 100644 index 0000000..e039c59 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/unit.md @@ -0,0 +1,111 @@ +[Back to Index](/Documents/Protocol/index.md) + +UNIT Field for SENSOR Message +============================= + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + +Summary +======= + +SENSOR message can handle a part of units defined in The International System +of Unites (SI) in its 8-byte (or 64-bit) field. The field is designed to +specify a unit consisting of SI-prefix (e.g. milli, micro, kilo etc...) and +a combination of SI-base and/or SI-derived units. The bites in the field are +assigned as follows: + +~~~~ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-... + |PREFIX | UNIT0 | EXP0 | UNIT1 | EXP1 | UNIT2 | EXP2 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-... + 0 1 2 3 4 + + ...-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + EXP2 | UNIT3 | EXP3 | UNIT4 | EXP4 | UNIT5 | EXP5 | + ...-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 4 5 6 7 +~~~~ + +PREFIX (4bit) +------------- + + Value | SI-Prefix +--------------|----------------- + 0x0 | None + 0x1 | deka (deca)(1e1) + 0x2 | hecto (1e2) + 0x3 | kilo (1e3) + 0x4 | mega (1e6) + 0x5 | giga (1e9) + 0x6 | tera (1e12) + 0x7 | peta (1e15) + -- | -- + 0x9 | deci (1e-1) + 0xA | centi (1e-2) + 0xB | milli (1e-3) + 0xC | micro (1e-6) + 0XD | nano (1e-9) + 0XE | pico (1e-12) + 0XF | femto (1e-15) + +UNIT(6bit) +---------- + +- SI Base Units + + Value | SI Base Unit Name +--------------|------------------- + 0x01 | meter + 0x02 | gram + 0x03 | second + 0x04 | ampere + 0x05 | kelvin + 0x06 | mole + 0x07 | candela + + +- SI-Derived Units + + Value | Unit Name | Dimension +--------------|-----------------|--------------------------- + 0x08 | radian | meter/meter + 0x09 | steradian | meter^2/meter^2 + 0x0A | hertz | /second + 0x0B | newton | meter-kilogram/second^2 + 0x0C | pascal | kilogram/meter-second^2 + 0x0D | joule | meter^2-kilogram/second^2 + 0x0E | watt | meter^2-kilogram/second^3 + 0x0F | coulomb | second-ampere + 0x10 | volt | meter^2-kilogram/second^3-ampere + 0x11 | farad | second^4-ampere^2/meter^2-kilogram + 0x12 | ohm | meter^2-kilogram/second^3-ampere^2 + 0x13 | siemens | second^3-ampere^2/meter^2-kilogram + 0x14 | weber | meter^2-kilogram/second^2-ampere + 0x15 | tesla | kilogram/second^2-ampere + 0x16 | henry | meter^2-kilogram/second^2-ampere^2 + 0x17 | lumen | candela-steradian + 0x18 | lux | candela-steradian/meter^2 + 0x19 | becquerel | /second + 0x1A | gray | meter^2/second^2 + 0x1B | sievert | meter^2/second^2 + +- EXP (4-bit) + + Value | Exponent +--------------|--------------- + 0x0 | ^0 + 0x1 | ^1 + 0x2 | ^2 + 0x3 | ^3 + 0x4 | ^4 + 0x5 | ^5 + 0x6 | ^6 + 0x7 | ^7 + -- | -- + 0xF | ^-1 + 0xE | ^-2 + 0xD | ^-3 + 0xC | ^-4 + 0XB | ^-5 + 0XA | ^-6 diff --git a/openigtlink/repo/Documents/Protocol/v3_proposal.md b/openigtlink/repo/Documents/Protocol/v3_proposal.md new file mode 100644 index 0000000..e8f240d --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/v3_proposal.md @@ -0,0 +1,250 @@ +[Back to Index](/Documents/Protocol/index.md) + +Overview of Version 3 Protocol +============================== + +- Protocol Version: 3.0 +- Release Date: January 20, 2017 + + +Background +=================== + +Since the release of version 2 protocol, we have learned that the protocol has several limitations: + +* While the naming convention for querying (i.e. GET_, STT_, STP_, and RTS_ prefixes) in version 2 provides a standardized way to identify query and response messages, there is still no standard way to manage multiple queries simaltaneously. This is mainly due to the lack of mechanism to reference the original query message from the response message. One workaround is to embed a unique message ID in the device names of query and response messages (e.g. "GET_STATUS_1234" and "RTS_STATUS_1234"). This approach requires the receiver process to parse the device name every time it receives a message, and reduces the actual length of device name. +* When developers design new message exchange schemes for specific applications, they often need to attach some application-specific information to the existing data types. While it can be achieved by bundling the data message with string messages using a BIND message, it is not ideal from the performance aspect. It would make more sense to have a way to add custom 'tags' to any messages. + +Overview of Version 3 Proposal +=================== + +At [Winter Project Week 2016](http://wiki.na-mic.org/Wiki/index.php/2016_Winter_Project_Week/Projects/TrackedUltrasoundStandardization) (January 5-9, 2016, Cambridge, MA), we discussed the limitations above, and potential extension to the existing protocols _with backward compatibility_. The following changes were proposed: + +* A new message structure. The body in the former protocol was splitted into extended header, content, and metadata. The message now consists of the following sections: + * Header (58 bytes) + * Extended Header (variable length) + * Content (variable length) + * Metadata (variable length) +* The _header_ section has the same format as version 2 protocol, and should contain the following information: + * The header version (the first two bytes) will be incremented to '0x0002' + * The Body size is the total byte size for the extended header, content, and Metadata. This will allow old clients to skip the entire message and read the sucessive message properly. + * The other fields are filled in the same as the previous version. +* The _extended header_ section contains the following fields: + * Extended header size (EXT_HEADER_SIZE) (2 bytes) + * Metadata size (METADATA_SIZE) (2 bytes) + * Message ID (MSG_ID) (4 bytes) +* The _content_ section is equivalent to the body section in the previous version. + * The size of content can be computed as: BODY_SIZZE - (EXT_HEADER_SIZE + METADAT_SIZE) +* The _metadata_ section contains pairs of 'key' and 'value' strings. Keys are ASCII string, while values can be stored using different encodings. + +Messaging Format +=================== + +Overall Message Format +------------------- + +~~~~ + Bytes + 0 58 72 + +----------+-------------+-------------------+-----------+ + | HEADER | EXT_HEADER | CONTENT | META_DATA | + +----------+-------------+-------------------+-----------+ +~~~~ + +Header + Extended Header +------------------- + +~~~~ + Bytes + 0 2 14 34 42 50 58 + +---+-----------------------+---------------------------------------+---------------+---------------+---------------+ + | V | TYPE | DEVICE_NAME | TIME_STAMP | BODY_SIZE | CRC64 | + +---+-----------------------+---------------------------------------+---------------+---------------+---------------+ + + 58 60 64 68 72 + +-----------------+---------------+---------+-----------+ + | EXT_HEADER_SIZE | METADATA_SIZE | MSG_ID | RESERVED | + +-----------------+---------------+---------+-----------+ +~~~~ + +Content +------------------- + +The format of contenst section is type-dependent. Please see individual type definition page. + + +Metadata +------------------- + +The metadata section consists of metadata header and metadata body. + +Metadata header: + +~~~~ + Bytes + 0 2 4 6 10 12 14 18 + +-------------+-------------+-------------------+---------------+-------------+-------------------+---------------+---- + | INDEX_COUNT | KEY_SIZE_0 | VALUE_ENCODING_0 | VALUE_SIZE_0 | KEY_SIZE_1 | VALUE_ENCODING_1 | VALUE_SIZE_1 | ... + +-------------+-------------+-------------------+---------------+-------------+-------------------+---------------+---- + |<-------------- Metadata 0 --------------------->|<--------------- Metadata 1 -------------------->| + + INDEX_COUNT*8+2 + ----+-------------+-------------------+---------------+ + ... |KEY_SIZE_N-1 |VALUE_ENCODING_N-1 |VALUE_SIZE_N-1 | + ----+-------------+-------------------+---------------+ + |<----------Metadata N-1 (=INDEX_COUNT)---------->| +~~~~ + +Metadata body: + +~~~~ + Bytes + +--------+---------+--------+----------+---- ----+--------+-----------+ + | KEY_0 | VALUE_0 | KEY_1 | VALUE_1 | ... |KEY_N-1 | VALUE_N-1 | + +--------+---------+--------+----------+---- ----+--------+-----------+ + |<-- Metadata 0 -->|<-- Metadata 1 --->| |<-- Metadata N-1 -->| +~~~~ + +Available Message Types +=================== + +New Messages Proposed for V3 +------------------- + + + + + + +
Type name +GET query +STT query +STP query +RTS message +Description +
COMMAND +-- +-- +-- +RTS_COMMAND +Command +
+ +Messages from version 1 and 2 +------------------- + + + + + + + + + + + + + + + + + + + + + + + + + +
Type name +GET query +STT query +STP query +RTS message +Description +
IMAGE +GET_IMAGE +STT_IMAGE +STP_IMAGE +RTS_IMAGE +2D/3D image data +
TRANSFORM +GET_TRANSFOR +STT_TRANSFOR +STP_TRANSFOR +RTS_TRANSFOR +Affine transform data. +
POSITION +GET_POSITION +STT_POSITION +STP_POSITION +RTS_POSITION +Position and orientation (quaternion) +
CAPABILITY +GET_CAPABIL +-- +-- +RTS_CAPABIL +Points or fiducials. +
STATUS +GET_STATUS +-- +-- +RTS_STATUS +Device status +
TDATA +GET_TDATA +STT_TDATA +STP_TDATA +RTS_TDATA +Tracking data +
IMGMETA +GET_IMGMETA +-- +-- +RTS_IMGMETA +List of image meta data including patient name, ID (medical record number), size, etc. +
LBMETA +GET_LBMETA +-- +-- +RTS_LBMETA +List of label meta data. +
POINT +GET_POINT +-- +-- +RTS_POINT +Points or fiducials. +
TRAJ +GET_TRAJ +-- +-- +RTS_TRAJ +Trajectory data (needle path etc.) +
NDARRAY +GET_NDARRAY +STT_NDARRAY +STP_NDARRAY +RTS_NDARRAY +Associative array to transfer a set of values with key names. +
+ + +Acknowledgement +=================== + +The version 3 propsal is drafted by the following members: + +* Andras Lasso, Tamas Ungi (PerkLab, Queen's University) +* Christian Askeland, Ingerid Reinertsen, Ole Vegard Solberg (CustusX, IGT research, SINTEF) +* Simon Drouin (Mcgill University, Montreal, Canada) +* Junichi Tokuda (Brigham and Women's Hospital, Boston, MA) +* Steve Pieper (Isomics, Cambridge, MA) +* Adam Rankin (VASST Laboratory, Western University, Canada) +* Thomas Kirchner, Janek Gröhl (MITK, DKFZ, Heidelberg, Germany) + + + + diff --git a/openigtlink/repo/Documents/Protocol/video.md b/openigtlink/repo/Documents/Protocol/video.md new file mode 100644 index 0000000..d03b153 --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/video.md @@ -0,0 +1,61 @@ +[Back to Index](/Documents/Protocol/index.md) + +Video Message +============== + +- Protocol Version: 3.1 +- Release Date: July 14, 2017 + + +Summary +======= + +The Video message supports video codec streaming with metric information including codec protocal name, +frame height, frame width, etc. The body section of the VIDEO +data consists of two parts: video header to transfer the metric information and video body +to transfer encoded video bit stream. The numerical values can be 8-, 16-, 32-bit integer, depending on the encoder. +The pixel values can be either big-endian or little-endian. This message type could be used for real-time video transmission. + +Message Types +============= + +VIDEO +------ + + Data | Type | Description +----------------------|------------------|------------------------------------------------- + HEADER_VERSION | uint16 | Header version number + ENDIAN | uint8 | Endian for image data (1:BIG 2:LITTLE) + ENCODING | char[4] | FourCC codec name, Default codec="VP90" + FRAMETYPE | uint16 | Field to identify frame type, such as key frame or invalid frame. Also, if the type value is larger than 0xFF, it indicates gray frames are encoded + COORD | uint8[3] | Coordinate system (1:RAS 2:LPS) + SIZE | uint16 | Video frame size + MATRIX | float32[12] | Orientation / origin of image + SUBVOL_OFFSET | uint16[3] | Sub volume offset + SUBVOL_SIZE | uint16[3] | Sub volume size + +STT_VIDEO +------------------- + + Data | Type | Description +---------------|---------------|------------------------------------------------- + CODEC | char[4] | Command Parameter. The Codec name indicates which codec to use for compression, Default codec="VP90". + TIME_INTERVAL | uint32 | Command Parameter. Minimum time between two frames. Unit is millisecond. Default = 50 ms + +STP_VIDEO +------------------- +N/A + +Implementations +=================== + +The TDATA message type is implemented in the following source code. + +* [igtlVideoMessage.h](/Source/VideoStreaming/igtlVideoMessage.h) +* [igtlVideoMessage.cxx](/Source/VideoStreaming/igtlVideoMessage.cxx) + +Contributors +=================== + +*Longquan Chen Junichi Tokuda + diff --git a/openigtlink/repo/Documents/Protocol/videometa.md b/openigtlink/repo/Documents/Protocol/videometa.md new file mode 100644 index 0000000..e65a98a --- /dev/null +++ b/openigtlink/repo/Documents/Protocol/videometa.md @@ -0,0 +1,76 @@ +[Back to Index](/Documents/Protocol/index.md) + +VIDEOMeta Message +================= + +- Protocol Version: 3.1 +- Release Date: July 17, 2017 + + +Summary +======= + +The VIDEOMETA message is used to transfer video meta information which are not available in video message type, +such as patient name, medical record number, camera focal length, zoom factor etc. +An VIDEOMETA message can contain meta data for multiple video sources. +This message type may be used to obtain a list of videos available in the remote system, such as video database, laparoscope or commercial image-guided surgery (IGS) system. + +Message Types +============= + +VIDEOMETA +------- + + Data | Type | Description +--------------|---------------|------------------------------------------------- + NAME | char[64] | Name or description of the video + DEVICENAME | char[64] | DeviceName to query the VIDEO and COLORT + PATIENT_NAME | char[64] | Name of the patient + PATIENT_ID | char[64] | ID of the patient + ZOOM_LEVEL | int16 | Defines the zoom level of the camera. + FOCAL_LENGTH | float64 | Defines the focal length of the camera in millimeter. + RI, RJ, RK | uint16[3] | Number of pixels in each direction + TX, TY, TZ | float32[3] | Transverse vector (direction for 'i' index) / The length represents pixel size in 'i' direction in millimeter + SX, SY, SZ | float32[3] | Transverse vector (direction for 'j' index) / The length represents pixel size in 'j' direction in millimeter + NX, NY, NZ | float32[3] | Normal vector of video frame plane(direction for 'k' index) / The length represents pixel size in 'z' direction or slice thickness in millimeter + PX, PY, PZ | float32[3] | Center position of the video frame (in millimeter) (*) + S | uint8 | Scalar type (e.g. 3:uint8, 5:uint16, same as in VIDEO) + -- | uint8 | Reserved + +* More than one item can be transmitted. The number is bodySize/itemSize. +* To get the VIDEO, GET_VIDEO is used with the Id in the device name field. + + +GET_VMETA +------------------- + +GET_VMETA is used to query for meta data of video sets. If DEVICE_NAME in the +header is empty, a list of meta data for all available video sources is returned. + + Data | Type | Description +--------------|---------------|------------------------------------------------- + | | + +STT_VMETA +------------------- + +N/A + +STP_VMETA +------------------- + +N/A + + +Implementations +=================== + +* [igtlVideoMetaMessage.h](/Source/VideoStreaming/igtlVideoMetaMessage.h) +* [igtlVideoMetaMessage.cxx](/Source/VideoStreaming/igtlVideoMetaMessage.cxx) + +Contributors +=================== + +* Longquan Chen + + diff --git a/openigtlink/repo/Examples/Bind/BindClient.cxx b/openigtlink/repo/Examples/Bind/BindClient.cxx new file mode 100644 index 0000000..97915d4 --- /dev/null +++ b/openigtlink/repo/Examples/Bind/BindClient.cxx @@ -0,0 +1,148 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlBindMessage.h" +#include "igtlStringMessage.h" +#include "igtlTransformMessage.h" +#include "igtlClientSocket.h" + +#define N_STRINGS 5 +const char * testString[N_STRINGS] = { + "OpenIGTLink", + "Network", + "Communication", + "Protocol", + "Image Guided Therapy", +}; + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 4) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int interval = (int) (1000.0 / fps); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Child Message Classes (String and Transform) + + igtl::StringMessage::Pointer stringMsg; + stringMsg = igtl::StringMessage::New(); + + igtl::TransformMessage::Pointer transMsg; + transMsg = igtl::TransformMessage::New(); + + //------------------------------------------------------------ + // Allocate Bind message class + + igtl::BindMessage::Pointer bindMsg; + bindMsg = igtl::BindMessage::New(); + + + //------------------------------------------------------------ + // loop + int i = 0; + while (1) + { + stringMsg->SetDeviceName("StringMessage"); + stringMsg->SetString(testString[i]); + stringMsg->Pack(); + + transMsg->SetDeviceName("Tracker"); + igtl::Matrix4x4 matrix; + GetRandomTestMatrix(matrix); + transMsg->SetMatrix(matrix); + transMsg->Pack(); + + bindMsg->Init(); + bindMsg->SetDeviceName("BindMessage"); + bindMsg->AppendChildMessage(stringMsg); + bindMsg->AppendChildMessage(transMsg); + bindMsg->Pack(); + + socket->Send(bindMsg->GetPackPointer(), bindMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + + //------------------------------------------------------------ + // Close connection + + socket->CloseSocket(); + +} + +//------------------------------------------------------------ +// Function to generate random matrix. + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix) +{ + float position[3]; + float orientation[4]; + + // random position + static float phi = 0.0; + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + phi = phi + 0.2; + + // random orientation + static float theta = 0.0; + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + //igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + + igtl::PrintMatrix(matrix); +} + diff --git a/openigtlink/repo/Examples/Bind/BindServer.cxx b/openigtlink/repo/Examples/Bind/BindServer.cxx new file mode 100644 index 0000000..cbf6a55 --- /dev/null +++ b/openigtlink/repo/Examples/Bind/BindServer.cxx @@ -0,0 +1,117 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlTransformMessage.h" +#include "igtlServerSocket.h" + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + double fps = atof(argv[2]); + int interval = (int) (1000.0 / fps); + + igtl::TransformMessage::Pointer transMsg; + transMsg = igtl::TransformMessage::New(); + transMsg->SetDeviceName("Tracker"); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + igtl::Matrix4x4 matrix; + GetRandomTestMatrix(matrix); + transMsg->SetMatrix(matrix); + transMsg->Pack(); + socket->Send(transMsg->GetPackPointer(), transMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix) +{ + float position[3]; + float orientation[4]; + + // random position + static float phi = 0.0; + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + phi = phi + 0.2; + + // random orientation + static float theta = 0.0; + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + //igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + + igtl::PrintMatrix(matrix); +} + diff --git a/openigtlink/repo/Examples/Bind/CMakeLists.txt b/openigtlink/repo/Examples/Bind/CMakeLists.txt new file mode 100644 index 0000000..9b2e1eb --- /dev/null +++ b/openigtlink/repo/Examples/Bind/CMakeLists.txt @@ -0,0 +1,18 @@ +PROJECT(Bind) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(BindClient BindClient.cxx) +TARGET_LINK_LIBRARIES(BindClient OpenIGTLink) + +#ADD_EXECUTABLE(BindServer BindServer.cxx) +#TARGET_LINK_LIBRARIES(BindServer OpenIGTLink) + + diff --git a/openigtlink/repo/Examples/CMakeLists.txt b/openigtlink/repo/Examples/CMakeLists.txt new file mode 100644 index 0000000..ac3dcd5 --- /dev/null +++ b/openigtlink/repo/Examples/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 2.4) + +# +# Examples +# +SET(EXAMPLE_DIRS + Tracker + Imager + Status + Receiver + Thread + ) + +if (${OpenIGTLink_PROTOCOL_VERSION} GREATER 1) + SET(EXAMPLE_DIRS + ${EXAMPLE_DIRS} + ImageMeta + Point + TrackingData + QuaternionTrackingData + ImageDatabaseServer + String + Bind + PolyData + Capability + Trajectory + SessionManager + TrackingDataUDPTransfer + #SampleUDPProgam + ) +endif (${OpenIGTLink_PROTOCOL_VERSION} GREATER 1) + +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER 2) + IF(OpenIGTLink_USE_H264 OR OpenIGTLink_USE_VP9 OR (OpenIGTLink_USE_X265 AND OpenIGTLink_USE_OpenHEVC) OR OpenIGTLink_USE_AV1) + SET(EXAMPLE_DIRS + ${EXAMPLE_DIRS} + VideoStreaming + ) + ENDIF() +ENDIF() + + +IF(OpenIGTLink_USE_WEBSOCKET) + SET(EXAMPLE_DIRS + ${EXAMPLE_DIRS} + WebSocket + ) +ENDIF() + +## Imager program isn't supported by QNX +if(NOT OpenIGTLink_PLATFORM_QNX) + SUBDIRS( + ${EXAMPLE_DIRS} + ) +else(NOT OpenIGTLink_PLATFORM_QNX) + SUBDIRS( + Tracker + Status + Receiver + ) +endif(NOT OpenIGTLink_PLATFORM_QNX) + + + diff --git a/openigtlink/repo/Examples/Capability/CMakeLists.txt b/openigtlink/repo/Examples/Capability/CMakeLists.txt new file mode 100644 index 0000000..dac2a76 --- /dev/null +++ b/openigtlink/repo/Examples/Capability/CMakeLists.txt @@ -0,0 +1,18 @@ +PROJECT(Capability) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(CapabilityClient CapabilityClient.cxx) +TARGET_LINK_LIBRARIES(CapabilityClient OpenIGTLink) + +ADD_EXECUTABLE(CapabilityServer CapabilityServer.cxx) +TARGET_LINK_LIBRARIES(CapabilityServer OpenIGTLink) + + diff --git a/openigtlink/repo/Examples/Capability/CapabilityClient.cxx b/openigtlink/repo/Examples/Capability/CapabilityClient.cxx new file mode 100644 index 0000000..177b1fe --- /dev/null +++ b/openigtlink/repo/Examples/Capability/CapabilityClient.cxx @@ -0,0 +1,83 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Sending Capability Messasge + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlCapabilityMessage.h" +#include "igtlClientSocket.h" + +#include "igtlTransformMessage.h" +#include "igtlImageMessage.h" +#include "igtlLabelMetaMessage.h" + +// +// Test comment +// + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + int interval = (int) (1000); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Capability Message Class + + igtl::CapabilityMessage::Pointer capabilityMsg; + capabilityMsg = igtl::CapabilityMessage::New(); + capabilityMsg->SetDeviceName("Device"); + + std::vector types; + types.push_back(std::string("TRANSFORM")); + types.push_back(std::string("GET_IMAGE")); + types.push_back(std::string("GET_LBMETA")); + capabilityMsg->SetTypes(types); + capabilityMsg->Pack(); + socket->Send(capabilityMsg->GetPackPointer(), capabilityMsg->GetPackSize()); + //------------------------------------------------------------ + // Close connection + + socket->CloseSocket(); + +} + + diff --git a/openigtlink/repo/Examples/Capability/CapabilityServer.cxx b/openigtlink/repo/Examples/Capability/CapabilityServer.cxx new file mode 100644 index 0000000..f47e368 --- /dev/null +++ b/openigtlink/repo/Examples/Capability/CapabilityServer.cxx @@ -0,0 +1,88 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlCapabilityMessage.h" +#include "igtlServerSocket.h" + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + int interval = (int) 1000; + + //------------------------------------------------------------ + // Allocate Capability Message Class + + igtl::CapabilityMessage::Pointer capabilityMsg; + capabilityMsg = igtl::CapabilityMessage::New(); + capabilityMsg->SetDeviceName("Device"); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + std::vector types; + types.push_back(std::string("TRANSFORM")); + types.push_back(std::string("GET_IMAGE")); + types.push_back(std::string("GET_LBMETA")); + capabilityMsg->SetTypes(types); + capabilityMsg->Pack(); + socket->Send(capabilityMsg->GetPackPointer(), capabilityMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + + diff --git a/openigtlink/repo/Examples/ImageDatabaseServer/CMakeLists.txt b/openigtlink/repo/Examples/ImageDatabaseServer/CMakeLists.txt new file mode 100644 index 0000000..618b052 --- /dev/null +++ b/openigtlink/repo/Examples/ImageDatabaseServer/CMakeLists.txt @@ -0,0 +1,16 @@ +PROJECT(ImageDatabaseServer) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + + +## igtl::ImageDatabaseMessage examples +ADD_EXECUTABLE(ImageDatabaseServer ImageDatabaseServer.cxx) +TARGET_LINK_LIBRARIES(ImageDatabaseServer OpenIGTLink) + diff --git a/openigtlink/repo/Examples/ImageDatabaseServer/ImageDatabaseServer.cxx b/openigtlink/repo/Examples/ImageDatabaseServer/ImageDatabaseServer.cxx new file mode 100644 index 0000000..ad35934 --- /dev/null +++ b/openigtlink/repo/Examples/ImageDatabaseServer/ImageDatabaseServer.cxx @@ -0,0 +1,386 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Image Meta Data Server + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlImageMessage.h" +#include "igtlImageMetaMessage.h" +#include "igtlLabelMetaMessage.h" +#include "igtlServerSocket.h" + +int SendImageMeta(igtl::Socket::Pointer& socket, const char* name); +int SendLabelMeta(igtl::Socket::Pointer& socket, const char* name); +int SendImage(igtl::Socket::Pointer& socket, const char* name, const char* filedir); +int SendLabel(igtl::Socket::Pointer& socket, const char* name, const char* filedir); +int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i); + +int main(int argc, char* argv[]) +{ + + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : file directory, where \"igtlTestImage[1-3].raw\" are placed." << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + char* filedir = argv[2]; + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + // Initialize receive buffer + headerMsg->InitPack(); + bool timeout(false); + // Receive generic header from the socket + int rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + socket->CloseSocket(); + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + std::cerr << "Receiving a message: " << std::endl; + std::cerr << " Device Type: \"" << headerMsg->GetDeviceType() << "\"" << std::endl; + std::cerr << " Device Name: \"" << headerMsg->GetDeviceName() << "\"" << std::endl; + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "GET_IMGMETA") == 0) + { + //socket->Skip(headerMsg->GetBodySizeToRead(), 0); + SendImageMeta(socket, headerMsg->GetDeviceName()); + } + else if (strcmp(headerMsg->GetDeviceType(), "GET_LBMETA") == 0) + { + SendLabelMeta(socket, headerMsg->GetDeviceName()); + } + else if (strcmp(headerMsg->GetDeviceType(), "GET_IMAGE") == 0) + { + SendImage(socket, headerMsg->GetDeviceName(), filedir); + } + else + { + // if the data type is unknown, skip reading. + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + + socket->CloseSocket(); + +} + + +int SendImageMeta(igtl::Socket::Pointer& socket, const char* name) +{ + //------------------------------------------------------------ + // Allocate Status Message Class + + igtl::ImageMetaMessage::Pointer imgMetaMsg; + imgMetaMsg = igtl::ImageMetaMessage::New(); + // NOTE: the server should send a message with the same device name + // as the received query message. + imgMetaMsg->SetDeviceName(name); + + //--------------------------- + // Create 1st meta data + igtl::ImageMetaElement::Pointer imgMeta0; + imgMeta0 = igtl::ImageMetaElement::New(); + imgMeta0->SetName("IMAGE_DESCRIPTION_0"); + imgMeta0->SetDeviceName("IMAGE_0"); + imgMeta0->SetModality("CT"); + imgMeta0->SetPatientName("PATIENT_0"); + imgMeta0->SetPatientID("PATIENT_ID_0"); + + igtl::TimeStamp::Pointer ts0; + ts0 = igtl::TimeStamp::New(); + ts0->SetTime(1291739370.2345); + + imgMeta0->SetTimeStamp(ts0); + imgMeta0->SetSize(512, 512, 64); + imgMeta0->SetScalarType(igtl::ImageMessage::TYPE_UINT16); + + //--------------------------- + // Create 2nd meta data + igtl::ImageMetaElement::Pointer imgMeta1; + imgMeta1 = igtl::ImageMetaElement::New(); + imgMeta1->SetName("IMAGE_DESCRIPTION_1"); + imgMeta1->SetDeviceName("IMAGE_1"); + imgMeta1->SetModality("MRI"); + imgMeta1->SetPatientName("PATIENT_1"); + imgMeta1->SetPatientID("PATIENT_ID_1"); + + igtl::TimeStamp::Pointer ts1; + ts1 = igtl::TimeStamp::New(); + ts1->SetTime(1291739380.3456); + + imgMeta1->SetTimeStamp(ts1); + imgMeta1->SetSize(256, 128, 32); + imgMeta1->SetScalarType(igtl::ImageMessage::TYPE_UINT16); + + //--------------------------- + // Create 3rd meta data + igtl::ImageMetaElement::Pointer imgMeta2; + imgMeta2 = igtl::ImageMetaElement::New(); + imgMeta2->SetName("IMAGE_DESCRIPTION_2"); + imgMeta2->SetDeviceName("IMAGE_2"); + imgMeta2->SetModality("PET"); + imgMeta2->SetPatientName("PATIENT_2"); + imgMeta2->SetPatientID("PATIENT_ID_2"); + + igtl::TimeStamp::Pointer ts2; + ts2 = igtl::TimeStamp::New(); + ts2->SetTime(1291739390.4567); + + imgMeta2->SetTimeStamp(ts2); + imgMeta2->SetSize(256, 256, 32); + imgMeta2->SetScalarType(igtl::ImageMessage::TYPE_UINT16); + + imgMetaMsg->AddImageMetaElement(imgMeta0); + imgMetaMsg->AddImageMetaElement(imgMeta1); + imgMetaMsg->AddImageMetaElement(imgMeta2); + + imgMetaMsg->Pack(); + std::cerr << "Size of pack: " << imgMetaMsg->GetPackSize() << std::endl; + std::cerr << "Name of type: " << imgMetaMsg->GetDeviceType() << std::endl; + std::cerr << "Sending a IMGMETA message..." << std::endl; + + socket->Send(imgMetaMsg->GetPackPointer(), imgMetaMsg->GetPackSize()); + + return 1; + +} + + +int SendLabelMeta(igtl::Socket::Pointer& socket, const char* name) +{ + //------------------------------------------------------------ + // Allocate Status Message Class + + igtl::LabelMetaMessage::Pointer lbMetaMsg; + lbMetaMsg = igtl::LabelMetaMessage::New(); + // NOTE: the server should send a message with the same device name + // as the received query message. + lbMetaMsg->SetDeviceName(name); + + //--------------------------- + // Create 1st meta data + igtl::LabelMetaElement::Pointer lbMeta0; + lbMeta0 = igtl::LabelMetaElement::New(); + lbMeta0->SetName("LABEL_DESCRIPTION_0"); + lbMeta0->SetDeviceName("LABEL_0"); + lbMeta0->SetOwner("IMAGE_0"); + lbMeta0->SetSize(512, 512, 64); + + //--------------------------- + // Create 2nd meta data + igtl::LabelMetaElement::Pointer lbMeta1; + lbMeta1 = igtl::LabelMetaElement::New(); + lbMeta1->SetName("LABEL_DESCRIPTION_1"); + lbMeta1->SetDeviceName("LABEL_1"); + lbMeta1->SetOwner("IMAGE_1"); + + lbMeta1->SetSize(256, 128, 32); + + //--------------------------- + // Create 3rd meta data + igtl::LabelMetaElement::Pointer lbMeta2; + lbMeta2 = igtl::LabelMetaElement::New(); + lbMeta2->SetName("LABEL_DESCRIPTION_2"); + lbMeta2->SetDeviceName("LABEL_2"); + lbMeta2->SetOwner("IMAGE_2"); + lbMeta2->SetSize(256, 256, 32); + + lbMetaMsg->AddLabelMetaElement(lbMeta0); + lbMetaMsg->AddLabelMetaElement(lbMeta1); + lbMetaMsg->AddLabelMetaElement(lbMeta2); + + lbMetaMsg->Pack(); + std::cerr << "Size of pack: " << lbMetaMsg->GetPackSize() << std::endl; + std::cerr << "Name of type: " << lbMetaMsg->GetDeviceType() << std::endl; + std::cerr << "Sending a LBMETA message..." << std::endl; + + socket->Send(lbMetaMsg->GetPackPointer(), lbMetaMsg->GetPackSize()); + + return 1; + +} + + + +int SendImage(igtl::Socket::Pointer& socket, const char* name, const char* filedir) +{ + int index = 0; + + if (strcmp(name, "IMAGE_0") == 0) + { + index = 1; + } + else if (strcmp(name, "IMAGE_1") == 0) + { + index = 2; + } + else if (strcmp(name, "IMAGE_2") == 0) + { + index = 3; + } + if (strcmp(name, "LABEL_0") == 0) + { + index = 4; + } + else if (strcmp(name, "LABEL_1") == 0) + { + index = 5; + } + else if (strcmp(name, "LABEL_2") == 0) + { + index = 6; + } + + if (index > 0) + { + int size[] = {256, 256, 1}; // image dimension + float spacing[] = {1.0, 1.0, 5.0}; // spacing (mm/pixel) + int svsize[] = {256, 256, 1}; // sub-volume size + int svoffset[] = {0, 0, 0}; // sub-volume offset + int scalarType = igtl::ImageMessage::TYPE_UINT8;// scalar type + + igtl::ImageMessage::Pointer imgMsg = igtl::ImageMessage::New(); + imgMsg->SetDimensions(size); + imgMsg->SetSpacing(spacing); + imgMsg->SetScalarType(scalarType); + imgMsg->SetDeviceName(name); + imgMsg->SetSubVolume(svsize, svoffset); + imgMsg->AllocateScalars(); + + // Following line may be called in case of 16-, 32-, and 64-bit scalar types. + // imgMsg->SetEndian(igtl::ImageMessage::ENDIAN_BIG); + + //------------------------------------------------------------ + // Set image data (See GetTestImage() bellow for the details) + GetTestImage(imgMsg, filedir, index); + + igtl::Matrix4x4 matrix; + igtl::IdentityMatrix(matrix); + imgMsg->SetMatrix(matrix); + + //------------------------------------------------------------ + // Pack (serialize) and send + imgMsg->Pack(); + socket->Send(imgMsg->GetPackPointer(), imgMsg->GetPackSize()); + } + else + { + //------------------------------------------------------------ + // Return RTS_IMAGE message with error code + + // TODO + + } + + return 1; +} + + +//------------------------------------------------------------ +// Function to read test image data +int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i) +{ + + //------------------------------------------------------------ + // Check if image index is in the range + if (i < 0 || i >= 7) + { + std::cerr << "Image index is invalid." << std::endl; + return 0; + } + + //------------------------------------------------------------ + // Generate path to the raw image file + char filename[128]; + sprintf(filename, "%s/igtlTestImage%d.raw", dir, i+1); + std::cerr << "Reading " << filename << "..."; + + //------------------------------------------------------------ + // Load raw data from the file + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) + { + std::cerr << "File opeining error: " << filename << std::endl; + return 0; + } + int fsize = msg->GetImageSize(); + //size_t b = fread(msg->GetScalarPointer(), 1, fsize, fp); + fread(msg->GetScalarPointer(), 1, fsize, fp); + + fclose(fp); + + std::cerr << "done." << std::endl; + + return 1; +} + + + + diff --git a/openigtlink/repo/Examples/ImageMeta/CMakeLists.txt b/openigtlink/repo/Examples/ImageMeta/CMakeLists.txt new file mode 100644 index 0000000..9922707 --- /dev/null +++ b/openigtlink/repo/Examples/ImageMeta/CMakeLists.txt @@ -0,0 +1,25 @@ +PROJECT(ImageMeta) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + + +## igtl::ImageMetaMessage examples +ADD_EXECUTABLE(ImageMetaServer ImageMetaServer.cxx) +TARGET_LINK_LIBRARIES(ImageMetaServer OpenIGTLink) + +ADD_EXECUTABLE(ImageMetaClient ImageMetaClient.cxx) +TARGET_LINK_LIBRARIES(ImageMetaClient OpenIGTLink) + +## igtl::LabelMetaMessage example +ADD_EXECUTABLE(LabelMetaServer LabelMetaServer.cxx) +TARGET_LINK_LIBRARIES(LabelMetaServer OpenIGTLink) + +ADD_EXECUTABLE(LabelMetaClient LabelMetaClient.cxx) +TARGET_LINK_LIBRARIES(LabelMetaClient OpenIGTLink) diff --git a/openigtlink/repo/Examples/ImageMeta/ImageMetaClient.cxx b/openigtlink/repo/Examples/ImageMeta/ImageMetaClient.cxx new file mode 100644 index 0000000..5163b70 --- /dev/null +++ b/openigtlink/repo/Examples/ImageMeta/ImageMetaClient.cxx @@ -0,0 +1,162 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Image Meta Data Client + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlImageMessage.h" +#include "igtlImageMetaMessage.h" +#include "igtlClientSocket.h" + + +int ReceiveImageMeta(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + + //------------------------------------------------------------ + // Establish Connection + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 10; i ++) + { + //------------------------------------------------------------ + // Send request data + igtl::GetImageMetaMessage::Pointer getImageMetaMsg; + getImageMetaMsg = igtl::GetImageMetaMessage::New(); + getImageMetaMsg->SetDeviceName("Client"); + getImageMetaMsg->Pack(); + socket->Send(getImageMetaMsg->GetPackPointer(), getImageMetaMsg->GetPackSize()); + + //------------------------------------------------------------ + // Wait for a reply + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + std::cerr << "Message size information and actual data size don't match." << std::endl; + exit(0); + } + + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "IMGMETA") == 0) + { + ReceiveImageMeta(socket, headerMsg); + } + else + { + std::cerr << "Invalid response from the server:" << headerMsg->GetDeviceName() << std::endl; + exit(0); + } + + igtl::Sleep(500); // wait + } + + //------------------------------------------------------------ + // Close connection + socket->CloseSocket(); + +} + + +int ReceiveImageMeta(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving IMGMETA data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::ImageMetaMessage::Pointer imgMeta; + imgMeta = igtl::ImageMetaMessage::New(); + imgMeta->SetMessageHeader(header); + imgMeta->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(imgMeta->GetPackBodyPointer(), imgMeta->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = imgMeta->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = imgMeta->GetNumberOfImageMetaElement(); + for (int i = 0; i < nElements; i ++) + { + igtl::ImageMetaElement::Pointer imgMetaElement; + imgMeta->GetImageMetaElement(i, imgMetaElement); + igtlUint16 size[3]; + imgMetaElement->GetSize(size); + + igtl::TimeStamp::Pointer ts; + imgMetaElement->GetTimeStamp(ts); + double time = ts->GetTimeStamp(); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << imgMetaElement->GetName() << std::endl; + std::cerr << " DeviceName : " << imgMetaElement->GetDeviceName() << std::endl; + std::cerr << " Modality : " << imgMetaElement->GetModality() << std::endl; + std::cerr << " PatientName: " << imgMetaElement->GetPatientName() << std::endl; + std::cerr << " PatientID : " << imgMetaElement->GetPatientID() << std::endl; + std::cerr << " TimeStamp : " << std::fixed << time << std::endl; + std::cerr << " Size : ( " << size[0] << ", " << size[1] << ", " << size[2] << ")" << std::endl; + std::cerr << " ScalarType : " << (int) imgMetaElement->GetScalarType() << std::endl; + std::cerr << "================================" << std::endl; + } + return 1; + } + + return 0; + +} + + + diff --git a/openigtlink/repo/Examples/ImageMeta/ImageMetaServer.cxx b/openigtlink/repo/Examples/ImageMeta/ImageMetaServer.cxx new file mode 100644 index 0000000..67cdead --- /dev/null +++ b/openigtlink/repo/Examples/ImageMeta/ImageMetaServer.cxx @@ -0,0 +1,206 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Image Meta Data Server + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlImageMessage.h" +#include "igtlServerSocket.h" +#include "igtlImageMetaMessage.h" + + +int SendImageMeta(igtl::Socket::Pointer& socket, const char* name); + +int main(int argc, char* argv[]) +{ + + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + socket->CloseSocket(); + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "GET_IMGMETA") == 0) + { + std::cerr << "Received a GET_IMGMETA message." << std::endl; + //socket->Skip(headerMsg->GetBodySizeToRead(), 0); + SendImageMeta(socket, headerMsg->GetDeviceName()); + } + else + { + // if the data type is unknown, skip reading. + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + + socket->CloseSocket(); + +} + + +int SendImageMeta(igtl::Socket::Pointer& socket, const char* name) +{ + + //------------------------------------------------------------ + // Allocate Status Message Class + + igtl::ImageMetaMessage::Pointer imgMetaMsg; + imgMetaMsg = igtl::ImageMetaMessage::New(); + // NOTE: the server should send a message with the same device name + // as the received query message. + imgMetaMsg->SetDeviceName(name); + + //--------------------------- + // Create 1st meta data + igtl::ImageMetaElement::Pointer imgMeta0; + imgMeta0 = igtl::ImageMetaElement::New(); + imgMeta0->SetName("IMAGE_DESCRIPTION_0"); + imgMeta0->SetDeviceName("IMAGE_0"); + imgMeta0->SetModality("CT"); + imgMeta0->SetPatientName("PATIENT_0"); + imgMeta0->SetPatientID("PATIENT_ID_0"); + + igtl::TimeStamp::Pointer ts0; + ts0 = igtl::TimeStamp::New(); + ts0->SetTime(1.2345); + + imgMeta0->SetTimeStamp(ts0); + imgMeta0->SetSize(512, 512, 64); + imgMeta0->SetScalarType(igtl::ImageMessage::TYPE_UINT16); + + //--------------------------- + // Create 2nd meta data + igtl::ImageMetaElement::Pointer imgMeta1; + imgMeta1 = igtl::ImageMetaElement::New(); + imgMeta1->SetName("IMAGE_DESCRIPTION_1"); + imgMeta1->SetDeviceName("IMAGE_1"); + imgMeta1->SetModality("MRI"); + imgMeta1->SetPatientName("PATIENT_1"); + imgMeta1->SetPatientID("PATIENT_ID_1"); + + igtl::TimeStamp::Pointer ts1; + ts1 = igtl::TimeStamp::New(); + ts1->SetTime(2.3456); + + imgMeta1->SetTimeStamp(ts1); + imgMeta1->SetSize(256, 128, 32); + imgMeta1->SetScalarType(igtl::ImageMessage::TYPE_UINT16); + + //--------------------------- + // Create 3rd meta data + igtl::ImageMetaElement::Pointer imgMeta2; + imgMeta2 = igtl::ImageMetaElement::New(); + imgMeta2->SetName("IMAGE_DESCRIPTION_2"); + imgMeta2->SetDeviceName("IMAGE_2"); + imgMeta2->SetModality("PET"); + imgMeta2->SetPatientName("PATIENT_2"); + imgMeta2->SetPatientID("PATIENT_ID_2"); + + igtl::TimeStamp::Pointer ts2; + ts2 = igtl::TimeStamp::New(); + ts2->SetTime(3.4567); + + imgMeta2->SetTimeStamp(ts2); + imgMeta2->SetSize(256, 256, 32); + imgMeta2->SetScalarType(igtl::ImageMessage::TYPE_UINT16); + + imgMetaMsg->AddImageMetaElement(imgMeta0); + imgMetaMsg->AddImageMetaElement(imgMeta1); + imgMetaMsg->AddImageMetaElement(imgMeta2); + + imgMetaMsg->Pack(); + std::cerr << "Size of pack: " << imgMetaMsg->GetPackSize() << std::endl; + std::cerr << "Name of type: " << imgMetaMsg->GetDeviceType() << std::endl; + std::cerr << "Sending a IMGMETA message..." << std::endl; + + socket->Send(imgMetaMsg->GetPackPointer(), imgMetaMsg->GetPackSize()); + + return 1; + +} + + + + + + + + diff --git a/openigtlink/repo/Examples/ImageMeta/LabelMetaClient.cxx b/openigtlink/repo/Examples/ImageMeta/LabelMetaClient.cxx new file mode 100644 index 0000000..eb969b4 --- /dev/null +++ b/openigtlink/repo/Examples/ImageMeta/LabelMetaClient.cxx @@ -0,0 +1,160 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Label Meta Data Client + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlImageMessage.h" +#include "igtlLabelMetaMessage.h" +#include "igtlClientSocket.h" + + +int ReceiveLabelMeta(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + + //------------------------------------------------------------ + // Establish Connection + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 10; i ++) + { + //------------------------------------------------------------ + // Send request data + igtl::GetLabelMetaMessage::Pointer getLabelMetaMsg; + getLabelMetaMsg = igtl::GetLabelMetaMessage::New(); + getLabelMetaMsg->SetDeviceName("Client"); + getLabelMetaMsg->Pack(); + socket->Send(getLabelMetaMsg->GetPackPointer(), getLabelMetaMsg->GetPackSize()); + + //------------------------------------------------------------ + // Wait for a reply + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + std::cerr << "Message size information and actual data size don't match." << std::endl; + exit(0); + } + + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "LBMETA") == 0) + { + ReceiveLabelMeta(socket, headerMsg); + } + else + { + std::cerr << "Invalid response from the server:" << headerMsg->GetDeviceName() << std::endl; + exit(0); + } + + igtl::Sleep(500); // wait + } + + //------------------------------------------------------------ + // Close connection + socket->CloseSocket(); + +} + + +int ReceiveLabelMeta(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving LBMETA data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::LabelMetaMessage::Pointer lbMeta; + lbMeta = igtl::LabelMetaMessage::New(); + lbMeta->SetMessageHeader(header); + lbMeta->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(lbMeta->GetPackBodyPointer(), lbMeta->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = lbMeta->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = lbMeta->GetNumberOfLabelMetaElement(); + for (int i = 0; i < nElements; i ++) + { + igtl::LabelMetaElement::Pointer lbMetaElement; + lbMeta->GetLabelMetaElement(i, lbMetaElement); + + igtlUint8 rgba[4]; + lbMetaElement->GetRGBA(rgba); + + igtlUint16 size[3]; + lbMetaElement->GetSize(size); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << lbMetaElement->GetName() << std::endl; + std::cerr << " DeviceName : " << lbMetaElement->GetDeviceName() << std::endl; + std::cerr << " Label : " << (int) lbMetaElement->GetLabel() << std::endl; + std::cerr << " RGBA : ( " << (int)rgba[0] << ", " << (int)rgba[1] << ", " << (int)rgba[2] << ", " << (int)rgba[3] << " )" << std::endl; + std::cerr << " Size : ( " << size[0] << ", " << size[1] << ", " << size[2] << ")" << std::endl; + std::cerr << " Owner : " << lbMetaElement->GetOwner() << std::endl; + std::cerr << "================================" << std::endl; + } + return 1; + } + + return 0; + +} + + + diff --git a/openigtlink/repo/Examples/ImageMeta/LabelMetaServer.cxx b/openigtlink/repo/Examples/ImageMeta/LabelMetaServer.cxx new file mode 100644 index 0000000..26908b0 --- /dev/null +++ b/openigtlink/repo/Examples/ImageMeta/LabelMetaServer.cxx @@ -0,0 +1,182 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Label Meta Data Server + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlImageMessage.h" +#include "igtlServerSocket.h" +#include "igtlLabelMetaMessage.h" + + +int SendLabelMeta(igtl::Socket::Pointer& socket); + +int main(int argc, char* argv[]) +{ + + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + socket->CloseSocket(); + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "GET_LBMETA") == 0) + { + std::cerr << "Received a GET_LBMETA message." << std::endl; + //socket->Skip(headerMsg->GetBodySizeToRead(), 0); + SendLabelMeta(socket); + } + else + { + // if the data type is unknown, skip reading. + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + + socket->CloseSocket(); + +} + + +int SendLabelMeta(igtl::Socket::Pointer& socket) +{ + + //------------------------------------------------------------ + // Allocate Status Message Class + + igtl::LabelMetaMessage::Pointer lbMetaMsg; + lbMetaMsg = igtl::LabelMetaMessage::New(); + lbMetaMsg->SetDeviceName("MetaServer"); + + //--------------------------- + // Create 1st meta data + igtl::LabelMetaElement::Pointer lbMeta0; + lbMeta0 = igtl::LabelMetaElement::New(); + lbMeta0->SetName("LABEL_DESCRIPTION_0"); + lbMeta0->SetDeviceName("LABEL_0"); + lbMeta0->SetLabel(1); + lbMeta0->SetRGBA(0xFF, 0x00, 0x00, 0xFF); + lbMeta0->SetSize(512, 512, 64); + lbMeta0->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 2nd meta data + igtl::LabelMetaElement::Pointer lbMeta1; + lbMeta1 = igtl::LabelMetaElement::New(); + lbMeta1->SetName("LABEL_DESCRIPTION_1"); + lbMeta1->SetDeviceName("LABEL_1"); + lbMeta1->SetLabel(2); + lbMeta1->SetRGBA(0x00, 0xFF, 0, 0xFF); + lbMeta1->SetSize(256, 128, 32); + lbMeta1->SetOwner("IMAGE_1"); + + //--------------------------- + // Create 3rd meta data + igtl::LabelMetaElement::Pointer lbMeta2; + lbMeta2 = igtl::LabelMetaElement::New(); + lbMeta2->SetName("LABEL_DESCRIPTION_2"); + lbMeta2->SetDeviceName("LABEL_2"); + lbMeta2->SetLabel(3); + lbMeta2->SetRGBA(0, 0, 0xFF, 0xFF); + lbMeta2->SetSize(256, 256, 32); + lbMeta2->SetOwner("IMAGE_2"); + + lbMetaMsg->AddLabelMetaElement(lbMeta0); + lbMetaMsg->AddLabelMetaElement(lbMeta1); + lbMetaMsg->AddLabelMetaElement(lbMeta2); + + lbMetaMsg->Pack(); + std::cerr << "Size of pack: " << lbMetaMsg->GetPackSize() << std::endl; + std::cerr << "Name of type: " << lbMetaMsg->GetDeviceType() << std::endl; + std::cerr << "Sending a LBMETA message..." << std::endl; + + socket->Send(lbMetaMsg->GetPackPointer(), lbMetaMsg->GetPackSize()); + + return 1; +} + + + + + + + + diff --git a/openigtlink/repo/Examples/Imager/CMakeLists.txt b/openigtlink/repo/Examples/Imager/CMakeLists.txt new file mode 100644 index 0000000..1b64da3 --- /dev/null +++ b/openigtlink/repo/Examples/Imager/CMakeLists.txt @@ -0,0 +1,25 @@ +PROJECT(Imager) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(ImagerClient ImagerClient.cxx) +TARGET_LINK_LIBRARIES(ImagerClient OpenIGTLink) + +ADD_EXECUTABLE(ImagerClient2 ImagerClient2.cxx) +TARGET_LINK_LIBRARIES(ImagerClient2 OpenIGTLink) + +ADD_EXECUTABLE(ImagerServer ImagerServer.cxx) +TARGET_LINK_LIBRARIES(ImagerServer OpenIGTLink) + +ADD_EXECUTABLE(ImagerClient3 ImagerClient3.cxx) +TARGET_LINK_LIBRARIES(ImagerClient3 OpenIGTLink) + +ADD_EXECUTABLE(ImagerServer3 ImagerServer3.cxx) +TARGET_LINK_LIBRARIES(ImagerServer3 OpenIGTLink) diff --git a/openigtlink/repo/Examples/Imager/ImagerClient.cxx b/openigtlink/repo/Examples/Imager/ImagerClient.cxx new file mode 100644 index 0000000..f61b452 --- /dev/null +++ b/openigtlink/repo/Examples/Imager/ImagerClient.cxx @@ -0,0 +1,188 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Imager Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlImageMessage.h" +#include "igtlClientSocket.h" + +int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i); +void GetRandomTestMatrix(igtl::Matrix4x4& matrix); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 5) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + std::cerr << " : file directory, where \"igtlTestImage[1-5].raw\" are placed." << std::endl; + std::cerr << " (usually, in the Examples/Imager/img directory.)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int interval = (int) (1000.0 / fps); + char* filedir = argv[4]; + + //------------------------------------------------------------ + // Establish Connection + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + //------------------------------------------------------------ + // size parameters + int size[] = {256, 256, 1}; // image dimension + float spacing[] = {1.0, 1.0, 5.0}; // spacing (mm/pixel) + int svsize[] = {256, 256, 1}; // sub-volume size + int svoffset[] = {0, 0, 0}; // sub-volume offset + int scalarType = igtl::ImageMessage::TYPE_UINT8;// scalar type + + //------------------------------------------------------------ + // Create a new IMAGE type message + igtl::ImageMessage::Pointer imgMsg = igtl::ImageMessage::New(); + imgMsg->SetDimensions(size); + imgMsg->SetSpacing(spacing); + imgMsg->SetScalarType(scalarType); + imgMsg->SetDeviceName("ImagerClient"); + imgMsg->SetSubVolume(svsize, svoffset); + imgMsg->AllocateScalars(); + + // Following line may be called in case of 16-, 32-, and 64-bit scalar types. + // imgMsg->SetEndian(igtl::ImageMessage::ENDIAN_BIG); + + //------------------------------------------------------------ + // Set image data (See GetTestImage() bellow for the details) + GetTestImage(imgMsg, filedir, i % 5); + + //------------------------------------------------------------ + // Get random orientation matrix and set it. + igtl::Matrix4x4 matrix; + GetRandomTestMatrix(matrix); + imgMsg->SetMatrix(matrix); + + //------------------------------------------------------------ + // Pack (serialize) and send + imgMsg->Pack(); + socket->Send(imgMsg->GetPackPointer(), imgMsg->GetPackSize()); + + igtl::Sleep(interval); // wait + + } + + //------------------------------------------------------------ + // Close connection + socket->CloseSocket(); + +} + + +//------------------------------------------------------------ +// Function to read test image data +int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i) +{ + + //------------------------------------------------------------ + // Check if image index is in the range + if (i < 0 || i >= 5) + { + std::cerr << "Image index is invalid." << std::endl; + return 0; + } + + //------------------------------------------------------------ + // Generate path to the raw image file + char filename[128]; + sprintf(filename, "%s/igtlTestImage%d.raw", dir, i+1); + std::cerr << "Reading " << filename << "..."; + + //------------------------------------------------------------ + // Load raw data from the file + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) + { + std::cerr << "File opeining error: " << filename << std::endl; + return 0; + } + int fsize = msg->GetImageSize(); + size_t b = fread(msg->GetScalarPointer(), 1, fsize, fp); + + fclose(fp); + + std::cerr << "done." << std::endl; + + return 1; +} + +//------------------------------------------------------------ +// Function to generate random matrix. +void GetRandomTestMatrix(igtl::Matrix4x4& matrix) +{ + //float position[3]; + //float orientation[4]; + + /* + // random position + static float phi = 0.0; + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 0; + phi = phi + 0.2; + + // random orientation + static float theta = 0.0; + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + */ + + matrix[0][0] = 1.0; matrix[1][0] = 0.0; matrix[2][0] = 0.0; matrix[3][0] = 0.0; + matrix[0][1] = 0.0; matrix[1][1] = -1.0; matrix[2][1] = 0.0; matrix[3][1] = 0.0; + matrix[0][2] = 0.0; matrix[1][2] = 0.0; matrix[2][2] = 1.0; matrix[3][2] = 0.0; + matrix[0][3] = 0.0; matrix[1][3] = 0.0; matrix[2][3] = 0.0; matrix[3][3] = 1.0; + + igtl::PrintMatrix(matrix); +} + diff --git a/openigtlink/repo/Examples/Imager/ImagerClient2.cxx b/openigtlink/repo/Examples/Imager/ImagerClient2.cxx new file mode 100644 index 0000000..042e226 --- /dev/null +++ b/openigtlink/repo/Examples/Imager/ImagerClient2.cxx @@ -0,0 +1,197 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Imager Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlImageMessage2.h" +#include "igtlClientSocket.h" + +int GetTestImage(char * image, const char* dir, int i); +void GetRandomTestMatrix(igtl::Matrix4x4& matrix); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 5) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + std::cerr << " : file directory, where \"igtlTestImage[1-5].raw\" are placed." << std::endl; + std::cerr << " (usually, in the Examples/Imager/img directory.)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int interval = (int) (1000.0 / fps); + char* filedir = argv[4]; + + //------------------------------------------------------------ + // Establish Connection + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + char * image = new char [256 * 256]; + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + //------------------------------------------------------------ + // size parameters + int size[] = {256, 256, 1}; // image dimension + float spacing[] = {1.0, 1.0, 5.0}; // spacing (mm/pixel) + int svsize[] = {256, 256, 1}; // sub-volume size + int svoffset[] = {0, 0, 0}; // sub-volume offset + int scalarType = igtl::ImageMessage2::TYPE_UINT8;// scalar type + + + //------------------------------------------------------------ + // Create a new IMAGE type message + igtl::ImageMessage2::Pointer imgMsg = igtl::ImageMessage2::New(); + imgMsg->SetDimensions(size); + imgMsg->SetSpacing(spacing); + imgMsg->SetScalarType(scalarType); + imgMsg->SetDeviceName("ImagerClient"); + imgMsg->SetSubVolume(svsize, svoffset); + imgMsg->AllocateScalars(); + + // Following line may be called in case of 16-, 32-, and 64-bit scalar types. + // imgMsg->SetEndian(igtl::ImageMessage::ENDIAN_BIG); + + //------------------------------------------------------------ + // Set image data (See GetTestImage() bellow for the details) + GetTestImage(image, filedir, i % 5); + + imgMsg->SetScalarPointer(image); + + //------------------------------------------------------------ + // Get random orientation matrix and set it. + igtl::Matrix4x4 matrix; + GetRandomTestMatrix(matrix); + imgMsg->SetMatrix(matrix); + + //------------------------------------------------------------ + // Pack (serialize) and send + imgMsg->Pack(); + //socket->Send(imgMsg->GetPackPointer(), imgMsg->GetPackSize()); + for (int i = 0; i < imgMsg->GetNumberOfPackFragments(); i ++) + { + socket->Send(imgMsg->GetPackFragmentPointer(i), imgMsg->GetPackFragmentSize(i)); + } + + + igtl::Sleep(interval); // wait + + } + + //------------------------------------------------------------ + // Close connection + socket->CloseSocket(); + +} + + +//------------------------------------------------------------ +// Function to read test image data +int GetTestImage(char * image, const char* dir, int i) +{ + + //------------------------------------------------------------ + // Check if image index is in the range + if (i < 0 || i >= 5) + { + std::cerr << "Image index is invalid." << std::endl; + return 0; + } + + //------------------------------------------------------------ + // Generate path to the raw image file + char filename[128]; + sprintf(filename, "%s/igtlTestImage%d.raw", dir, i+1); + std::cerr << "Reading " << filename << "..."; + + //------------------------------------------------------------ + // Load raw data from the file + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) + { + std::cerr << "File opeining error: " << filename << std::endl; + return 0; + } + size_t b = fread(image, 1, 256*256, fp); + + fclose(fp); + + std::cerr << "done." << std::endl; + + return 1; +} + +//------------------------------------------------------------ +// Function to generate random matrix. +void GetRandomTestMatrix(igtl::Matrix4x4& matrix) +{ + //float position[3]; + //float orientation[4]; + + /* + // random position + static float phi = 0.0; + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 0; + phi = phi + 0.2; + + // random orientation + static float theta = 0.0; + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + */ + + matrix[0][0] = 1.0; matrix[1][0] = 0.0; matrix[2][0] = 0.0; matrix[3][0] = 0.0; + matrix[0][1] = 0.0; matrix[1][1] = -1.0; matrix[2][1] = 0.0; matrix[3][1] = 0.0; + matrix[0][2] = 0.0; matrix[1][2] = 0.0; matrix[2][2] = 1.0; matrix[3][2] = 0.0; + matrix[0][3] = 0.0; matrix[1][3] = 0.0; matrix[2][3] = 0.0; matrix[3][3] = 1.0; + + igtl::PrintMatrix(matrix); +} + diff --git a/openigtlink/repo/Examples/Imager/ImagerClient3.cxx b/openigtlink/repo/Examples/Imager/ImagerClient3.cxx new file mode 100644 index 0000000..3b3c5b7 --- /dev/null +++ b/openigtlink/repo/Examples/Imager/ImagerClient3.cxx @@ -0,0 +1,211 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Imager Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include + +#include "igtl_header.h" +#include "igtlOSUtil.h" +#include "igtlImageMessage.h" +#include "igtlClientSocket.h" + +int ReceiveImageData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header, int loop); +int SaveTestImage(igtl::ImageMessage::Pointer& msg, int i); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 5) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + std::cerr << " Version : Version number send to the server" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int version = atoi(argv[4]); + int interval = (int) (1000.0 / fps); + //------------------------------------------------------------ + // Establish Connection + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + if (version > IGTL_HEADER_VERSION_2 || version < IGTL_HEADER_VERSION_1) + { + std::cerr << "Invalid version number" << std::endl; + exit(0); + } + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Ask the server to start pushing tracking data + std::cerr << "Sending Get_Image message....." << std::endl; + igtl::GetImageMessage::Pointer getImageMsg; + getImageMsg = igtl::GetImageMessage::New(); + getImageMsg->SetDeviceName("ImageClient"); + getImageMsg->SetHeaderVersion(version); + getImageMsg->Pack(); + socket->Send(getImageMsg->GetPackPointer(), getImageMsg->GetPackSize()); + + int loop = 0; + + while (1) + { + //------------------------------------------------------------ + // Wait for a reply + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + std::cerr << "Message size information and actual data size don't match." << std::endl; + socket->CloseSocket(); + exit(0); + } + + headerMsg->Unpack(); + if (headerMsg->GetHeaderVersion() != version) + { + std::cerr << "Version of the client and server don't match." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (strcmp(headerMsg->GetDeviceName(), "ImagerClient") == 0) + { + ReceiveImageData(socket, headerMsg, loop); + igtl::Sleep(interval); + } + else + { + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + if (++loop >= 100) // if received 100 times + { + //------------------------------------------------------------ + // Ask the server to stop pushing tracking data + std::cerr << "Sending STP_IMAGE message....." << std::endl; + igtl::StopImageMessage::Pointer stopImageMsg; + stopImageMsg = igtl::StopImageMessage::New(); + stopImageMsg->SetDeviceName("ImageClient"); + stopImageMsg->Pack(); + socket->Send(stopImageMsg->GetPackPointer(), stopImageMsg->GetPackSize()); + loop = 0; + } + } + +} + + +//------------------------------------------------------------ +// Function to read test image data +int ReceiveImageData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header,int loop) +{ + + std::cerr << "Receiving TDATA data type." << std::endl; + + //------------------------------------------------------------ + // Allocate TrackingData Message Class + + igtl::ImageMessage::Pointer imageData; + imageData = igtl::ImageMessage::New(); + imageData->SetMessageHeader(header);//Here the version is also set + imageData->AllocatePack(); + + // Receive body from the socket + bool timeout(false); + socket->Receive(imageData->GetPackBodyPointer(), imageData->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = imageData->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { +#if OpenIGTLink_HEADER_VERSION >= 2 + if (imageData->GetHeaderVersion() >= IGTL_HEADER_VERSION_2) + { + int i = 0; + for (std::map >::const_iterator it = imageData->GetMetaData().begin(); it != imageData->GetMetaData().end(); ++it, ++i) + { + std::cerr<<"The message ID is:"<< " " << imageData->GetMessageID() << std::endl; + std::cerr<< it->first << " coding scheme: " << it->second.first << " " << it->second.second << std::endl; + } + } +#endif + SaveTestImage(imageData, loop); + return 1; + } + return 0; +} + + +//------------------------------------------------------------ +// Function to read test image data +int SaveTestImage(igtl::ImageMessage::Pointer& msg, int i) +{ + + //------------------------------------------------------------ + // Check if image index is in the range + if (i < 0 || i >= 100) + { + std::cerr << "Image index is invalid." << std::endl; + return 0; + } + + //------------------------------------------------------------ + // Generate path to the raw image file + char filename[128]; + sprintf(filename, "igtlSaveImage%d.raw", i+1); + std::cerr << "Saving " << filename << "..."; + + //------------------------------------------------------------ + // Load raw data from the file + FILE *fp = fopen(filename, "wb"); + if (fp == NULL) + { + std::cerr << "File opeining error: " << filename << std::endl; + return 0; + } + int fsize = msg->GetImageSize(); + size_t b = fwrite(msg->GetScalarPointer(), 1, fsize, fp); + + fclose(fp); + + std::cerr << "done." << std::endl; + + return 1; +} + diff --git a/openigtlink/repo/Examples/Imager/ImagerServer.cxx b/openigtlink/repo/Examples/Imager/ImagerServer.cxx new file mode 100644 index 0000000..52705cc --- /dev/null +++ b/openigtlink/repo/Examples/Imager/ImagerServer.cxx @@ -0,0 +1,202 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlImageMessage.h" +#include "igtlServerSocket.h" + + + +int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i); +void GetRandomTestMatrix(igtl::Matrix4x4& matrix); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 4) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + std::cerr << " : file directory, where \"igtlTestImage[1-5].raw\" are placed." << std::endl; + std::cerr << " (usually, in the Examples/Imager/img directory.)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + double fps = atof(argv[2]); + int interval = (int) (1000.0 / fps); + char* filedir = argv[3]; + + + //------------------------------------------------------------ + // Prepare server socket + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + //------------------------------------------------------------ + // size parameters + int size[] = {256, 256, 1}; // image dimension + float spacing[] = {1.0, 1.0, 5.0}; // spacing (mm/pixel) + int svsize[] = {256, 256, 1}; // sub-volume size + int svoffset[] = {0, 0, 0}; // sub-volume offset + int scalarType = igtl::ImageMessage::TYPE_UINT8;// scalar type + + //------------------------------------------------------------ + // Create a new IMAGE type message + igtl::ImageMessage::Pointer imgMsg = igtl::ImageMessage::New(); + imgMsg->SetDimensions(size); + imgMsg->SetSpacing(spacing); + imgMsg->SetScalarType(scalarType); + imgMsg->SetDeviceName("ImagerClient"); + imgMsg->SetSubVolume(svsize, svoffset); + imgMsg->AllocateScalars(); + + // Following line may be called in case of 16-, 32-, and 64-bit scalar types. + // imgMsg->SetEndian(igtl::ImageMessage::ENDIAN_BIG); + + //------------------------------------------------------------ + // Set image data (See GetTestImage() bellow for the details) + GetTestImage(imgMsg, filedir, i % 5); + + //------------------------------------------------------------ + // Get randome orientation matrix and set it. + igtl::Matrix4x4 matrix; + GetRandomTestMatrix(matrix); + imgMsg->SetMatrix(matrix); + + //------------------------------------------------------------ + // Pack (serialize) and send + imgMsg->Pack(); + socket->Send(imgMsg->GetPackPointer(), imgMsg->GetPackSize()); + + igtl::Sleep(interval); // wait + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + + +//------------------------------------------------------------ +// Function to read test image data +int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i) +{ + + //------------------------------------------------------------ + // Check if image index is in the range + if (i < 0 || i >= 5) + { + std::cerr << "Image index is invalid." << std::endl; + return 0; + } + + //------------------------------------------------------------ + // Generate path to the raw image file + char filename[128]; + sprintf(filename, "%s/igtlTestImage%d.raw", dir, i+1); + std::cerr << "Reading " << filename << "..."; + + //------------------------------------------------------------ + // Load raw data from the file + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) + { + std::cerr << "File opeining error: " << filename << std::endl; + return 0; + } + int fsize = msg->GetImageSize(); + size_t b = fread(msg->GetScalarPointer(), 1, fsize, fp); + + fclose(fp); + + std::cerr << "done." << std::endl; + + return 1; +} + + +//------------------------------------------------------------ +// Function to generate random matrix. +void GetRandomTestMatrix(igtl::Matrix4x4& matrix) +{ + /* + float position[3]; + float orientation[4]; + + // random position + static float phi = 0.0; + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 0; + phi = phi + 0.2; + + // random orientation + static float theta = 0.0; + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + */ + + matrix[0][0] = 1.0; matrix[1][0] = 0.0; matrix[2][0] = 0.0; matrix[3][0] = 0.0; + matrix[0][1] = 0.0; matrix[1][1] = -1.0; matrix[2][1] = 0.0; matrix[3][1] = 0.0; + matrix[0][2] = 0.0; matrix[1][2] = 0.0; matrix[2][2] = 1.0; matrix[3][2] = 0.0; + matrix[0][3] = 0.0; matrix[1][3] = 0.0; matrix[2][3] = 0.0; matrix[3][3] = 1.0; + + igtl::PrintMatrix(matrix); +} + diff --git a/openigtlink/repo/Examples/Imager/ImagerServer3.cxx b/openigtlink/repo/Examples/Imager/ImagerServer3.cxx new file mode 100644 index 0000000..929dd29 --- /dev/null +++ b/openigtlink/repo/Examples/Imager/ImagerServer3.cxx @@ -0,0 +1,227 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include + +#include "igtl_header.h" +#include "igtlOSUtil.h" +#include "igtlImageMessage.h" +#include "igtlServerSocket.h" + + + +int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i); +void GetRandomTestMatrix(igtl::Matrix4x4& matrix); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 4) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + std::cerr << " : file directory, where \"igtlTestImage[1-5].raw\" are placed." << std::endl; + std::cerr << " (usually, in the Examples/Imager/img directory.)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + double fps = atof(argv[2]); + int interval = (int) (1000.0 / fps); + char* filedir = argv[3]; + + + //------------------------------------------------------------ + // Prepare server socket + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == headerMsg->GetPackSize()) + { + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "GET_IMAGE") == 0) + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + //------------------------------------------------------------ + // size parameters + int size[] = {256, 256, 1}; // image dimension + float spacing[] = {1.0, 1.0, 5.0}; // spacing (mm/pixel) + int svsize[] = {256, 256, 1}; // sub-volume size + int svoffset[] = {0, 0, 0}; // sub-volume offset + int scalarType = igtl::ImageMessage::TYPE_UINT8;// scalar type + + //------------------------------------------------------------ + // Create a new IMAGE type message + igtl::ImageMessage::Pointer imgMsg = igtl::ImageMessage::New(); + imgMsg->SetDimensions(size); + imgMsg->SetSpacing(spacing); + imgMsg->SetScalarType(scalarType); + imgMsg->SetDeviceName("ImagerClient"); + imgMsg->SetSubVolume(svsize, svoffset); + imgMsg->SetHeaderVersion(headerMsg->GetHeaderVersion()); +#if OpenIGTLink_HEADER_VERSION >= 2 + if (headerMsg->GetHeaderVersion() == IGTL_HEADER_VERSION_2) + { + imgMsg->SetMetaDataElement("Patient age", IANA_TYPE_US_ASCII, "25"); + imgMsg->SetMessageID(i); + } +#endif + imgMsg->AllocateScalars(); + + // Following line may be called in case of 16-, 32-, and 64-bit scalar types. + // imgMsg->SetEndian(igtl::ImageMessage::ENDIAN_BIG); + + //------------------------------------------------------------ + // Set image data (See GetTestImage() bellow for the details) + GetTestImage(imgMsg, filedir, i % 5); + + //------------------------------------------------------------ + // Get random orientation matrix and set it. + igtl::Matrix4x4 matrix; + GetRandomTestMatrix(matrix); + imgMsg->SetMatrix(matrix); + + //------------------------------------------------------------ + // Pack (serialize) and send + imgMsg->Pack(); + socket->Send(imgMsg->GetPackPointer(), imgMsg->GetPackSize()); + + igtl::Sleep(interval); // wait + } + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + + +//------------------------------------------------------------ +// Function to read test image data +int GetTestImage(igtl::ImageMessage::Pointer& msg, const char* dir, int i) +{ + + //------------------------------------------------------------ + // Check if image index is in the range + if (i < 0 || i >= 5) + { + std::cerr << "Image index is invalid." << std::endl; + return 0; + } + + //------------------------------------------------------------ + // Generate path to the raw image file + char filename[128]; + sprintf(filename, "%s/igtlTestImage%d.raw", dir, i+1); + std::cerr << "Reading " << filename << "..."; + + //------------------------------------------------------------ + // Load raw data from the file + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) + { + std::cerr << "File opeining error: " << filename << std::endl; + return 0; + } + int fsize = msg->GetImageSize(); + size_t b = fread(msg->GetScalarPointer(), 1, fsize, fp); + + fclose(fp); + + std::cerr << "done." << std::endl; + + return 1; +} + + +//------------------------------------------------------------ +// Function to generate random matrix. +void GetRandomTestMatrix(igtl::Matrix4x4& matrix) +{ + /* + float position[3]; + float orientation[4]; + + // random position + static float phi = 0.0; + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 0; + phi = phi + 0.2; + + // random orientation + static float theta = 0.0; + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + */ + + matrix[0][0] = 1.0; matrix[1][0] = 0.0; matrix[2][0] = 0.0; matrix[3][0] = 0.0; + matrix[0][1] = 0.0; matrix[1][1] = -1.0; matrix[2][1] = 0.0; matrix[3][1] = 0.0; + matrix[0][2] = 0.0; matrix[1][2] = 0.0; matrix[2][2] = 1.0; matrix[3][2] = 0.0; + matrix[0][3] = 0.0; matrix[1][3] = 0.0; matrix[2][3] = 0.0; matrix[3][3] = 1.0; + + igtl::PrintMatrix(matrix); +} + diff --git a/openigtlink/repo/Examples/Imager/img/igtlTestImage1.raw b/openigtlink/repo/Examples/Imager/img/igtlTestImage1.raw new file mode 100644 index 0000000..c761445 Binary files /dev/null and b/openigtlink/repo/Examples/Imager/img/igtlTestImage1.raw differ diff --git a/openigtlink/repo/Examples/Imager/img/igtlTestImage2.raw b/openigtlink/repo/Examples/Imager/img/igtlTestImage2.raw new file mode 100644 index 0000000..3d97aa8 Binary files /dev/null and b/openigtlink/repo/Examples/Imager/img/igtlTestImage2.raw differ diff --git a/openigtlink/repo/Examples/Imager/img/igtlTestImage3.raw b/openigtlink/repo/Examples/Imager/img/igtlTestImage3.raw new file mode 100644 index 0000000..0f1df7b Binary files /dev/null and b/openigtlink/repo/Examples/Imager/img/igtlTestImage3.raw differ diff --git a/openigtlink/repo/Examples/Imager/img/igtlTestImage4.raw b/openigtlink/repo/Examples/Imager/img/igtlTestImage4.raw new file mode 100644 index 0000000..c6c0892 Binary files /dev/null and b/openigtlink/repo/Examples/Imager/img/igtlTestImage4.raw differ diff --git a/openigtlink/repo/Examples/Imager/img/igtlTestImage5.raw b/openigtlink/repo/Examples/Imager/img/igtlTestImage5.raw new file mode 100644 index 0000000..50e67dc Binary files /dev/null and b/openigtlink/repo/Examples/Imager/img/igtlTestImage5.raw differ diff --git a/openigtlink/repo/Examples/Imager/img/igtlTestImage6.raw b/openigtlink/repo/Examples/Imager/img/igtlTestImage6.raw new file mode 100644 index 0000000..72a23f4 Binary files /dev/null and b/openigtlink/repo/Examples/Imager/img/igtlTestImage6.raw differ diff --git a/openigtlink/repo/Examples/Point/CMakeLists.txt b/openigtlink/repo/Examples/Point/CMakeLists.txt new file mode 100644 index 0000000..2d9a057 --- /dev/null +++ b/openigtlink/repo/Examples/Point/CMakeLists.txt @@ -0,0 +1,25 @@ +PROJECT(Point) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(PointClient PointClient.cxx) +TARGET_LINK_LIBRARIES(PointClient OpenIGTLink) + +ADD_EXECUTABLE(PointServer PointServer.cxx) +TARGET_LINK_LIBRARIES(PointServer OpenIGTLink) + +ADD_EXECUTABLE(PointListServer PointListServer.cxx) +TARGET_LINK_LIBRARIES(PointListServer OpenIGTLink) + +ADD_EXECUTABLE(PointClient3 PointClient3.cxx) +TARGET_LINK_LIBRARIES(PointClient3 OpenIGTLink) + +ADD_EXECUTABLE(PointServer3 PointServer3.cxx) +TARGET_LINK_LIBRARIES(PointServer3 OpenIGTLink) \ No newline at end of file diff --git a/openigtlink/repo/Examples/Point/PointClient.cxx b/openigtlink/repo/Examples/Point/PointClient.cxx new file mode 100644 index 0000000..ab3ced6 --- /dev/null +++ b/openigtlink/repo/Examples/Point/PointClient.cxx @@ -0,0 +1,110 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlPointMessage.h" +#include "igtlClientSocket.h" + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Transform Message Class + + igtl::PointMessage::Pointer pointMsg; + pointMsg = igtl::PointMessage::New(); + pointMsg->SetDeviceName("PointSender"); + + //--------------------------- + // Create 1st point + igtl::PointElement::Pointer point0; + point0 = igtl::PointElement::New(); + point0->SetName("POINT_0"); + point0->SetGroupName("GROUP_0"); + point0->SetRGBA(0xFF, 0x00, 0x00, 0xFF); + point0->SetPosition(10.0, 20.0, 30.0); + point0->SetRadius(15.0); + point0->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 2nd point + igtl::PointElement::Pointer point1; + point1 = igtl::PointElement::New(); + point1->SetName("POINT_1"); + point1->SetGroupName("GROUP_0"); + point1->SetRGBA(0x00, 0xFF, 0x00, 0xFF); + point1->SetPosition(40.0, 50.0, 60.0); + point1->SetRadius(45.0); + point1->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 3rd point + igtl::PointElement::Pointer point2; + point2 = igtl::PointElement::New(); + point2->SetName("POINT_2"); + point2->SetGroupName("GROUP_0"); + point2->SetRGBA(0x00, 0x00, 0xFF, 0xFF); + point2->SetPosition(70.0, 80.0, 90.0); + point2->SetRadius(75.0); + point2->SetOwner("IMAGE_0"); + + //--------------------------- + // Pack into the point message + pointMsg->AddPointElement(point0); + pointMsg->AddPointElement(point1); + pointMsg->AddPointElement(point2); + pointMsg->Pack(); + + //------------------------------------------------------------ + // Send + socket->Send(pointMsg->GetPackPointer(), pointMsg->GetPackSize()); + + + //------------------------------------------------------------ + // Close the socket + socket->CloseSocket(); + +} + diff --git a/openigtlink/repo/Examples/Point/PointClient3.cxx b/openigtlink/repo/Examples/Point/PointClient3.cxx new file mode 100644 index 0000000..4aa50c4 --- /dev/null +++ b/openigtlink/repo/Examples/Point/PointClient3.cxx @@ -0,0 +1,157 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlPointMessage.h" +#include "igtlClientSocket.h" + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 5) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + std::cerr << " Version : Version number send to the server" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int version = atoi(argv[4]); + int interval = (int) (1000.0 / fps); + //------------------------------------------------------------ + // Establish Connection + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + if (version > IGTL_HEADER_VERSION_2 || version < IGTL_HEADER_VERSION_1) + { + std::cerr << "Invalid version number" << std::endl; + exit(0); + } + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Ask the server to start pushing tracking data + std::cerr << "Sending GET_POINT message....." << std::endl; + igtl::GetPointMessage::Pointer getPointMsg; + getPointMsg = igtl::GetPointMessage::New(); + getPointMsg->SetDeviceName("PointClient"); + getPointMsg->SetHeaderVersion(version); + getPointMsg->Pack(); + socket->Send(getPointMsg->GetPackPointer(), getPointMsg->GetPackSize()); + + int loop = 0; + + while (1) + { + //------------------------------------------------------------ + // Wait for a reply + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + std::cerr << "Message size information and actual data size don't match." << std::endl; + socket->CloseSocket(); + exit(0); + } + + headerMsg->Unpack(); + if (headerMsg->GetHeaderVersion() != version) + { + std::cerr << "Version of the client and server don't match." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (strcmp(headerMsg->GetDeviceName(), "PointSender") == 0) + { + std::cerr << "Receiving Point data type." << std::endl; + + //------------------------------------------------------------ + // Allocate Point Data Message Class + + igtl::PointMessage::Pointer pointData; + pointData = igtl::PointMessage::New(); + pointData->SetMessageHeader(headerMsg);//Here the version is also set + pointData->AllocatePack(); + + // Receive body from the socket + bool timeout(false); + socket->Receive(pointData->GetPackBodyPointer(), pointData->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = pointData->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + if (pointData->GetHeaderVersion() >= IGTL_HEADER_VERSION_2) + { +#if OpenIGTLink_HEADER_VERSION >= 2 + int i = 0; + for (std::map >::const_iterator it = pointData->GetMetaData().begin(); it != pointData->GetMetaData().end(); ++it, ++i) + { + std::cerr<<"The message ID is:"<< " " << pointData->GetMessageID() << std::endl; + std::cerr<< it->first << " coding scheme: " << it->second.first << " " << it->second.second << std::endl; + } +#endif + } + } + igtl::PointElement::Pointer point; + for (int i = 0;i < pointData->GetNumberOfPointElement(); i++) + { + point = igtl::PointElement::New(); + pointData->GetPointElement(i, point); + igtlFloat32 x,y,z; + point->GetPosition(x,y,z); + const char * groupName = point->GetGroupName(); + const char * ownerName = point->GetOwner(); + std::cerr<<"point position: "<GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + +} + diff --git a/openigtlink/repo/Examples/Point/PointListServer.cxx b/openigtlink/repo/Examples/Point/PointListServer.cxx new file mode 100644 index 0000000..775874e --- /dev/null +++ b/openigtlink/repo/Examples/Point/PointListServer.cxx @@ -0,0 +1,225 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Image Meta Data Server + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlPointMessage.h" +#include "igtlServerSocket.h" + +using std::ifstream; +using std::stringstream; +using std::cerr; + +typedef struct { + double x; + double y; + double z; +} Point; + +typedef std::vector PointList; + +int SendPointList(igtl::Socket::Pointer& socket, const char *devicename, PointList points); +PointList DefaultPointList(); +PointList ReadPointList(char* ); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + PointList pointlist; + + if (argc < 2 || argc > 3) + { + // If not correct, print usage + std::cerr << "Sends OpenIGTLink point list upon POINT_GET request(s)" << std::endl; + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : [optional] file name, wherein each line contains 3 points to send" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + if (argc == 2) // check number of arguments + pointlist = DefaultPointList(); + else if (argc == 3) + { + char* filename = argv[2]; + pointlist = ReadPointList(filename); + } + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + socket->CloseSocket(); + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + std::cerr << "Receiving a message: " << std::endl; + std::cerr << " Device Type: \"" << headerMsg->GetDeviceType() << "\"" << std::endl; + std::cerr << " Device Name: \"" << headerMsg->GetDeviceName() << "\"" << std::endl; + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "GET_POINT") == 0) + { + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + SendPointList(socket, headerMsg->GetDeviceName(), pointlist); + } + else + { + // if the data type is unknown, skip reading. + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + socket->CloseSocket(); +} + + +int SendPointList(igtl::Socket::Pointer& socket, const char* name, PointList points) +{ + std::cout << "Sending PointList" << std::endl; + //------------------------------------------------------------ + // Allocate Point Message Class + igtl::PointMessage::Pointer pointMsg; + pointMsg = igtl::PointMessage::New(); + pointMsg->SetDeviceName("PointSender"); + + //--------------------------- + // Create a point message + int i = 0; + PointList::iterator pt_iter; + for (pt_iter = points.begin(); + pt_iter != points.end(); + ++pt_iter) + { + igtl::PointElement::Pointer point; + point = igtl::PointElement::New(); + stringstream pt_name; + pt_name << "POINT_" << i; + + point->SetName(pt_name.str().c_str()); + point->SetGroupName("GROUP_0"); + point->SetRGBA(0x00, 0x00, 0xFF, 0xFF); + point->SetPosition(pt_iter->x, pt_iter->y, pt_iter->z); + point->SetRadius(75.0); + point->SetOwner("IMAGE_0"); + + //--------------------------- + // Pack into the point message + pointMsg->AddPointElement(point); + i++; + } + pointMsg->Pack(); + + //--------------------------- + // Send + socket->Send(pointMsg->GetPackPointer(), pointMsg->GetPackSize()); + + return 1; +} + +//------------------------------------------------------------ +// Function to create default point list +PointList DefaultPointList() +{ + PointList points; + Point pt1 = {10.0, 20.0, 30.0}; + Point pt2 = {40.0, 50.0, 60.0}; + Point pt3 = {70.0, 80.0, 90.0}; + points.push_back(pt1); + points.push_back(pt2); + points.push_back(pt3); + return points; +} + + +//------------------------------------------------------------ +// Function to read test point data +PointList ReadPointList(char* filename) +{ + PointList points; + + //------------------------------------------------------------ + // Load point list from file + // file format is x y z\n + ifstream f_in(filename); + std::string line; + if (!f_in.is_open()) + { + std::cerr << "Error opening file: " << filename << std::endl; + exit(0); + } + + Point pt; + while ( f_in >> pt.x >> pt.y >> pt.z ) + points.push_back(pt); + + std::cerr << "Read: " << points.size() << " points from file." << std::endl; + return points; +} diff --git a/openigtlink/repo/Examples/Point/PointServer.cxx b/openigtlink/repo/Examples/Point/PointServer.cxx new file mode 100644 index 0000000..21e2763 --- /dev/null +++ b/openigtlink/repo/Examples/Point/PointServer.cxx @@ -0,0 +1,117 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Point Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlPointMessage.h" +#include "igtlServerSocket.h" + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + + //--------------------------- + // Create a point message + igtl::PointMessage::Pointer pointMsg; + pointMsg = igtl::PointMessage::New(); + pointMsg->SetDeviceName("PointSender"); + + //--------------------------- + // Create 1st point + igtl::PointElement::Pointer point0; + point0 = igtl::PointElement::New(); + point0->SetName("POINT_0"); + point0->SetGroupName("GROUP_0"); + point0->SetRGBA(0xFF, 0x00, 0x00, 0xFF); + point0->SetPosition(10.0, 20.0, 30.0); + point0->SetRadius(15.0); + point0->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 2nd point + igtl::PointElement::Pointer point1; + point1 = igtl::PointElement::New(); + point1->SetName("POINT_1"); + point1->SetGroupName("GROUP_0"); + point1->SetRGBA(0x00, 0xFF, 0x00, 0xFF); + point1->SetPosition(40.0, 50.0, 60.0); + point1->SetRadius(45.0); + point1->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 3rd point + igtl::PointElement::Pointer point2; + point2 = igtl::PointElement::New(); + point2->SetName("POINT_2"); + point2->SetGroupName("GROUP_0"); + point2->SetRGBA(0x00, 0x00, 0xFF, 0xFF); + point2->SetPosition(70.0, 80.0, 90.0); + point2->SetRadius(75.0); + point2->SetOwner("IMAGE_0"); + + //--------------------------- + // Pack into the point message + pointMsg->AddPointElement(point0); + pointMsg->AddPointElement(point1); + pointMsg->AddPointElement(point2); + pointMsg->Pack(); + + //--------------------------- + // Send + socket->Send(pointMsg->GetPackPointer(), pointMsg->GetPackSize()); + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + } + + socket->CloseSocket(); + +} + + diff --git a/openigtlink/repo/Examples/Point/PointServer3.cxx b/openigtlink/repo/Examples/Point/PointServer3.cxx new file mode 100644 index 0000000..60a022c --- /dev/null +++ b/openigtlink/repo/Examples/Point/PointServer3.cxx @@ -0,0 +1,148 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Point Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlPointMessage.h" +#include "igtlServerSocket.h" + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == headerMsg->GetPackSize()) + { + headerMsg->Unpack(); + int version = headerMsg->GetHeaderVersion(); + if (strcmp(headerMsg->GetDeviceType(), "GET_POINT") == 0) + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + //--------------------------- + // Create a point message + igtl::PointMessage::Pointer pointMsg; + pointMsg = igtl::PointMessage::New(); + pointMsg->SetHeaderVersion(version); + pointMsg->SetDeviceName("PointSender"); + + //--------------------------- + // Create 1st point + igtl::PointElement::Pointer point0; + point0 = igtl::PointElement::New(); + point0->SetName("POINT_0"); + point0->SetGroupName("GROUP_0"); + point0->SetRGBA(0xFF, 0x00, 0x00, 0xFF); + point0->SetPosition(10.0, 20.0, 30.0); + point0->SetRadius(15.0); + point0->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 2nd point + igtl::PointElement::Pointer point1; + point1 = igtl::PointElement::New(); + point1->SetName("POINT_1"); + point1->SetGroupName("GROUP_0"); + point1->SetRGBA(0x00, 0xFF, 0x00, 0xFF); + point1->SetPosition(40.0, 50.0, 60.0); + point1->SetRadius(45.0); + point1->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 3rd point + igtl::PointElement::Pointer point2; + point2 = igtl::PointElement::New(); + point2->SetName("POINT_2"); + point2->SetGroupName("GROUP_0"); + point2->SetRGBA(0x00, 0x00, 0xFF, 0xFF); + point2->SetPosition(70.0, 80.0, 90.0); + point2->SetRadius(75.0); + point2->SetOwner("IMAGE_0"); + + //--------------------------- + // Pack into the point message + pointMsg->AddPointElement(point0); + pointMsg->AddPointElement(point1); + pointMsg->AddPointElement(point2); + pointMsg->SetHeaderVersion(headerMsg->GetHeaderVersion()); +#if OpenIGTLink_HEADER_VERSION >= 2 + if (headerMsg->GetHeaderVersion() == IGTL_HEADER_VERSION_2) + { + pointMsg->SetMetaDataElement("First patient age", IANA_TYPE_US_ASCII, "22"); + pointMsg->SetMetaDataElement("Second patient age", IANA_TYPE_US_ASCII, "25"); + pointMsg->SetMessageID(i); + } +#endif + pointMsg->Pack(); + + //--------------------------- + // Send + socket->Send(pointMsg->GetPackPointer(), pointMsg->GetPackSize()); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + } + + socket->CloseSocket(); + +} + + diff --git a/openigtlink/repo/Examples/PolyData/CMakeLists.txt b/openigtlink/repo/Examples/PolyData/CMakeLists.txt new file mode 100644 index 0000000..58315bf --- /dev/null +++ b/openigtlink/repo/Examples/PolyData/CMakeLists.txt @@ -0,0 +1,19 @@ +PROJECT(PolyData) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + + +## igtl::PolyDataMessage examples +ADD_EXECUTABLE(PolyDataServer PolyDataServer.cxx) +TARGET_LINK_LIBRARIES(PolyDataServer OpenIGTLink) + +ADD_EXECUTABLE(PolyDataClient PolyDataClient.cxx) +TARGET_LINK_LIBRARIES(PolyDataClient OpenIGTLink) + diff --git a/openigtlink/repo/Examples/PolyData/PolyDataClient.cxx b/openigtlink/repo/Examples/PolyData/PolyDataClient.cxx new file mode 100644 index 0000000..d13f803 --- /dev/null +++ b/openigtlink/repo/Examples/PolyData/PolyDataClient.cxx @@ -0,0 +1,301 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Image Meta Data Client + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlPolyDataMessage.h" +#include "igtlClientSocket.h" + + +int ReceivePolyData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + + //------------------------------------------------------------ + // Establish Connection + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 10; i ++) + { + //------------------------------------------------------------ + // Send request data + igtl::GetPolyDataMessage::Pointer getPolyDataMsg; + getPolyDataMsg = igtl::GetPolyDataMessage::New(); + getPolyDataMsg->SetDeviceName("Client"); + getPolyDataMsg->Pack(); + socket->Send(getPolyDataMsg->GetPackPointer(), getPolyDataMsg->GetPackSize()); + + //------------------------------------------------------------ + // Wait for a reply + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + std::cerr << "Message size information and actual data size don't match." << std::endl; + exit(0); + } + + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "POLYDATA") == 0) + { + ReceivePolyData(socket, headerMsg); + } + else + { + std::cerr << "Invalid response from the server:" << headerMsg->GetDeviceName() << std::endl; + exit(0); + } + + igtl::Sleep(500); // wait + } + + //------------------------------------------------------------ + // Close connection + socket->CloseSocket(); + +} + + +int ReceivePolyData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving POLYDATA data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::PolyDataMessage::Pointer PolyData; + PolyData = igtl::PolyDataMessage::New(); + PolyData->SetMessageHeader(header); + PolyData->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(PolyData->GetPackBodyPointer(), PolyData->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = PolyData->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + igtl::PolyDataPointArray::Pointer pointsArray = PolyData->GetPoints(); + igtl::PolyDataCellArray::Pointer verticesArray = PolyData->GetVertices(); + igtl::PolyDataCellArray::Pointer linesArray = PolyData->GetLines(); + igtl::PolyDataCellArray::Pointer polygonsArray = PolyData->GetPolygons(); + igtl::PolyDataCellArray::Pointer triangleStripsArray = PolyData->GetTriangleStrips(); + + std::cerr << "========== PolyData Contents ==========" << std::endl; + if (pointsArray.IsNotNull()) + { + std::cerr << " ------ Points ------" << std::endl; + for (int i = 0; i < pointsArray->GetNumberOfPoints(); i ++) + { + igtlFloat32 point[3]; + pointsArray->GetPoint(i, point); + std::cerr << " point[" << i << "] = (" << point[0] << ", " + << point[1] << ", " << point[2] << ")" << std::endl; + } + } + + if (verticesArray.IsNotNull()) + { + std::cerr << " ------ Vertices ------" << std::endl; + for (unsigned int i = 0; i < verticesArray->GetNumberOfCells(); i ++) + { + std::list cell; + verticesArray->GetCell(i, cell); + std::list::iterator iter; + iter = cell.begin(); + if (iter != cell.end()) + { + std::cerr << " cell[" << i << "] = (" << *iter; + for (; iter != cell.end(); iter ++) + { + std::cerr << ", " << *iter; + } + std::cerr << ")" << std::endl; + } + } + } + + if (linesArray.IsNotNull()) + { + std::cerr << " ------ Lines ------" << std::endl; + for (unsigned int i = 0; i < linesArray->GetNumberOfCells(); i ++) + { + std::list cell; + linesArray->GetCell(i, cell); + std::list::iterator iter; + iter = cell.begin(); + if (iter != cell.end()) + { + std::cerr << " cell[" << i << "] = (" << *iter; + for (; iter != cell.end(); iter ++) + { + std::cerr << ", " << *iter; + } + std::cerr << ")" << std::endl; + } + } + } + + if (polygonsArray.IsNotNull()) + { + std::cerr << " ------ Polygons ------" << std::endl; + for (unsigned int i = 0; i < polygonsArray->GetNumberOfCells(); i ++) + { + std::list cell; + polygonsArray->GetCell(i, cell); + std::list::iterator iter; + iter = cell.begin(); + if (iter != cell.end()) + { + std::cerr << " cell[" << i << "] = (" << *iter; + for (; iter != cell.end(); iter ++) + { + std::cerr << ", " << *iter; + } + std::cerr << ")" << std::endl; + } + } + } + + if (triangleStripsArray.IsNotNull()) + { + std::cerr << " ------ TriangleStrips ------" << std::endl; + for (unsigned int i = 0; i < triangleStripsArray->GetNumberOfCells(); i ++) + { + std::list cell; + triangleStripsArray->GetCell(i, cell); + std::list::iterator iter; + iter = cell.begin(); + if (iter != cell.end()) + { + std::cerr << " cell[" << i << "] = (" << *iter; + for (; iter != cell.end(); iter ++) + { + std::cerr << ", " << *iter; + } + std::cerr << ")" << std::endl; + } + } + } + + unsigned int nAttr = PolyData->GetNumberOfAttributes(); + + for (unsigned int i = 0; i < nAttr; i ++) + { + std::cerr << " ------ Attributes #" << i << " ------" << std::endl; + igtl::PolyDataAttribute * p = PolyData->GetAttribute(static_cast(i)); + if (p) + { + std::cerr << " Name = " << p->GetName() << std::endl; + std::cerr << " Type = "; + switch (p->GetType()) + { + case igtl::PolyDataAttribute::POINT_SCALAR: + std::cerr << "POINT_SCALAR" << std::endl; + break; + case igtl::PolyDataAttribute::POINT_VECTOR: + std::cerr << "POINT_VECTOR" << std::endl; + break; + case igtl::PolyDataAttribute::POINT_NORMAL: + std::cerr << "POINT_NORMAL" << std::endl; + break; + case igtl::PolyDataAttribute::POINT_TENSOR: + std::cerr << "POINT_TENSOR" << std::endl; + break; + case igtl::PolyDataAttribute::POINT_RGBA: + std::cerr << "POINT_RGBA" << std::endl; + break; + case igtl::PolyDataAttribute::CELL_SCALAR: + std::cerr << "CELL_SCALAR" << std::endl; + break; + case igtl::PolyDataAttribute::CELL_VECTOR: + std::cerr << "CELL_VECTOR" << std::endl; + break; + case igtl::PolyDataAttribute::CELL_NORMAL: + std::cerr << "CELL_NORMAL" << std::endl; + break; + case igtl::PolyDataAttribute::CELL_TENSOR: + std::cerr << "CELL_TENSOR" << std::endl; + break; + case igtl::PolyDataAttribute::CELL_RGBA: + std::cerr << "CELL_RGBA" << std::endl; + break; + } + unsigned int size = p->GetSize(); + unsigned int ncomp = p->GetNumberOfComponents(); + igtlFloat32 * data = new igtlFloat32[ncomp]; + for (unsigned int j = 0; j < size; j ++) + { + p->GetNthData(j, data); + std::cerr << " data[" << j << "] = (" << data[0]; + for (unsigned int k = 1; k < ncomp; k ++) + { + std::cerr << ", " << data[k]; + } + std::cerr << ")" << std::endl; + } + } + } + + std::cerr << "================================" << std::endl; + return 1; + } + + return 0; + +} + + + diff --git a/openigtlink/repo/Examples/PolyData/PolyDataServer.cxx b/openigtlink/repo/Examples/PolyData/PolyDataServer.cxx new file mode 100644 index 0000000..22491de --- /dev/null +++ b/openigtlink/repo/Examples/PolyData/PolyDataServer.cxx @@ -0,0 +1,180 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Image Meta Data Server + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlServerSocket.h" +#include "igtlPolyDataMessage.h" + + +int SendPolyData(igtl::Socket::Pointer& socket, const char* name); + +int main(int argc, char* argv[]) +{ + + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + socket->CloseSocket(); + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "GET_POLYDATA") == 0) + { + std::cerr << "Received a GET_POLYDATA message." << std::endl; + //socket->Skip(headerMsg->GetBodySizeToRead(), 0); + SendPolyData(socket, headerMsg->GetDeviceName()); + } + else + { + // if the data type is unknown, skip reading. + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + socket->CloseSocket(); + +} + + +int SendPolyData(igtl::Socket::Pointer& socket, const char* name) +{ + + //------------------------------------------------------------ + // 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(name); + + // Geometry data + static igtlFloat32 pointsData[8][3]={{0,0,0}, {1,0,0}, {1,1,0}, {0,1,0}, + {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1}}; + static igtlUint32 polyData[6][4]={{0,3,2,1}, {4,5,6,7}, {0,1,5,4}, + {1,2,6,5}, {2,3,7,6}, {3,0,4,7}}; + static igtlFloat32 attributeData[8]={0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + + // Create point array + igtl::PolyDataPointArray::Pointer pointArray; + pointArray = igtl::PolyDataPointArray::New(); + for (unsigned int i = 0; i < 8; i ++) + { + pointArray->AddPoint(pointsData[i]); + } + polyDataMsg->SetPoints(pointArray); + + // Create polygon array + igtl::PolyDataCellArray::Pointer polyArray; + polyArray = igtl::PolyDataCellArray::New(); + for (unsigned int i = 0; i < 6; i ++) + { + polyArray->AddCell(4, polyData[i]); + } + polyDataMsg->SetPolygons(polyArray); + + // Create attribute array + igtl::PolyDataAttribute::Pointer attribute; + attribute = igtl::PolyDataAttribute::New(); + attribute->SetType(igtl::PolyDataAttribute::POINT_SCALAR); + attribute->SetName("attr"); + attribute->SetSize(8); + attribute->SetData(attributeData); + polyDataMsg->ClearAttributes(); + polyDataMsg->AddAttribute(attribute); + + polyDataMsg->Pack(); + std::cerr << "Size of pack: " << polyDataMsg->GetPackSize() << std::endl; + std::cerr << "Name of type: " << polyDataMsg->GetDeviceType() << std::endl; + std::cerr << "Sending a POLYDATA message..." << std::endl; + + socket->Send(polyDataMsg->GetPackPointer(), polyDataMsg->GetPackSize()); + + return 1; + +} + + + + + + + + diff --git a/openigtlink/repo/Examples/QuaternionTrackingData/CMakeLists.txt b/openigtlink/repo/Examples/QuaternionTrackingData/CMakeLists.txt new file mode 100644 index 0000000..873000e --- /dev/null +++ b/openigtlink/repo/Examples/QuaternionTrackingData/CMakeLists.txt @@ -0,0 +1,19 @@ +PROJECT(QuaternionTrackingData) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(QuaternionTrackingDataClient QuaternionTrackingDataClient.cxx) +TARGET_LINK_LIBRARIES(QuaternionTrackingDataClient OpenIGTLink) + +ADD_EXECUTABLE(QuaternionTrackingDataServer QuaternionTrackingDataServer.cxx) +TARGET_LINK_LIBRARIES(QuaternionTrackingDataServer OpenIGTLink) + + + diff --git a/openigtlink/repo/Examples/QuaternionTrackingData/QuaternionTrackingDataClient.cxx b/openigtlink/repo/Examples/QuaternionTrackingData/QuaternionTrackingDataClient.cxx new file mode 100644 index 0000000..89b258d --- /dev/null +++ b/openigtlink/repo/Examples/QuaternionTrackingData/QuaternionTrackingDataClient.cxx @@ -0,0 +1,165 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Quaternion Tracking Data Client + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlQuaternionTrackingDataMessage.h" +#include "igtlClientSocket.h" + + +int ReceiveQuaternionTrackingData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 4) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int interval = (int) (1000.0 / fps); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Ask the server to start pushing quaternion tracking data + std::cerr << "Sending STT_QTDATA message....." << std::endl; + igtl::StartQuaternionTrackingDataMessage::Pointer startQuaternionTrackingMsg; + startQuaternionTrackingMsg = igtl::StartQuaternionTrackingDataMessage::New(); + startQuaternionTrackingMsg->SetDeviceName("QTDataClient"); + startQuaternionTrackingMsg->SetResolution(interval); + startQuaternionTrackingMsg->SetCoordinateName("Patient"); + startQuaternionTrackingMsg->Pack(); + socket->Send(startQuaternionTrackingMsg->GetPackPointer(), startQuaternionTrackingMsg->GetPackSize()); + + int loop = 0; + + while (1) + { + //------------------------------------------------------------ + // Wait for a reply + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + std::cerr << "Message size information and actual data size don't match." << std::endl; + socket->CloseSocket(); + exit(0); + } + + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "QTDATA") == 0) + { + ReceiveQuaternionTrackingData(socket, headerMsg); + } + else + { + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + if (++loop >= 10) // if received 100 times + { + //------------------------------------------------------------ + // Ask the server to stop pushing quaternion tracking data + std::cerr << "Sending STP_QTDATA message....." << std::endl; + igtl::StopQuaternionTrackingDataMessage::Pointer stopQuaternionTrackingMsg; + stopQuaternionTrackingMsg = igtl::StopQuaternionTrackingDataMessage::New(); + stopQuaternionTrackingMsg->SetDeviceName("QTDataClient"); + stopQuaternionTrackingMsg->Pack(); + socket->Send(stopQuaternionTrackingMsg->GetPackPointer(), stopQuaternionTrackingMsg->GetPackSize()); + loop = 0; + } + } +} + + +int ReceiveQuaternionTrackingData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header) +{ + std::cerr << "Receiving QTDATA data type." << std::endl; + + //------------------------------------------------------------ + // Allocate QuaternionTrackingData Message Class + + igtl::QuaternionTrackingDataMessage::Pointer quaternionTrackingData; + quaternionTrackingData = igtl::QuaternionTrackingDataMessage::New(); + quaternionTrackingData->SetMessageHeader(header); + quaternionTrackingData->AllocatePack(); + + // Receive body from the socket + bool timeout(false); + socket->Receive(quaternionTrackingData->GetPackBodyPointer(), quaternionTrackingData->GetPackBodySize(), timeout); + + // Deserialize position and quaternion (orientation) data + // If you want to skip CRC check, call Unpack() without argument. + int c = quaternionTrackingData->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = quaternionTrackingData->GetNumberOfQuaternionTrackingDataElements(); + for (int i = 0; i < nElements; i ++) + { + igtl::QuaternionTrackingDataElement::Pointer quaternionTrackingElement; + quaternionTrackingData->GetQuaternionTrackingDataElement(i, quaternionTrackingElement); + + float position[3]; + float quaternion[4]; + quaternionTrackingElement->GetPosition(position); + quaternionTrackingElement->GetQuaternion(quaternion); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << quaternionTrackingElement->GetName() << std::endl; + std::cerr << " Type : " << (int) quaternionTrackingElement->GetType() << std::endl; + std::cerr << " Position : "; igtl::PrintVector3(position); + std::cerr << " Quaternion : "; igtl::PrintVector4(quaternion); + std::cerr << "================================" << std::endl; + } + return 1; + } + return 0; +} + + diff --git a/openigtlink/repo/Examples/QuaternionTrackingData/QuaternionTrackingDataServer.cxx b/openigtlink/repo/Examples/QuaternionTrackingData/QuaternionTrackingDataServer.cxx new file mode 100644 index 0000000..f097634 --- /dev/null +++ b/openigtlink/repo/Examples/QuaternionTrackingData/QuaternionTrackingDataServer.cxx @@ -0,0 +1,310 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Quaternion Tracking Data Server + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlServerSocket.h" +#include "igtlQuaternionTrackingDataMessage.h" +#include "igtlMultiThreader.h" + + +void* ThreadFunction(void* ptr); +int SendQuaternionTrackingData(igtl::Socket::Pointer& socket, igtl::QuaternionTrackingDataMessage::Pointer& quaternionTrackingMsg); +void GetRandomTestPositionAndQuaternion(float position[3], float quaternion[4], float phi, float theta); + +typedef struct { + int nloop; + igtl::MutexLock::Pointer glock; + igtl::Socket::Pointer socket; + int interval; + int stop; +} ThreadData; + + +int main(int argc, char* argv[]) +{ + + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + ThreadData td; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + int threadID = -1; + igtl::Socket::Pointer socket; + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + //------------------------------------------------------------ + // loop + for (;;) + { + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + if (threadID >= 0) + { + td.stop = 1; + threader->TerminateThread(threadID); + threadID = -1; + } + std::cerr << "Disconnecting the client." << std::endl; + td.socket = NULL; // VERY IMPORTANT. Completely remove the instance. + socket->CloseSocket(); + break; + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "STT_QTDATA") == 0) + { + std::cerr << "Received a STT_QTDATA message." << std::endl; + + igtl::StartQuaternionTrackingDataMessage::Pointer startQuaternionTracking; + startQuaternionTracking = igtl::StartQuaternionTrackingDataMessage::New(); + startQuaternionTracking->SetMessageHeader(headerMsg); + startQuaternionTracking->AllocatePack(); + + bool timeout(false); + igtlUint64 r2 = socket->Receive(startQuaternionTracking->GetPackBodyPointer(), startQuaternionTracking->GetPackBodySize(), timeout); + int c = startQuaternionTracking->Unpack(1); + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + td.interval = startQuaternionTracking->GetResolution(); + td.glock = glock; + td.socket = socket; + td.stop = 0; + threadID = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + } + } + else if (strcmp(headerMsg->GetDeviceType(), "STP_QTDATA") == 0) + { + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + std::cerr << "Received a STP_QTDATA message." << std::endl; + if (threadID >= 0) + { + td.stop = 1; + threader->TerminateThread(threadID); + threadID = -1; + std::cerr << "Disconnecting the client." << std::endl; + td.socket = NULL; // VERY IMPORTANT. Completely remove the instance. + socket->CloseSocket(); + } + break; + } + else + { + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + serverSocket->CloseSocket(); + +} + + +void* ThreadFunction(void* ptr) +{ + //------------------------------------------------------------ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + //int id = info->ThreadID; + //int nThread = info->NumberOfThreads; + ThreadData* td = static_cast(info->UserData); + + //------------------------------------------------------------ + // Get user data + igtl::MutexLock::Pointer glock = td->glock; + long interval = td->interval; + std::cerr << "Interval = " << interval << " (ms)" << std::endl; + //long interval = 1000; + //long interval = (id + 1) * 100; // (ms) + + igtl::Socket::Pointer& socket = td->socket; + + //------------------------------------------------------------ + // Allocate QuaternionTrackingData Message Class + // + // NOTE: QuaternionTrackingDataElement class instances are + // allocated before the loop starts to avoid + // reallocation in each image transfer. + + igtl::QuaternionTrackingDataMessage::Pointer quaternionTrackingMsg; + quaternionTrackingMsg = igtl::QuaternionTrackingDataMessage::New(); + + igtl::QuaternionTrackingDataElement::Pointer quaternionTrackElement0; + quaternionTrackElement0 = igtl::QuaternionTrackingDataElement::New(); + quaternionTrackElement0->SetName("Channel 0"); + quaternionTrackElement0->SetType(igtl::QuaternionTrackingDataElement::TYPE_TRACKER); + + igtl::QuaternionTrackingDataElement::Pointer quaternionTrackElement1; + quaternionTrackElement1 = igtl::QuaternionTrackingDataElement::New(); + quaternionTrackElement1->SetName("Channel 1"); + quaternionTrackElement1->SetType(igtl::QuaternionTrackingDataElement::TYPE_6D); + + igtl::QuaternionTrackingDataElement::Pointer quaternionTrackElement2; + quaternionTrackElement2 = igtl::QuaternionTrackingDataElement::New(); + quaternionTrackElement2->SetName("Channel 2"); + quaternionTrackElement2->SetType(igtl::QuaternionTrackingDataElement::TYPE_5D); + + quaternionTrackingMsg->AddQuaternionTrackingDataElement(quaternionTrackElement0); + quaternionTrackingMsg->AddQuaternionTrackingDataElement(quaternionTrackElement1); + quaternionTrackingMsg->AddQuaternionTrackingDataElement(quaternionTrackElement2); + + //------------------------------------------------------------ + // Loop + while (!td->stop) + { + quaternionTrackingMsg->SetDeviceName("Tracker"); + glock->Lock(); + SendQuaternionTrackingData(socket, quaternionTrackingMsg); + glock->Unlock(); + igtl::Sleep(interval); + } + + //glock->Lock(); + //std::cerr << "Thread #" << id << ": end." << std::endl; + //glock->Unlock(); + + return NULL; +} + + +int SendQuaternionTrackingData(igtl::Socket::Pointer& socket, igtl::QuaternionTrackingDataMessage::Pointer& quaternionTrackingMsg) +{ + + static float phi0 = 0.0; + static float theta0 = 0.0; + static float phi1 = 0.0; + static float theta1 = 0.0; + static float phi2 = 0.0; + static float theta2 = 0.0; + + float position[3]; + float quaternion[4]; + igtl::QuaternionTrackingDataElement::Pointer ptr; + + // Channel 0 + quaternionTrackingMsg->GetQuaternionTrackingDataElement(0, ptr); + GetRandomTestPositionAndQuaternion(position, quaternion, phi0, theta0); + ptr->SetPosition(position); + ptr->SetQuaternion(quaternion); + + // Channel 1 + quaternionTrackingMsg->GetQuaternionTrackingDataElement(1, ptr); + GetRandomTestPositionAndQuaternion(position, quaternion, phi1, theta1); + ptr->SetPosition(position); + ptr->SetQuaternion(quaternion); + + // Channel 2 + quaternionTrackingMsg->GetQuaternionTrackingDataElement(2, ptr); + GetRandomTestPositionAndQuaternion(position, quaternion, phi2, theta2); + ptr->SetPosition(position); + ptr->SetQuaternion(quaternion); + + quaternionTrackingMsg->Pack(); + socket->Send(quaternionTrackingMsg->GetPackPointer(), quaternionTrackingMsg->GetPackSize()); + + phi0 += 0.1; + phi1 += 0.2; + phi2 += 0.3; + theta0 += 0.2; + theta1 += 0.1; + theta2 += 0.05; + + return 0; +} + + + +//------------------------------------------------------------ +// Function to generate random position and orientation (quaternion). +void GetRandomTestPositionAndQuaternion(float position[3], float quaternion[4], float phi, float theta) +{ + // random position + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + phi = phi + 0.2; + + // random orientation + quaternion[0]=0.0; + quaternion[1]=0.6666666666*cos(theta); + quaternion[2]=0.577350269189626; + quaternion[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + //igtl::PrintVector3(position); + //igtl::PrintVector4(quaternion); +} + + + + + + diff --git a/openigtlink/repo/Examples/Receiver/CMakeLists.txt b/openigtlink/repo/Examples/Receiver/CMakeLists.txt new file mode 100644 index 0000000..3f721f6 --- /dev/null +++ b/openigtlink/repo/Examples/Receiver/CMakeLists.txt @@ -0,0 +1,16 @@ +PROJECT(Receiver) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(ReceiveServer ReceiveServer.cxx) +TARGET_LINK_LIBRARIES(ReceiveServer OpenIGTLink) + +ADD_EXECUTABLE(ReceiveClient ReceiveClient.cxx) +TARGET_LINK_LIBRARIES(ReceiveClient OpenIGTLink) diff --git a/openigtlink/repo/Examples/Receiver/ReceiveClient.cxx b/openigtlink/repo/Examples/Receiver/ReceiveClient.cxx new file mode 100644 index 0000000..71febe6 --- /dev/null +++ b/openigtlink/repo/Examples/Receiver/ReceiveClient.cxx @@ -0,0 +1,622 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Data Receiving Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlTransformMessage.h" +#include "igtlPositionMessage.h" +#include "igtlImageMessage.h" +#include "igtlClientSocket.h" +#include "igtlStatusMessage.h" + +#if OpenIGTLink_PROTOCOL_VERSION >= 2 +#include "igtlSensorMessage.h" +#include "igtlPointMessage.h" +#include "igtlTrajectoryMessage.h" +#include "igtlStringMessage.h" +#include "igtlTrackingDataMessage.h" +#include "igtlQuaternionTrackingDataMessage.h" +#include "igtlCapabilityMessage.h" +#endif // OpenIGTLink_PROTOCOL_VERSION >= 2 + +int ReceiveTransform(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); +int ReceivePosition(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); +int ReceiveImage(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); +int ReceiveStatus(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); + +#if OpenIGTLink_PROTOCOL_VERSION >= 2 + int ReceiveSensor(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); + int ReceivePoint(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); + int ReceiveTrajectory(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); + int ReceiveString(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); + int ReceiveTrackingData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); + int ReceiveQuaternionTrackingData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); + int ReceiveCapability(igtl::Socket * socket, igtl::MessageHeader * header); +#endif //OpenIGTLink_PROTOCOL_VERSION >= 2 + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + + //------------------------------------------------------------ + // Allocate a time stamp + igtl::TimeStamp::Pointer ts; + ts = igtl::TimeStamp::New(); + + + while (1) + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 r = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (r == 0) + { + socket->CloseSocket(); + exit(0); + } + if (r != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + // Get time stamp + igtlUint32 sec; + igtlUint32 nanosec; + + headerMsg->GetTimeStamp(ts); + ts->GetTimeStamp(&sec, &nanosec); + + std::cerr << "Name: " << headerMsg->GetDeviceName() << std::endl; + std::cerr << "Time stamp: " + << sec << "." << std::setw(9) << std::setfill('0') + << nanosec << std::endl; + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "TRANSFORM") == 0) + { + ReceiveTransform(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "POSITION") == 0) + { + ReceivePosition(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "IMAGE") == 0) + { + ReceiveImage(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "STATUS") == 0) + { + ReceiveStatus(socket, headerMsg); + } +#if OpenIGTLink_PROTOCOL_VERSION >= 2 + else if (strcmp(headerMsg->GetDeviceType(), "SENSOR") == 0) + { + ReceiveSensor(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "POINT") == 0) + { + ReceivePoint(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "TRAJ") == 0) + { + ReceiveTrajectory(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "STRING") == 0) + { + ReceiveString(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "TDATA") == 0) + { + ReceiveTrackingData(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "QTDATA") == 0) + { + ReceiveQuaternionTrackingData(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "CAPABILITY") == 0) + { + ReceiveCapability(socket, headerMsg);; + } +#endif //OpenIGTLink_PROTOCOL_VERSION >= 2 + else + { + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches this section ...) + + socket->CloseSocket(); + +} + + +int ReceiveTransform(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + std::cerr << "Receiving TRANSFORM data type." << std::endl; + + // Create a message buffer to receive transform datag + igtl::TransformMessage::Pointer transMsg; + transMsg = igtl::TransformMessage::New(); + transMsg->SetMessageHeader(header); + transMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(transMsg->GetPackBodyPointer(), transMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = transMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + // Retrive the transform data + igtl::Matrix4x4 matrix; + transMsg->GetMatrix(matrix); + igtl::PrintMatrix(matrix); + std::cerr << std::endl; + return 1; + } + + return 0; +} + +int ReceiveSensor(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + std::cerr << "Receiving SENSOR data type." << std::endl; + + // Create a message buffer to receive transform datag + igtl::SensorMessage::Pointer sensMsg; + sensMsg = igtl::SensorMessage::New(); + sensMsg->SetMessageHeader(header); + sensMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(sensMsg->GetPackBodyPointer(), sensMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = sensMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + for (size_t i = 0; i < sensMsg->GetLength(); ++i) { + std::cerr << "v[" << i << "]: " << sensMsg->GetValue(i) << " "; + } + std::cerr << std::endl; + return 1; + } + + return 0; +} + +int ReceivePosition(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + std::cerr << "Receiving POSITION data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::PositionMessage::Pointer positionMsg; + positionMsg = igtl::PositionMessage::New(); + positionMsg->SetMessageHeader(header); + positionMsg->AllocatePack(); + + // Receive position position data from the socket + bool timeout(false); + socket->Receive(positionMsg->GetPackBodyPointer(), positionMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = positionMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + // Retrive the transform data + float position[3]; + float quaternion[4]; + + positionMsg->GetPosition(position); + positionMsg->GetQuaternion(quaternion); + + std::cerr << "position = (" << position[0] << ", " << position[1] << ", " << position[2] << ")" << std::endl; + std::cerr << "quaternion = (" << quaternion[0] << ", " << quaternion[1] << ", " + << quaternion[2] << ", " << quaternion[3] << ")" << std::endl << std::endl; + + return 1; + } + + return 0; +} + +int ReceiveImage(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + std::cerr << "Receiving IMAGE data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::ImageMessage::Pointer imgMsg; + imgMsg = igtl::ImageMessage::New(); + imgMsg->SetMessageHeader(header); + imgMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(imgMsg->GetPackBodyPointer(), imgMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = imgMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + // Retrive the image data + int size[3]; // image dimension + float spacing[3]; // spacing (mm/pixel) + int svsize[3]; // sub-volume size + int svoffset[3]; // sub-volume offset + int scalarType; // scalar type + int endian; // endian + + scalarType = imgMsg->GetScalarType(); + endian = imgMsg->GetEndian(); + imgMsg->GetDimensions(size); + imgMsg->GetSpacing(spacing); + imgMsg->GetSubVolume(svsize, svoffset); + + + std::cerr << "Device Name : " << imgMsg->GetDeviceName() << std::endl; + std::cerr << "Scalar Type : " << scalarType << std::endl; + std::cerr << "Endian : " << endian << std::endl; + std::cerr << "Dimensions : (" + << size[0] << ", " << size[1] << ", " << size[2] << ")" << std::endl; + std::cerr << "Spacing : (" + << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << ")" << std::endl; + std::cerr << "Sub-Volume dimensions : (" + << svsize[0] << ", " << svsize[1] << ", " << svsize[2] << ")" << std::endl; + std::cerr << "Sub-Volume offset : (" + << svoffset[0] << ", " << svoffset[1] << ", " << svoffset[2] << ")" << std::endl << std::endl; + return 1; + } + + return 0; + +} + + +int ReceiveStatus(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving STATUS data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::StatusMessage::Pointer statusMsg; + statusMsg = igtl::StatusMessage::New(); + statusMsg->SetMessageHeader(header); + statusMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(statusMsg->GetPackBodyPointer(), statusMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = statusMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + std::cerr << "========== STATUS ==========" << std::endl; + std::cerr << " Code : " << statusMsg->GetCode() << std::endl; + std::cerr << " SubCode : " << statusMsg->GetSubCode() << std::endl; + std::cerr << " Error Name: " << statusMsg->GetErrorName() << std::endl; + std::cerr << " Status : " << statusMsg->GetStatusString() << std::endl; + std::cerr << "============================" << std::endl << std::endl; + } + + return 0; + +} + +#if OpenIGTLink_PROTOCOL_VERSION >= 2 +int ReceivePoint(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving POINT data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::PointMessage::Pointer pointMsg; + pointMsg = igtl::PointMessage::New(); + pointMsg->SetMessageHeader(header); + pointMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(pointMsg->GetPackBodyPointer(), pointMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = pointMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = pointMsg->GetNumberOfPointElement(); + for (int i = 0; i < nElements; i ++) + { + igtl::PointElement::Pointer pointElement; + pointMsg->GetPointElement(i, pointElement); + + igtlUint8 rgba[4]; + pointElement->GetRGBA(rgba); + + igtlFloat32 pos[3]; + pointElement->GetPosition(pos); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << pointElement->GetName() << std::endl; + std::cerr << " GroupName : " << pointElement->GetGroupName() << std::endl; + std::cerr << " RGBA : ( " << (int)rgba[0] << ", " << (int)rgba[1] << ", " << (int)rgba[2] << ", " << (int)rgba[3] << " )" << std::endl; + std::cerr << " Position : ( " << std::fixed << pos[0] << ", " << pos[1] << ", " << pos[2] << " )" << std::endl; + std::cerr << " Radius : " << std::fixed << pointElement->GetRadius() << std::endl; + std::cerr << " Owner : " << pointElement->GetOwner() << std::endl; + std::cerr << "================================" << std::endl << std::endl; + } + } + + return 1; +} + +int ReceiveTrajectory(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving TRAJECTORY data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::TrajectoryMessage::Pointer trajectoryMsg; + trajectoryMsg = igtl::TrajectoryMessage::New(); + trajectoryMsg->SetMessageHeader(header); + trajectoryMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(trajectoryMsg->GetPackBodyPointer(), trajectoryMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = trajectoryMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = trajectoryMsg->GetNumberOfTrajectoryElement(); + for (int i = 0; i < nElements; i ++) + { + igtl::TrajectoryElement::Pointer trajectoryElement; + trajectoryMsg->GetTrajectoryElement(i, trajectoryElement); + + igtlUint8 rgba[4]; + trajectoryElement->GetRGBA(rgba); + + igtlFloat32 entry[3]; + igtlFloat32 target[3]; + trajectoryElement->GetEntryPosition(entry); + trajectoryElement->GetTargetPosition(target); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << trajectoryElement->GetName() << std::endl; + std::cerr << " GroupName : " << trajectoryElement->GetGroupName() << std::endl; + std::cerr << " RGBA : ( " << (int)rgba[0] << ", " << (int)rgba[1] << ", " << (int)rgba[2] << ", " << (int)rgba[3] << " )" << std::endl; + std::cerr << " Entry Pt : ( " << std::fixed << entry[0] << ", " << entry[1] << ", " << entry[2] << " )" << std::endl; + std::cerr << " Target Pt : ( " << std::fixed << target[0] << ", " << target[1] << ", " << target[2] << " )" << std::endl; + std::cerr << " Radius : " << std::fixed << trajectoryElement->GetRadius() << std::endl; + std::cerr << " Owner : " << trajectoryElement->GetOwner() << std::endl; + std::cerr << "================================" << std::endl << std::endl; + } + } + + return 1; +} + +int ReceiveString(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving STRING data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::StringMessage::Pointer stringMsg; + stringMsg = igtl::StringMessage::New(); + stringMsg->SetMessageHeader(header); + stringMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(stringMsg->GetPackBodyPointer(), stringMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = stringMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + std::cerr << "Encoding: " << stringMsg->GetEncoding() << "; " + << "String: " << stringMsg->GetString() << std::endl << std::endl; + } + + return 1; +} + +int ReceiveTrackingData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header) +{ + std::cerr << "Receiving TDATA data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::TrackingDataMessage::Pointer trackingData; + trackingData = igtl::TrackingDataMessage::New(); + trackingData->SetMessageHeader(header); + trackingData->AllocatePack(); + + // Receive body from the socket + bool timeout(false); + socket->Receive(trackingData->GetPackBodyPointer(), trackingData->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = trackingData->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = trackingData->GetNumberOfTrackingDataElements(); + for (int i = 0; i < nElements; i ++) + { + igtl::TrackingDataElement::Pointer trackingElement; + trackingData->GetTrackingDataElement(i, trackingElement); + + igtl::Matrix4x4 matrix; + trackingElement->GetMatrix(matrix); + + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << trackingElement->GetName() << std::endl; + std::cerr << " Type : " << (int) trackingElement->GetType() << std::endl; + std::cerr << " Matrix : " << std::endl; + igtl::PrintMatrix(matrix); + std::cerr << "================================" << std::endl << std::endl; + } + return 1; + } + return 0; +} + +int ReceiveQuaternionTrackingData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header) +{ + std::cerr << "Receiving QTDATA data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::QuaternionTrackingDataMessage::Pointer quaternionTrackingData; + quaternionTrackingData = igtl::QuaternionTrackingDataMessage::New(); + quaternionTrackingData->SetMessageHeader(header); + quaternionTrackingData->AllocatePack(); + + // Receive body from the socket + bool timeout(false); + socket->Receive(quaternionTrackingData->GetPackBodyPointer(), quaternionTrackingData->GetPackBodySize(), timeout); + + // Deserialize position and quaternion (orientation) data + // If you want to skip CRC check, call Unpack() without argument. + int c = quaternionTrackingData->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = quaternionTrackingData->GetNumberOfQuaternionTrackingDataElements(); + for (int i = 0; i < nElements; i ++) + { + igtl::QuaternionTrackingDataElement::Pointer quaternionTrackingElement; + quaternionTrackingData->GetQuaternionTrackingDataElement(i, quaternionTrackingElement); + + float position[3]; + float quaternion[4]; + quaternionTrackingElement->GetPosition(position); + quaternionTrackingElement->GetQuaternion(quaternion); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << quaternionTrackingElement->GetName() << std::endl; + std::cerr << " Type : " << (int) quaternionTrackingElement->GetType() << std::endl; + std::cerr << " Position : "; igtl::PrintVector3(position); + std::cerr << " Quaternion : "; igtl::PrintVector4(quaternion); + std::cerr << "================================" << std::endl << std::endl; + } + return 1; + } + return 0; +} + +int ReceiveCapability(igtl::Socket * socket, igtl::MessageHeader * header) +{ + + std::cerr << "Receiving CAPABILITY data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::CapabilityMessage::Pointer capabilMsg; + capabilMsg = igtl::CapabilityMessage::New(); + capabilMsg->SetMessageHeader(header); + capabilMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(capabilMsg->GetPackBodyPointer(), capabilMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = capabilMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nTypes = capabilMsg->GetNumberOfTypes(); + for (int i = 0; i < nTypes; i ++) + { + std::cerr << "Typename #" << i << ": " << capabilMsg->GetType(i) << std::endl; + } + } + + return 1; + +} + +#endif //OpenIGTLink_PROTOCOL_VERSION >= 2 diff --git a/openigtlink/repo/Examples/Receiver/ReceiveServer.cxx b/openigtlink/repo/Examples/Receiver/ReceiveServer.cxx new file mode 100644 index 0000000..2bc8ca4 --- /dev/null +++ b/openigtlink/repo/Examples/Receiver/ReceiveServer.cxx @@ -0,0 +1,560 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Data Receiving Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlTransformMessage.h" +#include "igtlImageMessage.h" +#include "igtlServerSocket.h" +#include "igtlStatusMessage.h" +#include "igtlPositionMessage.h" + +#if OpenIGTLink_PROTOCOL_VERSION >= 2 +#include "igtlPointMessage.h" +#include "igtlTrajectoryMessage.h" +#include "igtlStringMessage.h" +#include "igtlBindMessage.h" +#include "igtlCapabilityMessage.h" +#endif //OpenIGTLink_PROTOCOL_VERSION >= 2 + + +int ReceiveTransform(igtl::Socket * socket, igtl::MessageHeader * header); +int ReceivePosition(igtl::Socket * socket, igtl::MessageHeader * header); +int ReceiveImage(igtl::Socket * socket, igtl::MessageHeader * header); +int ReceiveStatus(igtl::Socket * socket, igtl::MessageHeader * header); + +#if OpenIGTLink_PROTOCOL_VERSION >= 2 +int ReceivePoint(igtl::Socket * socket, igtl::MessageHeader * header); +int ReceiveTrajectory(igtl::Socket * socket, igtl::MessageHeader::Pointer& header); +int ReceiveString(igtl::Socket * socket, igtl::MessageHeader * header); +int ReceiveBind(igtl::Socket * socket, igtl::MessageHeader * header); +int ReceiveCapability(igtl::Socket * socket, igtl::MessageHeader * header); +#endif //OpenIGTLink_PROTOCOL_VERSION >= 2 + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + + //------------------------------------------------------------ + // Allocate a time stamp + igtl::TimeStamp::Pointer ts; + ts = igtl::TimeStamp::New(); + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 r = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (r == 0) + { + socket->CloseSocket(); + } + if (r != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + // Get time stamp + igtlUint32 sec; + igtlUint32 nanosec; + + headerMsg->GetTimeStamp(ts); + ts->GetTimeStamp(&sec, &nanosec); + + std::cerr << "Time stamp: " + << sec << "." << std::setw(9) << std::setfill('0') + << nanosec << std::endl; + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "TRANSFORM") == 0) + { + ReceiveTransform(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "POSITION") == 0) + { + ReceivePosition(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "IMAGE") == 0) + { + ReceiveImage(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "STATUS") == 0) + { + ReceiveStatus(socket, headerMsg); + } +#if OpenIGTLink_PROTOCOL_VERSION >= 2 + else if (strcmp(headerMsg->GetDeviceType(), "POINT") == 0) + { + ReceivePoint(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "TRAJ") == 0) + { + ReceiveTrajectory(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "STRING") == 0) + { + ReceiveString(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "BIND") == 0) + { + ReceiveBind(socket, headerMsg); + } + else if (strcmp(headerMsg->GetDeviceType(), "CAPABILITY") == 0) + { + ReceiveCapability(socket, headerMsg); + } +#endif //OpenIGTLink_PROTOCOL_VERSION >= 2 + else + { + // if the data type is unknown, skip reading. + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + std::cerr << "Size : " << headerMsg->GetBodySizeToRead() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + + socket->CloseSocket(); + +} + + +int ReceiveTransform(igtl::Socket * socket, igtl::MessageHeader * header) +{ + std::cerr << "Receiving TRANSFORM data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::TransformMessage::Pointer transMsg; + transMsg = igtl::TransformMessage::New(); + transMsg->SetMessageHeader(header); + transMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(transMsg->GetPackBodyPointer(), transMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = transMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + // Retrive the transform data + igtl::Matrix4x4 matrix; + transMsg->GetMatrix(matrix); + igtl::PrintMatrix(matrix); + return 1; + } + + return 0; + +} + + +int ReceivePosition(igtl::Socket * socket, igtl::MessageHeader * header) +{ + std::cerr << "Receiving POSITION data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::PositionMessage::Pointer positionMsg; + positionMsg = igtl::PositionMessage::New(); + positionMsg->SetMessageHeader(header); + positionMsg->AllocatePack(); + + // Receive position position data from the socket + bool timeout(false); + socket->Receive(positionMsg->GetPackBodyPointer(), positionMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = positionMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + // Retrive the transform data + float position[3]; + float quaternion[4]; + + positionMsg->GetPosition(position); + positionMsg->GetQuaternion(quaternion); + + std::cerr << "position = (" << position[0] << ", " << position[1] << ", " << position[2] << ")" << std::endl; + std::cerr << "quaternion = (" << quaternion[0] << ", " << quaternion[1] << ", " + << quaternion[2] << ", " << quaternion[3] << ")" << std::endl << std::endl; + + return 1; + } + + return 0; + +} + + +int ReceiveImage(igtl::Socket * socket, igtl::MessageHeader * header) +{ + std::cerr << "Receiving IMAGE data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::ImageMessage::Pointer imgMsg; + imgMsg = igtl::ImageMessage::New(); + imgMsg->SetMessageHeader(header); + imgMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(imgMsg->GetPackBodyPointer(), imgMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = imgMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + // Retrive the image data + int size[3]; // image dimension + float spacing[3]; // spacing (mm/pixel) + int svsize[3]; // sub-volume size + int svoffset[3]; // sub-volume offset + int scalarType; // scalar type + int endian; // endian + + scalarType = imgMsg->GetScalarType(); + endian = imgMsg->GetEndian(); + imgMsg->GetDimensions(size); + imgMsg->GetSpacing(spacing); + imgMsg->GetSubVolume(svsize, svoffset); + + std::cerr << "Device Name : " << imgMsg->GetDeviceName() << std::endl; + std::cerr << "Scalar Type : " << scalarType << std::endl; + std::cerr << "Endian : " << endian << std::endl; + std::cerr << "Dimensions : (" + << size[0] << ", " << size[1] << ", " << size[2] << ")" << std::endl; + std::cerr << "Spacing : (" + << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << ")" << std::endl; + std::cerr << "Sub-Volume dimensions : (" + << svsize[0] << ", " << svsize[1] << ", " << svsize[2] << ")" << std::endl; + std::cerr << "Sub-Volume offset : (" + << svoffset[0] << ", " << svoffset[1] << ", " << svoffset[2] << ")" << std::endl; + return 1; + } + + return 0; + +} + + +int ReceiveStatus(igtl::Socket * socket, igtl::MessageHeader * header) +{ + + std::cerr << "Receiving STATUS data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::StatusMessage::Pointer statusMsg; + statusMsg = igtl::StatusMessage::New(); + statusMsg->SetMessageHeader(header); + statusMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(statusMsg->GetPackBodyPointer(), statusMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = statusMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + std::cerr << "========== STATUS ==========" << std::endl; + std::cerr << " Code : " << statusMsg->GetCode() << std::endl; + std::cerr << " SubCode : " << statusMsg->GetSubCode() << std::endl; + std::cerr << " Error Name: " << statusMsg->GetErrorName() << std::endl; + std::cerr << " Status : " << statusMsg->GetStatusString() << std::endl; + std::cerr << "============================" << std::endl; + } + + return 0; + +} + + +#if OpenIGTLink_PROTOCOL_VERSION >= 2 +int ReceivePoint(igtl::Socket * socket, igtl::MessageHeader * header) +{ + + std::cerr << "Receiving POINT data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::PointMessage::Pointer pointMsg; + pointMsg = igtl::PointMessage::New(); + pointMsg->SetMessageHeader(header); + pointMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(pointMsg->GetPackBodyPointer(), pointMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = pointMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = pointMsg->GetNumberOfPointElement(); + for (int i = 0; i < nElements; i ++) + { + igtl::PointElement::Pointer pointElement; + pointMsg->GetPointElement(i, pointElement); + + igtlUint8 rgba[4]; + pointElement->GetRGBA(rgba); + + igtlFloat32 pos[3]; + pointElement->GetPosition(pos); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << pointElement->GetName() << std::endl; + std::cerr << " GroupName : " << pointElement->GetGroupName() << std::endl; + std::cerr << " RGBA : ( " << (int)rgba[0] << ", " << (int)rgba[1] << ", " << (int)rgba[2] << ", " << (int)rgba[3] << " )" << std::endl; + std::cerr << " Position : ( " << std::fixed << pos[0] << ", " << pos[1] << ", " << pos[2] << " )" << std::endl; + std::cerr << " Radius : " << std::fixed << pointElement->GetRadius() << std::endl; + std::cerr << " Owner : " << pointElement->GetOwner() << std::endl; + std::cerr << "================================" << std::endl; + } + } + + return 1; +} + +int ReceiveTrajectory(igtl::Socket * socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving TRAJECTORY data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::TrajectoryMessage::Pointer trajectoryMsg; + trajectoryMsg = igtl::TrajectoryMessage::New(); + trajectoryMsg->SetMessageHeader(header); + trajectoryMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(trajectoryMsg->GetPackBodyPointer(), trajectoryMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = trajectoryMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = trajectoryMsg->GetNumberOfTrajectoryElement(); + for (int i = 0; i < nElements; i ++) + { + igtl::TrajectoryElement::Pointer trajectoryElement; + trajectoryMsg->GetTrajectoryElement(i, trajectoryElement); + + igtlUint8 rgba[4]; + trajectoryElement->GetRGBA(rgba); + + igtlFloat32 entry[3]; + igtlFloat32 target[3]; + trajectoryElement->GetEntryPosition(entry); + trajectoryElement->GetTargetPosition(target); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << trajectoryElement->GetName() << std::endl; + std::cerr << " GroupName : " << trajectoryElement->GetGroupName() << std::endl; + std::cerr << " RGBA : ( " << (int)rgba[0] << ", " << (int)rgba[1] << ", " << (int)rgba[2] << ", " << (int)rgba[3] << " )" << std::endl; + std::cerr << " Entry Pt : ( " << std::fixed << entry[0] << ", " << entry[1] << ", " << entry[2] << " )" << std::endl; + std::cerr << " Target Pt : ( " << std::fixed << target[0] << ", " << target[1] << ", " << target[2] << " )" << std::endl; + std::cerr << " Radius : " << std::fixed << trajectoryElement->GetRadius() << std::endl; + std::cerr << " Owner : " << trajectoryElement->GetOwner() << std::endl; + std::cerr << "================================" << std::endl << std::endl; + } + } + + return 1; +} + + +int ReceiveString(igtl::Socket * socket, igtl::MessageHeader * header) +{ + + std::cerr << "Receiving STRING data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::StringMessage::Pointer stringMsg; + stringMsg = igtl::StringMessage::New(); + stringMsg->SetMessageHeader(header); + stringMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(stringMsg->GetPackBodyPointer(), stringMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = stringMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + std::cerr << "Encoding: " << stringMsg->GetEncoding() << "; " + << "String: " << stringMsg->GetString() << std::endl; + } + + return 1; +} + + +int ReceiveBind(igtl::Socket * socket, igtl::MessageHeader * header) +{ + + std::cerr << "Receiving BIND data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::BindMessage::Pointer bindMsg; + bindMsg = igtl::BindMessage::New(); + bindMsg->SetMessageHeader(header); + bindMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(bindMsg->GetPackBodyPointer(), bindMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = bindMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int n = bindMsg->GetNumberOfChildMessages(); + + for (int i = 0; i < n; i ++) + { + if (strcmp(bindMsg->GetChildMessageType(i), "STRING") == 0) + { + igtl::StringMessage::Pointer stringMsg; + stringMsg = igtl::StringMessage::New(); + bindMsg->GetChildMessage(i, stringMsg); + stringMsg->Unpack(0); + std::cerr << "Message type: STRING" << std::endl; + std::cerr << "Message name: " << stringMsg->GetDeviceName() << std::endl; + std::cerr << "Encoding: " << stringMsg->GetEncoding() << "; " + << "String: " << stringMsg->GetString() << std::endl; + } + else if (strcmp(bindMsg->GetChildMessageType(i), "TRANSFORM") == 0) + { + igtl::TransformMessage::Pointer transMsg; + transMsg = igtl::TransformMessage::New(); + bindMsg->GetChildMessage(i, transMsg); + transMsg->Unpack(0); + std::cerr << "Message type: TRANSFORM" << std::endl; + std::cerr << "Message name: " << transMsg->GetDeviceName() << std::endl; + igtl::Matrix4x4 matrix; + transMsg->GetMatrix(matrix); + igtl::PrintMatrix(matrix); + } + } + } + + return 1; +} + + +int ReceiveCapability(igtl::Socket * socket, igtl::MessageHeader * header) +{ + + std::cerr << "Receiving CAPABILITY data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::CapabilityMessage::Pointer capabilMsg; + capabilMsg = igtl::CapabilityMessage::New(); + capabilMsg->SetMessageHeader(header); + capabilMsg->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(capabilMsg->GetPackBodyPointer(), capabilMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = capabilMsg->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nTypes = capabilMsg->GetNumberOfTypes(); + for (int i = 0; i < nTypes; i ++) + { + std::cerr << "Typename #" << i << ": " << capabilMsg->GetType(i) << std::endl; + } + } + + return 1; + +} + + +#endif //OpenIGTLink_PROTOCOL_VERSION >= 2 diff --git a/openigtlink/repo/Examples/SampleUDPProgam/CMakeLists.txt b/openigtlink/repo/Examples/SampleUDPProgam/CMakeLists.txt new file mode 100755 index 0000000..3e13f89 --- /dev/null +++ b/openigtlink/repo/Examples/SampleUDPProgam/CMakeLists.txt @@ -0,0 +1,19 @@ +PROJECT(SampleUDPProgam) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(ClientUDPTransfer ClientUDPTransfer.cxx) +TARGET_LINK_LIBRARIES(ClientUDPTransfer) + +ADD_EXECUTABLE(ServerUDPTransfer ServerUDPTransfer.cxx) +TARGET_LINK_LIBRARIES(ServerUDPTransfer) + + + diff --git a/openigtlink/repo/Examples/SampleUDPProgam/ClientUDPTransfer.cxx b/openigtlink/repo/Examples/SampleUDPProgam/ClientUDPTransfer.cxx new file mode 100755 index 0000000..f3f033c --- /dev/null +++ b/openigtlink/repo/Examples/SampleUDPProgam/ClientUDPTransfer.cxx @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include +#include +#include + +#define BUFLEN 512 +#define NPACK 1000 +#define PORT 9930 + +void diep(char *s) +{ + perror(s); + _exit(1); +} + +int main(void) +{ + struct sockaddr_in si_me, si_other; + int s, i, slen=sizeof(si_other); + char buf[BUFLEN]; + + if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) + diep("socket"); + + memset((char *) &si_me, 0, sizeof(si_me)); + si_me.sin_family = AF_INET; + si_me.sin_port = htons(PORT); + si_me.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(s, (struct sockaddr *)&si_me, sizeof(si_me))==-1) + diep("bind"); + + for (i=0; i +#include +#include +#include +#include +#include + +#define BUFLEN 512 +#define NPACK 10 +#define PORT 9930 + +#include + +#ifndef BUFLEN + #define BUFLEN 512 +#endif +#ifndef NPACK + #define NPACK 10000 +#endif +#ifndef PORT + #define PORT 9930 +#endif +void diep(char *s) +{ + perror(s); + _exit(1); +} + +#define SRV_IP "127.0.0.1" +/* diep(), #includes and #defines like in the server */ + +int main(void) +{ + struct sockaddr_in si_other; + int s, i, slen=sizeof(si_other); + char buf[BUFLEN]; + + if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) + diep("socket"); + + memset((char *) &si_other, 0, sizeof(si_other)); + si_other.sin_family = AF_INET; + si_other.sin_port = htons(PORT); + if (inet_aton(SRV_IP, &si_other.sin_addr)==0) { + fprintf(stderr, "inet_aton() failed\n"); + _exit(1); + } + + for (i=0; i +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlMessageHandler.h" +#include "igtlMessageHandlerMacro.h" +#include "igtlSessionManager.h" +#include "igtlTransformMessage.h" +#include "igtlPositionMessage.h" +#include "igtlImageMessage.h" + + + +//------------------------------------------------------------ +// Define a structure type to share data between message +// handler classes and main() function. +// It can be any types e.g. C++ class, array, etc. +// In this example, the shared structure is only used for +// passing the message type and the device name from the +// handler to main() function. + +typedef struct { + std::string messagetype; + std::string devicename; +} MyData; + + +//------------------------------------------------------------ +// Define message handler classes for TransformMessage, +// PositionMessage and ImageMessage. +// igtlMessageHandlerClassMacro() defines a child class of +// igtl::MessageHandler to handle OpenIGTLink messages for +// the message type specified as the first argument. The +// second argument will be used for the name of this +// message handler class, while the third argument specifies +// a type of data that will be shared with the message functions +// of this handler class. + +igtlMessageHandlerClassMacro(igtl::TransformMessage, TransformHandler, MyData); +igtlMessageHandlerClassMacro(igtl::PositionMessage, PositionHandler, MyData); +igtlMessageHandlerClassMacro(igtl::ImageMessage, ImageHandler, MyData); + + +//------------------------------------------------------------ +// You need to describe how the received message is processed +// in Process() function of the message handler class. +// When Process() is called, pointers to the received message +// and the shared data are passed as the arguments. + +// -- Transform message +int TransformHandler::Process(igtl::TransformMessage * transMsg, MyData* data) +{ + // Retrive the transform data + igtl::Matrix4x4 matrix; + transMsg->GetMatrix(matrix); + igtl::PrintMatrix(matrix); + + data->messagetype = transMsg->GetDeviceType(); + data->devicename = transMsg->GetDeviceName(); + + return 1; +} + +// -- Position message +int PositionHandler::Process(igtl::PositionMessage * positionMsg, MyData* data) +{ + // Retrive the transform data + float position[3]; + float quaternion[4]; + + positionMsg->GetPosition(position); + positionMsg->GetQuaternion(quaternion); + + std::cerr << "position = (" << position[0] << ", " << position[1] << ", " << position[2] << ")" << std::endl; + std::cerr << "quaternion = (" << quaternion[0] << ", " << quaternion[1] << ", " + << quaternion[2] << ", " << quaternion[3] << ")" << std::endl << std::endl; + + data->messagetype = positionMsg->GetDeviceType(); + data->devicename = positionMsg->GetDeviceName(); + + return 1; +} + +// -- Image message +int ImageHandler::Process(igtl::ImageMessage * imgMsg, MyData *data) +{ + // Retrive the image data + int size[3]; // image dimension + float spacing[3]; // spacing (mm/pixel) + int svsize[3]; // sub-volume size + int svoffset[3]; // sub-volume offset + int scalarType; // scalar type + int endian; // endian + + scalarType = imgMsg->GetScalarType(); + endian = imgMsg->GetEndian(); + imgMsg->GetDimensions(size); + imgMsg->GetSpacing(spacing); + imgMsg->GetSubVolume(svsize, svoffset); + + std::cerr << "Device Name : " << imgMsg->GetDeviceName() << std::endl; + std::cerr << "Scalar Type : " << scalarType << std::endl; + std::cerr << "Endian : " << endian << std::endl; + std::cerr << "Dimensions : (" + << size[0] << ", " << size[1] << ", " << size[2] << ")" << std::endl; + std::cerr << "Spacing : (" + << spacing[0] << ", " << spacing[1] << ", " << spacing[2] << ")" << std::endl; + std::cerr << "Sub-Volume dimensions : (" + << svsize[0] << ", " << svsize[1] << ", " << svsize[2] << ")" << std::endl; + std::cerr << "Sub-Volume offset : (" + << svoffset[0] << ", " << svoffset[1] << ", " << svoffset[2] << ")" << std::endl; + + data->messagetype = imgMsg->GetDeviceType(); + data->devicename = imgMsg->GetDeviceName(); + + return 1; +} + + +int main(int argc, char* argv[]) +{ + + //------------------------------------------------------------ + // Parse Arguments + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + //------------------------------------------------------------ + // Create a session manager + igtl::SessionManager::Pointer sm; + sm = igtl::SessionManager::New(); + sm->SetMode(igtl::SessionManager::MODE_SERVER); + sm->SetPort(port); + + //------------------------------------------------------------ + // Create message handlers + TransformHandler::Pointer tmh = TransformHandler::New(); + PositionHandler::Pointer pmh = PositionHandler::New(); + ImageHandler::Pointer imh = ImageHandler::New(); + + MyData mydata; + tmh->SetData(&mydata); + pmh->SetData(&mydata); + imh->SetData(&mydata); + + //------------------------------------------------------------ + // Register the message handlers to the session manager + sm->AddMessageHandler(tmh); + sm->AddMessageHandler(pmh); + sm->AddMessageHandler(imh); + + //------------------------------------------------------------ + // Start session + if (sm->Connect()) + { + while (1) + { + int r = sm->ProcessMessage(); + if (r == 0) // Disconnected + { + break; + } + std::cerr << "Message Type: " << tmh->GetData()->messagetype << std::endl; + std::cerr << "Device Name: " << tmh->GetData()->devicename << std::endl; + } + // Stop session + sm->Disconnect(); + } + +} + + + diff --git a/openigtlink/repo/Examples/Status/CMakeLists.txt b/openigtlink/repo/Examples/Status/CMakeLists.txt new file mode 100644 index 0000000..3f2a60d --- /dev/null +++ b/openigtlink/repo/Examples/Status/CMakeLists.txt @@ -0,0 +1,15 @@ +PROJECT(Status) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(StatusClient StatusClient.cxx) +TARGET_LINK_LIBRARIES(StatusClient OpenIGTLink) +ADD_EXECUTABLE(StatusServer StatusServer.cxx) +TARGET_LINK_LIBRARIES(StatusServer OpenIGTLink) diff --git a/openigtlink/repo/Examples/Status/StatusClient.cxx b/openigtlink/repo/Examples/Status/StatusClient.cxx new file mode 100644 index 0000000..57c9b40 --- /dev/null +++ b/openigtlink/repo/Examples/Status/StatusClient.cxx @@ -0,0 +1,85 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Sending Status Messasge + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlStatusMessage.h" +#include "igtlClientSocket.h" + +// +// Test comment +// + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + int interval = (int) (1000); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Status Message Class + + igtl::StatusMessage::Pointer statusMsg; + statusMsg = igtl::StatusMessage::New(); + statusMsg->SetDeviceName("Device"); + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + statusMsg->SetCode(igtl::StatusMessage::STATUS_OK); + statusMsg->SetSubCode(128); + statusMsg->SetErrorName("OK!"); + statusMsg->SetStatusString("This is a test to send status message."); + statusMsg->Pack(); + socket->Send(statusMsg->GetPackPointer(), statusMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + + //------------------------------------------------------------ + // Close connection + + socket->CloseSocket(); + +} + + diff --git a/openigtlink/repo/Examples/Status/StatusServer.cxx b/openigtlink/repo/Examples/Status/StatusServer.cxx new file mode 100644 index 0000000..bfdb81a --- /dev/null +++ b/openigtlink/repo/Examples/Status/StatusServer.cxx @@ -0,0 +1,89 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlStatusMessage.h" +#include "igtlServerSocket.h" + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + int interval = (int) 1000; + + + //------------------------------------------------------------ + // Allocate Status Message Class + + igtl::StatusMessage::Pointer statusMsg; + statusMsg = igtl::StatusMessage::New(); + statusMsg->SetDeviceName("Device"); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + statusMsg->SetDeviceName("Device"); + statusMsg->SetCode(igtl::StatusMessage::STATUS_OK); + statusMsg->SetSubCode(128); + statusMsg->SetErrorName("OK!"); + statusMsg->SetStatusString("This is a test to send status message."); + statusMsg->Pack(); + socket->Send(statusMsg->GetPackPointer(), statusMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + + diff --git a/openigtlink/repo/Examples/String/CMakeLists.txt b/openigtlink/repo/Examples/String/CMakeLists.txt new file mode 100644 index 0000000..14b1562 --- /dev/null +++ b/openigtlink/repo/Examples/String/CMakeLists.txt @@ -0,0 +1,22 @@ +PROJECT(String) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(StringClient StringClient.cxx) +TARGET_LINK_LIBRARIES(StringClient OpenIGTLink) + +ADD_EXECUTABLE(StringServer StringServer.cxx) +TARGET_LINK_LIBRARIES(StringServer OpenIGTLink) + +ADD_EXECUTABLE(StringEchoServer StringEchoServer.cxx) +TARGET_LINK_LIBRARIES(StringEchoServer OpenIGTLink) + + + diff --git a/openigtlink/repo/Examples/String/StringClient.cxx b/openigtlink/repo/Examples/String/StringClient.cxx new file mode 100644 index 0000000..915367d --- /dev/null +++ b/openigtlink/repo/Examples/String/StringClient.cxx @@ -0,0 +1,93 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for String Message Client Program + Module: $RCSfile: $ + Language: C++ + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlStringMessage.h" +#include "igtlClientSocket.h" + +#define N_STRINGS 5 + +const char * testString[N_STRINGS] = { + "OpenIGTLink", + "Network", + "Communication", + "Protocol", + "Image Guided Therapy", +}; + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 4) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send string" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int interval = (int) (1000.0 / fps); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Transform Message Class + + igtl::StringMessage::Pointer stringMsg; + stringMsg = igtl::StringMessage::New(); + + + //------------------------------------------------------------ + // loop + int i = 0; + while (1) + { + stringMsg->SetDeviceName("StringMessage"); + std::cout << "Sending string: " << testString[i] << std::endl; + stringMsg->SetString(testString[i]); + stringMsg->Pack(); + socket->Send(stringMsg->GetPackPointer(), stringMsg->GetPackSize()); + igtl::Sleep(interval); // wait + i = (i + 1) % N_STRINGS; + } + + //------------------------------------------------------------ + // Close connection + + socket->CloseSocket(); +} diff --git a/openigtlink/repo/Examples/String/StringEchoServer.cxx b/openigtlink/repo/Examples/String/StringEchoServer.cxx new file mode 100644 index 0000000..7e13d98 --- /dev/null +++ b/openigtlink/repo/Examples/String/StringEchoServer.cxx @@ -0,0 +1,94 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for String Echo Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlStringMessage.h" +#include "igtlServerSocket.h" + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + igtl::MessageHeader::Pointer hdrMsg = igtl::MessageHeader::New(); + + while (socket.IsNotNull() && socket->GetConnected()) + { + hdrMsg->InitPack(); + bool timeout(false); + igtlUint64 r = socket->Receive(hdrMsg->GetPackPointer(), hdrMsg->GetPackSize(), timeout); + + // check message + if (r == 0) + { + socket->CloseSocket(); + continue; + } + if (r != hdrMsg->GetPackSize()) + continue; + + // get data + hdrMsg->Unpack(); + igtl::StringMessage::Pointer strMsg(igtl::StringMessage::New()); + strMsg->SetMessageHeader(hdrMsg); + strMsg->AllocatePack(); + timeout = false; + socket->Receive(strMsg->GetPackBodyPointer(), strMsg->GetPackBodySize(), timeout); + int c = strMsg->Unpack(); + + // echo message back + std::cout << "Echoing: " << strMsg->GetString() << std::endl; + strMsg->SetDeviceName("StringEchoServer"); + strMsg->Pack(); + socket->Send(strMsg->GetPackPointer(), strMsg->GetPackSize()); + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + diff --git a/openigtlink/repo/Examples/String/StringServer.cxx b/openigtlink/repo/Examples/String/StringServer.cxx new file mode 100644 index 0000000..77e2e40 --- /dev/null +++ b/openigtlink/repo/Examples/String/StringServer.cxx @@ -0,0 +1,94 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlStringMessage.h" +#include "igtlServerSocket.h" + +#define N_STRINGS 5 + +const char * testString[N_STRINGS] = { + "OpenIGTLink", + "Network", + "Communication", + "Protocol", + "Image Guided Therapy", +}; + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send string" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + double fps = atof(argv[2]); + int interval = (int) (1000.0 / fps); + + igtl::StringMessage::Pointer stringMsg; + stringMsg = igtl::StringMessage::New(); + stringMsg->SetDeviceName("StringMessage"); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + std::cout << "Sending string: " << testString[i%N_STRINGS] << std::endl; + stringMsg->SetDeviceName("StringMessage"); + stringMsg->SetString(testString[i%N_STRINGS]); + stringMsg->Pack(); + socket->Send(stringMsg->GetPackPointer(), stringMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + diff --git a/openigtlink/repo/Examples/Thread/CMakeLists.txt b/openigtlink/repo/Examples/Thread/CMakeLists.txt new file mode 100644 index 0000000..b26a583 --- /dev/null +++ b/openigtlink/repo/Examples/Thread/CMakeLists.txt @@ -0,0 +1,21 @@ +PROJECT(Thread) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(SingleMethodExecute SingleMethodExecute.cxx) +TARGET_LINK_LIBRARIES(SingleMethodExecute OpenIGTLink) + +ADD_EXECUTABLE(MultipleMethodExecute MultipleMethodExecute.cxx) +TARGET_LINK_LIBRARIES(MultipleMethodExecute OpenIGTLink) + +ADD_EXECUTABLE(SpawnThread SpawnThread.cxx) +TARGET_LINK_LIBRARIES(SpawnThread OpenIGTLink) + + diff --git a/openigtlink/repo/Examples/Thread/MultipleMethodExecute.cxx b/openigtlink/repo/Examples/Thread/MultipleMethodExecute.cxx new file mode 100644 index 0000000..e200210 --- /dev/null +++ b/openigtlink/repo/Examples/Thread/MultipleMethodExecute.cxx @@ -0,0 +1,132 @@ +/*========================================================================= + + Program: OpenIGTLink Library -- Example for Thread (Multiple Methods) + Module: $RCSfile: itkImage.h,v $ + Language: C++ + Date: $Date: 2008/01/13 19:48:38 $ + Version: $Revision: 1.142 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlMultiThreader.h" +#include "igtlOSUtil.h" + + +typedef struct { + int nloop; + igtl::MutexLock::Pointer glock; +} ThreadData; + + +void* ThreadFunction1(void* ptr) +{ + //------------------------------------------------------------ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + int id = info->ThreadID; + int nThread = info->NumberOfThreads; + ThreadData* data = static_cast(info->UserData); + + //------------------------------------------------------------ + // Get user data + + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + long interval = 100; // (ms) + + //------------------------------------------------------------ + // Loop + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + std::cerr << "Thread #1: counter = " << i << std::endl; + glock->Unlock(); + igtl::Sleep(interval); + } + + glock->Lock(); + std::cerr << "Thread #1: end." << std::endl; + glock->Unlock(); + + return NULL; +} + + +void* ThreadFunction2(void* ptr) +{ + //------------------------------------------------------------ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + int id = info->ThreadID; + int nThread = info->NumberOfThreads; + ThreadData* data = static_cast(info->UserData); + + //------------------------------------------------------------ + // Set user data + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + long interval = 200; // (ms) + + //------------------------------------------------------------ + // loop + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + std::cerr << "Thread #2: counter = " << i << std::endl; + glock->Unlock(); + igtl::Sleep(interval); + } + + glock->Lock(); + std::cerr << "Thread #2: end." << std::endl; + glock->Unlock(); + + return NULL; +} + + +int main(int argc, char * argv [] ) +{ + + //------------------------------------------------------------ + // Set up thread and mutex cleasses + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + + //------------------------------------------------------------ + // Set up user data + ThreadData td; + td.nloop = 20; + td.glock = glock; + + //------------------------------------------------------------ + // Set multiple methods as threads + threader->SetNumberOfThreads(2); + threader->SetMultipleMethod(0, (igtl::ThreadFunctionType) &ThreadFunction1, &td); + threader->SetMultipleMethod(1, (igtl::ThreadFunctionType) &ThreadFunction2, &td); + + //------------------------------------------------------------ + // Start threads -- the main thread waits until all threads return. + std::cerr << "Starting threads ...." << std::endl; + threader->MultipleMethodExecute(); + std::cerr << "Theads stopped ...." << std::endl; + + return 0; +} + + + + + diff --git a/openigtlink/repo/Examples/Thread/SingleMethodExecute.cxx b/openigtlink/repo/Examples/Thread/SingleMethodExecute.cxx new file mode 100644 index 0000000..b466e19 --- /dev/null +++ b/openigtlink/repo/Examples/Thread/SingleMethodExecute.cxx @@ -0,0 +1,96 @@ +/*========================================================================= + + Program: OpenIGTLink Library -- Example for Thread (Single Method) + Module: $RCSfile: itkImage.h,v $ + Language: C++ + Date: $Date: 2008/01/13 19:48:38 $ + Version: $Revision: 1.142 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlMultiThreader.h" +#include "igtlOSUtil.h" + + +typedef struct { + int nloop; + igtl::MutexLock::Pointer glock; +} ThreadData; + + +#define NUM_THREADS 4 + + +void* ThreadFunction(void* ptr) +{ + //------------------------------------------------------------ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + int id = info->ThreadID; + int nThread = info->NumberOfThreads; + ThreadData* data = static_cast(info->UserData); + + //------------------------------------------------------------ + // Get user data + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + long interval = (id + 1) * 100; // (ms) + + //------------------------------------------------------------ + // Loop + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + std::cerr << "Thread #" << id << ": counter = " << i << std::endl; + glock->Unlock(); + igtl::Sleep(interval); + } + + glock->Lock(); + std::cerr << "Thread #" << id << ": end." << std::endl; + glock->Unlock(); + + return NULL; +} + + +int main(int argc, char * argv [] ) +{ + //------------------------------------------------------------ + // Set up thread and mutex cleasses + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + + //------------------------------------------------------------ + // Set user data + ThreadData td; + td.nloop = 20; + td.glock = glock; + + //------------------------------------------------------------ + // Set multiple methods as threads + threader->SetNumberOfThreads(NUM_THREADS); + threader->SetSingleMethod((igtl::ThreadFunctionType) &ThreadFunction, &td); + + //------------------------------------------------------------ + // Start threads -- the main thread waits until all threads return. + std::cerr << "Starting threads ...." << std::endl; + threader->SingleMethodExecute(); + std::cerr << "Theads stopped ...." << std::endl; + + return 0; +} + + + + + diff --git a/openigtlink/repo/Examples/Thread/SpawnThread.cxx b/openigtlink/repo/Examples/Thread/SpawnThread.cxx new file mode 100644 index 0000000..29aabbc --- /dev/null +++ b/openigtlink/repo/Examples/Thread/SpawnThread.cxx @@ -0,0 +1,115 @@ +/*========================================================================= + + Program: OpenIGTLink Library -- Example for Thread (Spawn Thread) + Module: $RCSfile: itkImage.h,v $ + Language: C++ + Date: $Date: 2008/01/13 19:48:38 $ + Version: $Revision: 1.142 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlMultiThreader.h" +#include "igtlOSUtil.h" + + +typedef struct { + int nloop; + igtl::MutexLock::Pointer glock; +} ThreadData; + + +#define NUM_THREADS 4 + + +void* ThreadFunction(void* ptr) +{ + //------------------------------------------------------------ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + int id = info->ThreadID; + int nThread = info->NumberOfThreads; + ThreadData* data = static_cast(info->UserData); + + //------------------------------------------------------------ + // Get user data + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + long interval = (id + 1) * 100; // (ms) + + //------------------------------------------------------------ + // Loop + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + std::cerr << "Thread #" << id << ": counter = " << i << std::endl; + glock->Unlock(); + igtl::Sleep(interval); + } + + glock->Lock(); + std::cerr << "Thread #" << id << ": end." << std::endl; + glock->Unlock(); + + return NULL; +} + + +int main(int argc, char * argv [] ) +{ + + //------------------------------------------------------------ + // Set up thread and mutex cleasses + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + + //------------------------------------------------------------ + // Set up user data + ThreadData td; + td.nloop = 20; + td.glock = glock; + + //------------------------------------------------------------ + // Start threads -- the main thread waits until all threads return. + + std::cerr << "Starting threads ...." << std::endl; + + int id1 = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + int id2 = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + int id3 = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + int id4 = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + int id5 = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + + //------------------------------------------------------------ + // All threads are detached ... main thread is still active + for (int i = 0; i < td.nloop; i ++) + { + glock->Lock(); + std::cerr << "Main Thread: counter = " << i << std::endl; + glock->Unlock(); + igtl::Sleep(200); + } + + //------------------------------------------------------------ + // wait for the threads + threader->TerminateThread(id1); + threader->TerminateThread(id2); + threader->TerminateThread(id3); + threader->TerminateThread(id4); + threader->TerminateThread(id5); + + std::cerr << "Theads stopped ...." << std::endl; + + return 0; +} + + + diff --git a/openigtlink/repo/Examples/Tracker/CMakeLists.txt b/openigtlink/repo/Examples/Tracker/CMakeLists.txt new file mode 100644 index 0000000..dac9d81 --- /dev/null +++ b/openigtlink/repo/Examples/Tracker/CMakeLists.txt @@ -0,0 +1,25 @@ +PROJECT(Tracker) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(TrackerClient TrackerClient.cxx) +TARGET_LINK_LIBRARIES(TrackerClient OpenIGTLink) +ADD_EXECUTABLE(TrackerServer TrackerServer.cxx) +TARGET_LINK_LIBRARIES(TrackerServer OpenIGTLink) + +ADD_EXECUTABLE(TrackerClient2 TrackerClient2.cxx) +TARGET_LINK_LIBRARIES(TrackerClient2 OpenIGTLink) +ADD_EXECUTABLE(TrackerServer2 TrackerServer2.cxx) +TARGET_LINK_LIBRARIES(TrackerServer2 OpenIGTLink) + +ADD_EXECUTABLE(TrackerClient3 TrackerClient3.cxx) +TARGET_LINK_LIBRARIES(TrackerClient3 OpenIGTLink) + + diff --git a/openigtlink/repo/Examples/Tracker/TrackerClient.cxx b/openigtlink/repo/Examples/Tracker/TrackerClient.cxx new file mode 100644 index 0000000..f7b7a14 --- /dev/null +++ b/openigtlink/repo/Examples/Tracker/TrackerClient.cxx @@ -0,0 +1,122 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlTransformMessage.h" +#include "igtlClientSocket.h" + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 4) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int interval = (int) (1000.0 / fps); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Transform Message Class + + igtl::TransformMessage::Pointer transMsg; + transMsg = igtl::TransformMessage::New(); + transMsg->SetDeviceName("Tracker"); + + //------------------------------------------------------------ + // Allocate TimeStamp class + igtl::TimeStamp::Pointer ts; + ts = igtl::TimeStamp::New(); + + //------------------------------------------------------------ + // loop + while (1) + { + igtl::Matrix4x4 matrix; + GetRandomTestMatrix(matrix); + ts->GetTime(); + transMsg->SetMatrix(matrix); + transMsg->SetTimeStamp(ts); + transMsg->Pack(); + socket->Send(transMsg->GetPackPointer(), transMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + + //------------------------------------------------------------ + // Close connection + + socket->CloseSocket(); + +} + +//------------------------------------------------------------ +// Function to generate random matrix. + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix) +{ + float position[3]; + float orientation[4]; + + // random position + static float phi = 0.0; + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + phi = phi + 0.2; + + // random orientation + static float theta = 0.0; + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + //igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + + igtl::PrintMatrix(matrix); +} + diff --git a/openigtlink/repo/Examples/Tracker/TrackerClient2.cxx b/openigtlink/repo/Examples/Tracker/TrackerClient2.cxx new file mode 100644 index 0000000..5e81d9d --- /dev/null +++ b/openigtlink/repo/Examples/Tracker/TrackerClient2.cxx @@ -0,0 +1,116 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Client Program II + (POSITION data type) + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlPositionMessage.h" +#include "igtlClientSocket.h" + +void GetRandomTestVectors(float* position, float* quaternion); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 4) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int interval = (int) (1000.0 / fps); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Transform Message Class + + igtl::PositionMessage::Pointer positionMsg; + positionMsg = igtl::PositionMessage::New(); + positionMsg->SetDeviceName("Tracker"); + positionMsg->SetPackType(igtl::PositionMessage::ALL); // default + + //------------------------------------------------------------ + // loop + while (1) + { + float position[3]; + float quaternion[4]; + + GetRandomTestVectors(position, quaternion); + positionMsg->SetPosition(position); + positionMsg->SetQuaternion(quaternion); + positionMsg->Pack(); + socket->Send(positionMsg->GetPackPointer(), positionMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + + //------------------------------------------------------------ + // Close connection + + socket->CloseSocket(); + +} + + +//------------------------------------------------------------ +// Function to generate random matrix. + +void GetRandomTestVectors(float* position, float* quaternion) +{ + + // random position + static float phi = 0.0; + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + phi = phi + 0.2; + + // random orientation + static float theta = 0.0; + quaternion[0]=0.0; + quaternion[1]=0.6666666666*cos(theta); + quaternion[2]=0.577350269189626; + quaternion[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + std::cerr << "position = (" << position[0] << ", " << position[1] << ", " << position[2] << ")" << std::endl; + std::cerr << "quaternion = (" << quaternion[0] << ", " << quaternion[1] << ", " + << quaternion[2] << ", " << quaternion[3] << ")" << std::endl << std::endl; +} + + + diff --git a/openigtlink/repo/Examples/Tracker/TrackerClient3.cxx b/openigtlink/repo/Examples/Tracker/TrackerClient3.cxx new file mode 100644 index 0000000..8409618 --- /dev/null +++ b/openigtlink/repo/Examples/Tracker/TrackerClient3.cxx @@ -0,0 +1,153 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlTransformMessage.h" +#include "igtlClientSocket.h" + +#define MAX_DEVICE 4 + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix, float phi, float theta); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc < 4 || argc > 4 + MAX_DEVICE) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " [ .. ]" << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + std::cerr << " .. : Device names (N < " << MAX_DEVICE << ")" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int interval = (int) (1000.0 / fps); + int numdev = argc - 4; + const char* devicename[4]; + + if (numdev == 0) + { + numdev = 1; + devicename[0] = "Tracker"; + } + else + { + for (int i = 0; i < numdev; i ++) + { + devicename[i] = argv[i+4]; + } + } + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Transform Message Class + + igtl::TransformMessage::Pointer transMsg; + transMsg = igtl::TransformMessage::New(); + + float phi[MAX_DEVICE]; + float theta[MAX_DEVICE]; + float incr[MAX_DEVICE]; + for (int i = 0; i < numdev; i ++) + { + phi[i] = 0.3*(float)i; + theta[i] = 0.2*(float)i; + incr[i] = 0.5*(float)(i+1); + } + + + //------------------------------------------------------------ + // loop + igtl::TimeStamp::Pointer ts = igtl::TimeStamp::New(); + + while (1) + { + for (int i = 0; i < numdev; i ++) + { + transMsg->SetDeviceName(devicename[i]); + igtl::Matrix4x4 matrix; + GetRandomTestMatrix(matrix, phi[i], theta[i]); + transMsg->SetMatrix(matrix); + ts->GetTime(); + transMsg->SetTimeStamp(ts); + transMsg->Pack(); + + igtlUint32 sec; + igtlUint32 nsec; + ts->GetTimeStamp(&sec, &nsec); + std::cerr << "Time Stamp: sec = " << sec << ", nsec = " << nsec << std::endl; + socket->Send(transMsg->GetPackPointer(), transMsg->GetPackSize()); + phi[i] = phi[i] + 0.2*incr[i]; + theta[i] = theta[i] + 0.1*incr[i]; + } + igtl::Sleep(interval); // wait + } + + //------------------------------------------------------------ + // Close connection + socket->CloseSocket(); + +} + +//------------------------------------------------------------ +// Function to generate random matrix. + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix, float phi, float theta) +{ + float position[3]; + float orientation[4]; + + // random position + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + + // random orientation + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + + //igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + + igtl::PrintMatrix(matrix); +} + diff --git a/openigtlink/repo/Examples/Tracker/TrackerServer.cxx b/openigtlink/repo/Examples/Tracker/TrackerServer.cxx new file mode 100644 index 0000000..1fe3740 --- /dev/null +++ b/openigtlink/repo/Examples/Tracker/TrackerServer.cxx @@ -0,0 +1,117 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlTransformMessage.h" +#include "igtlServerSocket.h" + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + double fps = atof(argv[2]); + int interval = (int) (1000.0 / fps); + + igtl::TransformMessage::Pointer transMsg; + transMsg = igtl::TransformMessage::New(); + transMsg->SetDeviceName("Tracker"); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + igtl::Matrix4x4 matrix; + GetRandomTestMatrix(matrix); + transMsg->SetDeviceName("Tracker"); + transMsg->SetMatrix(matrix); + transMsg->Pack(); + socket->Send(transMsg->GetPackPointer(), transMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix) +{ + float position[3]; + float orientation[4]; + + // random position + static float phi = 0.0; + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + phi = phi + 0.2; + + // random orientation + static float theta = 0.0; + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + //igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + + igtl::PrintMatrix(matrix); +} + diff --git a/openigtlink/repo/Examples/Tracker/TrackerServer2.cxx b/openigtlink/repo/Examples/Tracker/TrackerServer2.cxx new file mode 100644 index 0000000..a270fc4 --- /dev/null +++ b/openigtlink/repo/Examples/Tracker/TrackerServer2.cxx @@ -0,0 +1,116 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlPositionMessage.h" +#include "igtlServerSocket.h" + +void GetRandomTestVectors(float* position, float* quaternion); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + double fps = atof(argv[2]); + int interval = (int) (1000.0 / fps); + + + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + float position[3]; + float quaternion[4]; + igtl::PositionMessage::Pointer positionMsg; + positionMsg = igtl::PositionMessage::New(); + positionMsg->SetDeviceName("Tracker"); + positionMsg->SetPackType(igtl::PositionMessage::ALL); // default + GetRandomTestVectors(position, quaternion); + positionMsg->SetPosition(position); + positionMsg->SetQuaternion(quaternion); + positionMsg->Pack(); + socket->Send(positionMsg->GetPackPointer(), positionMsg->GetPackSize()); + igtl::Sleep(interval); // wait + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + + +//------------------------------------------------------------ +// Function to generate random matrix. + +void GetRandomTestVectors(float* position, float* quaternion) +{ + + // random position + static float phi = 0.0; + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + phi = phi + 0.2; + + // random orientation + static float theta = 0.0; + quaternion[0]=0.0; + quaternion[1]=0.6666666666*cos(theta); + quaternion[2]=0.577350269189626; + quaternion[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + +} + + + diff --git a/openigtlink/repo/Examples/TrackingData/CMakeLists.txt b/openigtlink/repo/Examples/TrackingData/CMakeLists.txt new file mode 100644 index 0000000..f4aef04 --- /dev/null +++ b/openigtlink/repo/Examples/TrackingData/CMakeLists.txt @@ -0,0 +1,19 @@ +PROJECT(TrackingData) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(TrackingDataClient TrackingDataClient.cxx) +TARGET_LINK_LIBRARIES(TrackingDataClient OpenIGTLink) + +ADD_EXECUTABLE(TrackingDataServer TrackingDataServer.cxx) +TARGET_LINK_LIBRARIES(TrackingDataServer OpenIGTLink) + + + diff --git a/openigtlink/repo/Examples/TrackingData/TrackingDataClient.cxx b/openigtlink/repo/Examples/TrackingData/TrackingDataClient.cxx new file mode 100644 index 0000000..45ba269 --- /dev/null +++ b/openigtlink/repo/Examples/TrackingData/TrackingDataClient.cxx @@ -0,0 +1,164 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlTrackingDataMessage.h" +#include "igtlClientSocket.h" + + +int ReceiveTrackingData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 4) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send coordinate" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int interval = (int) (1000.0 / fps); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Ask the server to start pushing tracking data + std::cerr << "Sending STT_TDATA message....." << std::endl; + igtl::StartTrackingDataMessage::Pointer startTrackingMsg; + startTrackingMsg = igtl::StartTrackingDataMessage::New(); + startTrackingMsg->SetDeviceName("TDataClient"); + startTrackingMsg->SetResolution(interval); + startTrackingMsg->SetCoordinateName("Patient"); + startTrackingMsg->Pack(); + socket->Send(startTrackingMsg->GetPackPointer(), startTrackingMsg->GetPackSize()); + + int loop = 0; + + while (1) + { + //------------------------------------------------------------ + // Wait for a reply + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + std::cerr << "Message size information and actual data size don't match." << std::endl; + socket->CloseSocket(); + exit(0); + } + + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "TDATA") == 0) + { + ReceiveTrackingData(socket, headerMsg); + } + else + { + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + if (++loop >= 10) // if received 100 times + { + //------------------------------------------------------------ + // Ask the server to stop pushing tracking data + std::cerr << "Sending STP_TDATA message....." << std::endl; + igtl::StopTrackingDataMessage::Pointer stopTrackingMsg; + stopTrackingMsg = igtl::StopTrackingDataMessage::New(); + stopTrackingMsg->SetDeviceName("TDataClient"); + stopTrackingMsg->Pack(); + socket->Send(stopTrackingMsg->GetPackPointer(), stopTrackingMsg->GetPackSize()); + loop = 0; + } + } +} + + +int ReceiveTrackingData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header) +{ + std::cerr << "Receiving TDATA data type." << std::endl; + + //------------------------------------------------------------ + // Allocate TrackingData Message Class + + igtl::TrackingDataMessage::Pointer trackingData; + trackingData = igtl::TrackingDataMessage::New(); + trackingData->SetMessageHeader(header); + trackingData->AllocatePack(); + + // Receive body from the socket + bool timeout(false); + socket->Receive(trackingData->GetPackBodyPointer(), trackingData->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = trackingData->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = trackingData->GetNumberOfTrackingDataElements(); + for (int i = 0; i < nElements; i ++) + { + igtl::TrackingDataElement::Pointer trackingElement; + trackingData->GetTrackingDataElement(i, trackingElement); + + igtl::Matrix4x4 matrix; + trackingElement->GetMatrix(matrix); + + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << trackingElement->GetName() << std::endl; + std::cerr << " Type : " << (int) trackingElement->GetType() << std::endl; + std::cerr << " Matrix : " << std::endl; + igtl::PrintMatrix(matrix); + std::cerr << "================================" << std::endl; + } + return 1; + } + return 0; +} + + diff --git a/openigtlink/repo/Examples/TrackingData/TrackingDataServer.cxx b/openigtlink/repo/Examples/TrackingData/TrackingDataServer.cxx new file mode 100644 index 0000000..652654f --- /dev/null +++ b/openigtlink/repo/Examples/TrackingData/TrackingDataServer.cxx @@ -0,0 +1,316 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracking Data Server + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlServerSocket.h" +#include "igtlTrackingDataMessage.h" +#include "igtlMultiThreader.h" + + +void* ThreadFunction(void* ptr); +int SendTrackingData(igtl::Socket::Pointer& socket, igtl::TrackingDataMessage::Pointer& trackingMsg); +void GetRandomTestMatrix(igtl::Matrix4x4& matrix, float phi, float theta); + +typedef struct { + int nloop; + igtl::MutexLock::Pointer glock; + igtl::Socket::Pointer socket; + int interval; + int stop; +} ThreadData; + + +int main(int argc, char* argv[]) +{ + + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + ThreadData td; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + int threadID = -1; + igtl::Socket::Pointer socket; + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + //------------------------------------------------------------ + // loop + for (;;) + { + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + if (threadID >= 0) + { + td.stop = 1; + threader->TerminateThread(threadID); + threadID = -1; + } + std::cerr << "Disconnecting the client." << std::endl; + td.socket = NULL; // VERY IMPORTANT. Completely remove the instance. + socket->CloseSocket(); + break; + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "STT_TDATA") == 0) + { + std::cerr << "Received a STT_TDATA message." << std::endl; + + igtl::StartTrackingDataMessage::Pointer startTracking; + startTracking = igtl::StartTrackingDataMessage::New(); + startTracking->SetMessageHeader(headerMsg); + startTracking->AllocatePack(); + + bool timeout(false); + igtlUint64 r2 = socket->Receive(startTracking->GetPackBodyPointer(), startTracking->GetPackBodySize(), timeout); + int c = startTracking->Unpack(1); + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + td.interval = startTracking->GetResolution(); + td.glock = glock; + td.socket = socket; + td.stop = 0; + threadID = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + } + } + else if (strcmp(headerMsg->GetDeviceType(), "STP_TDATA") == 0) + { + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + std::cerr << "Received a STP_TDATA message." << std::endl; + if (threadID >= 0) + { + td.stop = 1; + threader->TerminateThread(threadID); + threadID = -1; + std::cerr << "Disconnecting the client." << std::endl; + td.socket = NULL; // VERY IMPORTANT. Completely remove the instance. + socket->CloseSocket(); + } + break; + } + else + { + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + serverSocket->CloseSocket(); + +} + + +void* ThreadFunction(void* ptr) +{ + //------------------------------------------------------------ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + //int id = info->ThreadID; + //int nThread = info->NumberOfThreads; + ThreadData* td = static_cast(info->UserData); + + //------------------------------------------------------------ + // Get user data + igtl::MutexLock::Pointer glock = td->glock; + long interval = td->interval; + std::cerr << "Interval = " << interval << " (ms)" << std::endl; + //long interval = 1000; + //long interval = (id + 1) * 100; // (ms) + + igtl::Socket::Pointer& socket = td->socket; + + //------------------------------------------------------------ + // Allocate TrackingData Message Class + // + // NOTE: TrackingDataElement class instances are allocated + // before the loop starts to avoid reallocation + // in each image transfer. + + igtl::TrackingDataMessage::Pointer trackingMsg; + trackingMsg = igtl::TrackingDataMessage::New(); + + + igtl::TrackingDataElement::Pointer trackElement0; + trackElement0 = igtl::TrackingDataElement::New(); + trackElement0->SetName("Channel 0"); + trackElement0->SetType(igtl::TrackingDataElement::TYPE_TRACKER); + + igtl::TrackingDataElement::Pointer trackElement1; + trackElement1 = igtl::TrackingDataElement::New(); + trackElement1->SetName("Channel 1"); + trackElement1->SetType(igtl::TrackingDataElement::TYPE_6D); + + igtl::TrackingDataElement::Pointer trackElement2; + trackElement2 = igtl::TrackingDataElement::New(); + trackElement2->SetName("Channel 2"); + trackElement2->SetType(igtl::TrackingDataElement::TYPE_5D); + + trackingMsg->AddTrackingDataElement(trackElement0); + trackingMsg->AddTrackingDataElement(trackElement1); + trackingMsg->AddTrackingDataElement(trackElement2); + + //------------------------------------------------------------ + // Loop + while (!td->stop) + { + trackingMsg->SetDeviceName("Tracker"); + glock->Lock(); + SendTrackingData(socket, trackingMsg); + glock->Unlock(); + igtl::Sleep(interval); + } + + //glock->Lock(); + //std::cerr << "Thread #" << id << ": end." << std::endl; + //glock->Unlock(); + + return NULL; +} + + +int SendTrackingData(igtl::Socket::Pointer& socket, igtl::TrackingDataMessage::Pointer& trackingMsg) +{ + + static float phi0 = 0.0; + static float theta0 = 0.0; + static float phi1 = 0.0; + static float theta1 = 0.0; + static float phi2 = 0.0; + static float theta2 = 0.0; + + igtl::Matrix4x4 matrix; + igtl::TrackingDataElement::Pointer ptr; + + // Channel 0 + trackingMsg->GetTrackingDataElement(0, ptr); + GetRandomTestMatrix(matrix, phi0, theta0); + ptr->SetMatrix(matrix); + + // Channel 1 + trackingMsg->GetTrackingDataElement(1, ptr); + GetRandomTestMatrix(matrix, phi1, theta1); + ptr->SetMatrix(matrix); + + // Channel 2 + trackingMsg->GetTrackingDataElement(2, ptr); + GetRandomTestMatrix(matrix, phi2, theta2); + ptr->SetMatrix(matrix); + + trackingMsg->Pack(); + socket->Send(trackingMsg->GetPackPointer(), trackingMsg->GetPackSize()); + + phi0 += 0.1; + phi1 += 0.2; + phi2 += 0.3; + theta0 += 0.2; + theta1 += 0.1; + theta2 += 0.05; + + return 0; +} + + + +//------------------------------------------------------------ +// Function to generate random matrix. +void GetRandomTestMatrix(igtl::Matrix4x4& matrix, float phi, float theta) +{ + float position[3]; + float orientation[4]; + + // random position + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + phi = phi + 0.2; + + // random orientation + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + //igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + + //igtl::PrintMatrix(matrix); +} + + + + + + diff --git a/openigtlink/repo/Examples/TrackingDataUDPTransfer/CMakeLists.txt b/openigtlink/repo/Examples/TrackingDataUDPTransfer/CMakeLists.txt new file mode 100755 index 0000000..74c9240 --- /dev/null +++ b/openigtlink/repo/Examples/TrackingDataUDPTransfer/CMakeLists.txt @@ -0,0 +1,19 @@ +PROJECT(TrackingDataUDPTransfer) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(TrackingDataClientUDPTransfer TrackingDataClientUDPTransfer.cxx) +TARGET_LINK_LIBRARIES(TrackingDataClientUDPTransfer OpenIGTLink) + +ADD_EXECUTABLE(TrackingDataServerUDPTransfer TrackingDataServerUDPTransfer.cxx) +TARGET_LINK_LIBRARIES(TrackingDataServerUDPTransfer OpenIGTLink) + + + diff --git a/openigtlink/repo/Examples/TrackingDataUDPTransfer/TrackingDataClientUDPTransfer.cxx b/openigtlink/repo/Examples/TrackingDataUDPTransfer/TrackingDataClientUDPTransfer.cxx new file mode 100755 index 0000000..0065c62 --- /dev/null +++ b/openigtlink/repo/Examples/TrackingDataUDPTransfer/TrackingDataClientUDPTransfer.cxx @@ -0,0 +1,133 @@ +/*========================================================================= + + Program: Open IGT Link -- Example for Tracker Client Program + Module: $RCSfile: $ + Language: C++ + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include + +#include + +#include "igtlOSUtil.h" +#include "igtlTrackingDataMessage.h" +#include "igtlMessageRTPWrapper.h" +#include "igtlUDPClientSocket.h" + +int ReceiveTrackingData(igtl::TrackingDataMessage::Pointer& msgData); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 or 18945 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + //------------------------------------------------------------ + // Establish Connection + + igtl::UDPClientSocket::Pointer socket; + socket = igtl::UDPClientSocket::New(); + int success = socket->JoinNetwork("127.0.0.1", port); + if (success<0) + { + std::cerr << "unable to join network, check if your local machine joined the host more than once. " << std::endl; + exit(0); + } + unsigned char* bufferPKT = new unsigned char[RTP_PAYLOAD_LENGTH+RTP_HEADER_LENGTH]; + igtl::MessageRTPWrapper::Pointer rtpWrapper = igtl::MessageRTPWrapper::New(); + igtl::SimpleMutexLock* glock = igtl::SimpleMutexLock::New(); + int loop = 0; + for (loop = 0; loop<100; loop++) + { + int totMsgLen = socket->ReadSocket(bufferPKT, RTP_PAYLOAD_LENGTH+RTP_HEADER_LENGTH); + rtpWrapper->PushDataIntoPacketBuffer(bufferPKT, totMsgLen); + rtpWrapper->UnWrapPacketWithTypeAndName("TDATA", "Tracker"); + glock->Lock(); + unsigned int messageNum = rtpWrapper->unWrappedMessages.size(); + glock->Unlock(); + if(messageNum)// to do: glock this session + { + igtl::TrackingDataMessage::Pointer trackingMultiPKTMSG = igtl::TrackingDataMessage::New(); + glock->Lock(); + std::map::iterator it = rtpWrapper->unWrappedMessages.begin(); + igtlUint8 * message = new igtlUint8[it->second->messageDataLength]; + int MSGLength = it->second->messageDataLength; + memcpy(message, it->second->messagePackPointer, it->second->messageDataLength); + delete it->second; + it->second = NULL; + rtpWrapper->unWrappedMessages.erase(it); + glock->Unlock(); + igtl::MessageHeader::Pointer header = igtl::MessageHeader::New(); + header->InitPack(); + memcpy(header->GetPackPointer(), message, IGTL_HEADER_SIZE); + header->Unpack(); + trackingMultiPKTMSG->SetMessageHeader(header); + trackingMultiPKTMSG->AllocateBuffer(); + if (MSGLength == trackingMultiPKTMSG->GetPackSize()) + { + memcpy(trackingMultiPKTMSG->GetPackPointer(), message, MSGLength); + ReceiveTrackingData(trackingMultiPKTMSG); + } + } + } +} + + +int ReceiveTrackingData(igtl::TrackingDataMessage::Pointer& msgData) +{ + // Receive body from the socket + igtl::TrackingDataMessage::Pointer trackingData; + trackingData = igtl::TrackingDataMessage::New(); + //trackingData->SetMessageHeader(header); + trackingData->Copy(msgData); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = trackingData->Unpack(0); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = trackingData->GetNumberOfTrackingDataElements(); + for (int i = 0; i < nElements; i ++) + { + igtl::TrackingDataElement::Pointer trackingElement; + trackingData->GetTrackingDataElement(i, trackingElement); + + igtl::Matrix4x4 matrix; + trackingElement->GetMatrix(matrix); + + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << trackingElement->GetName() << std::endl; + std::cerr << " Type : " << (int) trackingElement->GetType() << std::endl; + std::cerr << " Matrix : " << std::endl; + igtl::PrintMatrix(matrix); + std::cerr << "================================" << std::endl; + } + return 1; + } + return 0; +} + + diff --git a/openigtlink/repo/Examples/TrackingDataUDPTransfer/TrackingDataServerUDPTransfer.cxx b/openigtlink/repo/Examples/TrackingDataUDPTransfer/TrackingDataServerUDPTransfer.cxx new file mode 100755 index 0000000..76a0f0a --- /dev/null +++ b/openigtlink/repo/Examples/TrackingDataUDPTransfer/TrackingDataServerUDPTransfer.cxx @@ -0,0 +1,208 @@ +/*========================================================================= + + Program: Open IGT Link -- Example for Tracking Data Server + Module: $RCSfile: $ + Language: C++ + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlImageMessage.h" +#include "igtlUDPServerSocket.h" +#include "igtlTrackingDataMessage.h" +#include "igtlMultiThreader.h" +#include "igtlMessageRTPWrapper.h" + + +void WrapMessage(igtl::UDPServerSocket::Pointer serverSocket,igtl::MessageRTPWrapper::Pointer rtpWrapper); +int SendTrackingData(igtl::UDPServerSocket::Pointer& socket, igtl::TrackingDataMessage::Pointer& trackingMsg, igtl::MessageRTPWrapper::Pointer rtpWrapper); +void GetRandomTestMatrix(igtl::Matrix4x4& matrix, float phi, float theta); + + +int main(int argc, char* argv[]) +{ + + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 1) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: No augments" << std::endl; + exit(0); + } + + igtl::UDPServerSocket::Pointer serverSocket; + serverSocket = igtl::UDPServerSocket::New(); + int r = serverSocket->CreateUDPServer(); + serverSocket->AddClient("127.0.0.1", 18944, 1); + serverSocket->AddClient("127.0.0.1", 18945, 1); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + igtl::MessageRTPWrapper::Pointer rtpWrapper = igtl::MessageRTPWrapper::New(); + //------------------------------------------------------------ + // loop + for (int i = 0;i<1000;i++) + { + WrapMessage(serverSocket, rtpWrapper); + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + serverSocket->CloseSocket(); + +} + + +void WrapMessage(igtl::UDPServerSocket::Pointer serverSocket, igtl::MessageRTPWrapper::Pointer rtpWrapper) +{ + //------------------------------------------------------------ + // Get user data + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + long interval = 500; + std::cerr << "Interval = " << interval << " (ms)" << std::endl; + //long interval = 1000; + //long interval = (id + 1) * 100; // (ms) + //------------------------------------------------------------ + // Allocate TrackingData Message Class + // + // NOTE: TrackingDataElement class instances are allocated + // before the loop starts to avoid reallocation + // in each image transfer. + + igtl::TrackingDataMessage::Pointer trackingMsg; + trackingMsg = igtl::TrackingDataMessage::New(); + trackingMsg->SetDeviceName("Tracker"); + + igtl::TrackingDataElement::Pointer trackElement0; + trackElement0 = igtl::TrackingDataElement::New(); + trackElement0->SetName("Channel 0"); + trackElement0->SetType(igtl::TrackingDataElement::TYPE_TRACKER); + + igtl::TrackingDataElement::Pointer trackElement1; + trackElement1 = igtl::TrackingDataElement::New(); + trackElement1->SetName("Channel 1"); + trackElement1->SetType(igtl::TrackingDataElement::TYPE_6D); + + igtl::TrackingDataElement::Pointer trackElement2; + trackElement2 = igtl::TrackingDataElement::New(); + trackElement2->SetName("Channel 2"); + trackElement2->SetType(igtl::TrackingDataElement::TYPE_5D); + + trackingMsg->AddTrackingDataElement(trackElement0); + trackingMsg->AddTrackingDataElement(trackElement1); + trackingMsg->AddTrackingDataElement(trackElement2); + + //------------------------------------------------------------ + glock->Lock(); + SendTrackingData(serverSocket, trackingMsg, rtpWrapper); + glock->Unlock(); + igtl::Sleep(interval); +} + + +int SendTrackingData(igtl::UDPServerSocket::Pointer& socket, igtl::TrackingDataMessage::Pointer& trackingMsg, igtl::MessageRTPWrapper::Pointer rtpWrapper) +{ + + static float phi0 = 0.0; + static float theta0 = 0.0; + static float phi1 = 0.0; + static float theta1 = 0.0; + static float phi2 = 0.0; + static float theta2 = 0.0; + + igtl::Matrix4x4 matrix; + igtl::TrackingDataElement::Pointer ptr; + + // Channel 0 + trackingMsg->GetTrackingDataElement(0, ptr); + GetRandomTestMatrix(matrix, phi0, theta0); + ptr->SetMatrix(matrix); + + // Channel 1 + trackingMsg->GetTrackingDataElement(1, ptr); + GetRandomTestMatrix(matrix, phi1, theta1); + ptr->SetMatrix(matrix); + + // Channel 2 + trackingMsg->GetTrackingDataElement(2, ptr); + GetRandomTestMatrix(matrix, phi2, theta2); + ptr->SetMatrix(matrix); + + trackingMsg->Pack(); + rtpWrapper->SetSSRC(1); + int status = igtl::MessageRTPWrapper::PacketReady; + igtl_uint8* messagePointer = (igtl_uint8*)trackingMsg->GetPackPointer(); + rtpWrapper->SetMSGHeader((igtl_uint8*)trackingMsg->GetPackPointer()); + int messageLength = trackingMsg->GetPackSize(); + status = rtpWrapper->WrapMessageAndSend(socket, messagePointer, messageLength); + + phi0 += 0.1; + phi1 += 0.2; + phi2 += 0.3; + theta0 += 0.2; + theta1 += 0.1; + theta2 += 0.05; + + return 0; +} + + + +//------------------------------------------------------------ +// Function to generate random matrix. +void GetRandomTestMatrix(igtl::Matrix4x4& matrix, float phi, float theta) +{ + float position[3]; + float orientation[4]; + + // random position + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + phi = phi + 0.2; + + // random orientation + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + //igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + + //igtl::PrintMatrix(matrix); +} + + + + + + diff --git a/openigtlink/repo/Examples/Trajectory/CMakeLists.txt b/openigtlink/repo/Examples/Trajectory/CMakeLists.txt new file mode 100644 index 0000000..a892e3d --- /dev/null +++ b/openigtlink/repo/Examples/Trajectory/CMakeLists.txt @@ -0,0 +1,18 @@ +PROJECT(Trajectory) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +ADD_EXECUTABLE(TrajectoryClient TrajectoryClient.cxx) +TARGET_LINK_LIBRARIES(TrajectoryClient OpenIGTLink) + +ADD_EXECUTABLE(TrajectoryServer TrajectoryServer.cxx) +TARGET_LINK_LIBRARIES(TrajectoryServer OpenIGTLink) + + diff --git a/openigtlink/repo/Examples/Trajectory/TrajectoryClient.cxx b/openigtlink/repo/Examples/Trajectory/TrajectoryClient.cxx new file mode 100644 index 0000000..12ec227 --- /dev/null +++ b/openigtlink/repo/Examples/Trajectory/TrajectoryClient.cxx @@ -0,0 +1,113 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Trajectory message + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlTrajectoryMessage.h" +#include "igtlClientSocket.h" + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Allocate Transform Message Class + + igtl::TrajectoryMessage::Pointer trajectoryMsg; + trajectoryMsg = igtl::TrajectoryMessage::New(); + trajectoryMsg->SetDeviceName("TrajectorySender"); + + //--------------------------- + // Create 1st trajectory + igtl::TrajectoryElement::Pointer trajectory0; + trajectory0 = igtl::TrajectoryElement::New(); + trajectory0->SetName("TRAJECTORY_0"); + trajectory0->SetGroupName("GROUP_0"); + trajectory0->SetRGBA(0xFF, 0x00, 0x00, 0xFF); + trajectory0->SetEntryPosition(10.0, 20.0, 30.0); + trajectory0->SetTargetPosition(20.0, 20.0, 40.0); + trajectory0->SetRadius(15.0); + trajectory0->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 2nd trajectory + igtl::TrajectoryElement::Pointer trajectory1; + trajectory1 = igtl::TrajectoryElement::New(); + trajectory1->SetName("TRAJECTORY_1"); + trajectory1->SetGroupName("GROUP_0"); + trajectory1->SetRGBA(0x00, 0xFF, 0x00, 0xFF); + trajectory1->SetEntryPosition(40.0, 50.0, 60.0); + trajectory1->SetTargetPosition(20.0, 30.0, 10.0); + trajectory1->SetRadius(45.0); + trajectory1->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 3rd trajectory + igtl::TrajectoryElement::Pointer trajectory2; + trajectory2 = igtl::TrajectoryElement::New(); + trajectory2->SetName("TRAJECTORY_2"); + trajectory2->SetGroupName("GROUP_0"); + trajectory2->SetRGBA(0x00, 0x00, 0xFF, 0xFF); + trajectory2->SetEntryPosition(70.0, 80.0, 90.0); + trajectory1->SetTargetPosition(10.0, 40.0, 20.0); + trajectory2->SetRadius(75.0); + trajectory2->SetOwner("IMAGE_0"); + + //--------------------------- + // Pack into the trajectory message + trajectoryMsg->AddTrajectoryElement(trajectory0); + trajectoryMsg->AddTrajectoryElement(trajectory1); + trajectoryMsg->AddTrajectoryElement(trajectory2); + trajectoryMsg->Pack(); + + //------------------------------------------------------------ + // Send + socket->Send(trajectoryMsg->GetPackPointer(), trajectoryMsg->GetPackSize()); + + + //------------------------------------------------------------ + // Close the socket + socket->CloseSocket(); + +} + diff --git a/openigtlink/repo/Examples/Trajectory/TrajectoryServer.cxx b/openigtlink/repo/Examples/Trajectory/TrajectoryServer.cxx new file mode 100644 index 0000000..e4260c5 --- /dev/null +++ b/openigtlink/repo/Examples/Trajectory/TrajectoryServer.cxx @@ -0,0 +1,120 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Trajectory message + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlTrajectoryMessage.h" +#include "igtlServerSocket.h" + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + + //--------------------------- + // Create a trajectory message + igtl::TrajectoryMessage::Pointer trajectoryMsg; + trajectoryMsg = igtl::TrajectoryMessage::New(); + trajectoryMsg->SetDeviceName("TrajectorySender"); + + //--------------------------- + // Create 1st trajectory + igtl::TrajectoryElement::Pointer trajectory0; + trajectory0 = igtl::TrajectoryElement::New(); + trajectory0->SetName("TRAJECTORY_0"); + trajectory0->SetGroupName("GROUP_0"); + trajectory0->SetRGBA(0xFF, 0x00, 0x00, 0xFF); + trajectory0->SetEntryPosition(10.0, 20.0, 30.0); + trajectory0->SetTargetPosition(20.0, 20.0, 40.0); + trajectory0->SetRadius(15.0); + trajectory0->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 2nd trajectory + igtl::TrajectoryElement::Pointer trajectory1; + trajectory1 = igtl::TrajectoryElement::New(); + trajectory1->SetName("TRAJECTORY_1"); + trajectory1->SetGroupName("GROUP_0"); + trajectory1->SetRGBA(0x00, 0xFF, 0x00, 0xFF); + trajectory1->SetEntryPosition(40.0, 50.0, 60.0); + trajectory1->SetTargetPosition(20.0, 30.0, 10.0); + trajectory1->SetRadius(45.0); + trajectory1->SetOwner("IMAGE_0"); + + //--------------------------- + // Create 3rd trajectory + igtl::TrajectoryElement::Pointer trajectory2; + trajectory2 = igtl::TrajectoryElement::New(); + trajectory2->SetName("TRAJECTORY_2"); + trajectory2->SetGroupName("GROUP_0"); + trajectory2->SetRGBA(0x00, 0x00, 0xFF, 0xFF); + trajectory2->SetEntryPosition(70.0, 80.0, 90.0); + trajectory2->SetTargetPosition(10.0, 40.0, 20.0); + trajectory2->SetRadius(75.0); + trajectory2->SetOwner("IMAGE_0"); + + //--------------------------- + // Pack into the trajectory message + trajectoryMsg->AddTrajectoryElement(trajectory0); + trajectoryMsg->AddTrajectoryElement(trajectory1); + trajectoryMsg->AddTrajectoryElement(trajectory2); + trajectoryMsg->Pack(); + + //--------------------------- + // Send + socket->Send(trajectoryMsg->GetPackPointer(), trajectoryMsg->GetPackSize()); + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + } + + socket->CloseSocket(); + +} + + diff --git a/openigtlink/repo/Examples/VideoStreaming/CMakeLists.txt b/openigtlink/repo/Examples/VideoStreaming/CMakeLists.txt new file mode 100755 index 0000000..cc582be --- /dev/null +++ b/openigtlink/repo/Examples/VideoStreaming/CMakeLists.txt @@ -0,0 +1,22 @@ +PROJECT(VideoStreaming) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +add_executable( VideoServer VideoServer.cxx) +target_link_libraries( VideoServer OpenIGTLink) + +add_executable( VideoClient VideoClient.cxx) +target_link_libraries( VideoClient OpenIGTLink) + +add_executable( VideoMetaServer VideoMetaServer.cxx) +target_link_libraries( VideoMetaServer OpenIGTLink) + +add_executable( VideoMetaClient VideoMetaClient.cxx) +target_link_libraries( VideoMetaClient OpenIGTLink) diff --git a/openigtlink/repo/Examples/VideoStreaming/VideoClient.cxx b/openigtlink/repo/Examples/VideoStreaming/VideoClient.cxx new file mode 100644 index 0000000..57c477f --- /dev/null +++ b/openigtlink/repo/Examples/VideoStreaming/VideoClient.cxx @@ -0,0 +1,191 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Client Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlVideoMessage.h" +#include "igtlClientSocket.h" + + +#if defined(OpenIGTLink_USE_H264) +#include "igtlH264Decoder.h" +#endif + +#if defined(OpenIGTLink_USE_VP9) +#include "igtlVP9Decoder.h" +#endif + +#if defined(OpenIGTLink_USE_AV1) +#include "igtlAV1Decoder.h" +#endif + +using namespace igtl; + +int ReceiveVideoData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header, GenericDecoder * decoder); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 4) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + std::cerr << " : Frequency (fps) to send video frame" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + double fps = atof(argv[3]); + int interval = (int) (1000.0 / fps); + + //------------------------------------------------------------ + // Establish Connection + + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + GenericDecoder * decoder = NULL; +#if defined(OpenIGTLink_USE_VP9) + VP9Decoder* VP9StreamDecoder = new VP9Decoder(); + decoder = VP9StreamDecoder; +#endif +#if defined(OpenIGTLink_USE_H264) + H264Decoder* H264StreamDecoder = new H264Decoder(); + decoder = H264StreamDecoder; +#endif +#if defined(OpenIGTLink_USE_AV1) + igtlAV1Decoder* AV1StreamDecoder = new igtlAV1Decoder(); + decoder = AV1StreamDecoder; +#endif + + //------------------------------------------------------------ + // Ask the server to start pushing tracking data + std::cerr << "Sending STT_VIDEO message....." << std::endl; + igtl::StartVideoMessage::Pointer startVideoMsg; + startVideoMsg = igtl::StartVideoMessage::New(); + startVideoMsg->SetDeviceName("Laparoscopy"); + startVideoMsg->SetTimeInterval(interval); + startVideoMsg->Pack(); + socket->Send(startVideoMsg->GetPackPointer(), startVideoMsg->GetPackSize()); + + int loop = 0; + + while (1) + { + //------------------------------------------------------------ + // Wait for a reply + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + std::cerr << "Message size information and actual data size don't match." << std::endl; + socket->CloseSocket(); + exit(0); + } + + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "VIDEO") == 0) + { + ReceiveVideoData(socket, headerMsg, decoder); + } + else + { + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + if (++loop >= 250) // if received 100 times + { + //------------------------------------------------------------ + // Ask the server to stop pushing tracking data + std::cerr << "Sending STP_TDATA message....." << std::endl; + igtl::StopVideoMessage::Pointer stopVideoMsg; + stopVideoMsg = igtl::StopVideoMessage::New(); + stopVideoMsg->SetDeviceName("Laparoscopy"); + stopVideoMsg->Pack(); + socket->Send(stopVideoMsg->GetPackPointer(), stopVideoMsg->GetPackSize()); + loop = 0; + } + } +} + + +int ReceiveVideoData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header, GenericDecoder * decoder) +{ + std::cerr << "Receiving TDATA data type." << std::endl; + + //------------------------------------------------------------ + // Allocate TrackingData Message Class + + igtl::VideoMessage::Pointer videoMsg; + videoMsg = igtl::VideoMessage::New(); + videoMsg->SetMessageHeader(header); + videoMsg->AllocatePack(); + + // Receive body from the socket + bool timeout(false); + socket->Receive(videoMsg->GetPackBodyPointer(), videoMsg->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = videoMsg->Unpack(1); + + static int totalFrame = 0; + SourcePicture* pDecodedPic = new SourcePicture(); + pDecodedPic->data[0] = new igtl_uint8[videoMsg->GetWidth()*videoMsg->GetHeight()*3/2]; + memset(pDecodedPic->data[0], 0, videoMsg->GetWidth()*videoMsg->GetHeight() * 3 / 2); + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int iRet= decoder->DecodeVideoMSGIntoSingleFrame(videoMsg.GetPointer(), pDecodedPic); + if(iRet) + { + std::cerr<<"Decoding Frame Index: " << totalFrame << std::endl; + totalFrame ++; + } + else + { + delete pDecodedPic; + pDecodedPic = NULL; + return 0; + } + } + delete pDecodedPic; + pDecodedPic = NULL; + return 1; +} + + diff --git a/openigtlink/repo/Examples/VideoStreaming/VideoMetaClient.cxx b/openigtlink/repo/Examples/VideoStreaming/VideoMetaClient.cxx new file mode 100644 index 0000000..d9c587d --- /dev/null +++ b/openigtlink/repo/Examples/VideoStreaming/VideoMetaClient.cxx @@ -0,0 +1,159 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Video Meta Data Client + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlVideoMessage.h" +#include "igtlVideoMetaMessage.h" +#include "igtlClientSocket.h" + + +int ReceiveVideoMeta(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); + + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 3) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + char* hostname = argv[1]; + int port = atoi(argv[2]); + + //------------------------------------------------------------ + // Establish Connection + igtl::ClientSocket::Pointer socket; + socket = igtl::ClientSocket::New(); + int r = socket->ConnectToServer(hostname, port); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 10; i ++) + { + //------------------------------------------------------------ + // Send request data + igtl::GetVideoMetaMessage::Pointer getVideoMetaMsg; + getVideoMetaMsg = igtl::GetVideoMetaMessage::New(); + getVideoMetaMsg->SetDeviceName("Client"); + getVideoMetaMsg->Pack(); + socket->Send(getVideoMetaMsg->GetPackPointer(), getVideoMetaMsg->GetPackSize()); + + //------------------------------------------------------------ + // Wait for a reply + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + std::cerr << "Message size information and actual data size don't match." << std::endl; + exit(0); + } + + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "VIDEOMETA") == 0) + { + ReceiveVideoMeta(socket, headerMsg); + } + else + { + std::cerr << "Invalid response from the server:" << headerMsg->GetDeviceName() << std::endl; + exit(0); + } + + igtl::Sleep(500); // wait + } + + //------------------------------------------------------------ + // Close connection + socket->CloseSocket(); + +} + + +int ReceiveVideoMeta(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header) +{ + + std::cerr << "Receiving VIDEOMETA data type." << std::endl; + + // Create a message buffer to receive transform data + igtl::VideoMetaMessage::Pointer videoMeta; + videoMeta = igtl::VideoMetaMessage::New(); + videoMeta->SetMessageHeader(header); + videoMeta->AllocatePack(); + + // Receive transform data from the socket + bool timeout(false); + socket->Receive(videoMeta->GetPackBodyPointer(), videoMeta->GetPackBodySize(), timeout); + + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = videoMeta->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = videoMeta->GetNumberOfVideoMetaElement(); + for (int i = 0; i < nElements; i ++) + { + igtl::VideoMetaElement::Pointer videoMetaElement; + videoMeta->GetVideoMetaElement(i, videoMetaElement); + igtlUint16 size[3]; + videoMetaElement->GetSize(size[0],size[1],size[2]); + igtl::Matrix4x4 mat; + videoMetaElement->GetMatrix(mat); + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << videoMetaElement->GetName() << std::endl; + std::cerr << " DeviceName : " << videoMetaElement->GetDeviceName() << std::endl; + std::cerr << " PatientName: " << videoMetaElement->GetPatientName() << std::endl; + std::cerr << " PatientID : " << videoMetaElement->GetPatientID() << std::endl; + igtl::PrintMatrix(mat); + std::cerr << " Size : ( " << size[0] << ", " << size[1] << ", " << size[2] << ")" << std::endl; + std::cerr << " ScalarType : " << (int) videoMetaElement->GetScalarType() << std::endl; + std::cerr << "================================" << std::endl; + } + return 1; + } + + return 0; + +} + + + diff --git a/openigtlink/repo/Examples/VideoStreaming/VideoMetaServer.cxx b/openigtlink/repo/Examples/VideoStreaming/VideoMetaServer.cxx new file mode 100644 index 0000000..57f8b2d --- /dev/null +++ b/openigtlink/repo/Examples/VideoStreaming/VideoMetaServer.cxx @@ -0,0 +1,200 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Video Meta Data Server + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlVideoMessage.h" +#include "igtlServerSocket.h" +#include "igtlVideoMetaMessage.h" + + +int SendVideoMeta(igtl::Socket::Pointer& socket, const char* name); + +int main(int argc, char* argv[]) +{ + + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + + igtl::Socket::Pointer socket; + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + + //------------------------------------------------------------ + // loop + for (int i = 0; i < 100; i ++) + { + + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + socket->CloseSocket(); + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "GET_VMETA") == 0) + { + std::cerr << "Received a GET_VMETA message." << std::endl; + //socket->Skip(headerMsg->GetBodySizeToRead(), 0); + SendVideoMeta(socket, headerMsg->GetDeviceName()); + } + else + { + // if the data type is unknown, skip reading. + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + + socket->CloseSocket(); + +} + + +int SendVideoMeta(igtl::Socket::Pointer& socket, const char* name) +{ + + //------------------------------------------------------------ + // Allocate Status Message Class + + igtl::VideoMetaMessage::Pointer videoMetaMsg; + videoMetaMsg = igtl::VideoMetaMessage::New(); + // NOTE: the server should send a message with the same device name + // as the received query message. + videoMetaMsg->SetDeviceName(name); + + //--------------------------- + // Create 1st meta data + igtl::VideoMetaElement::Pointer videoMeta0; + videoMeta0 = igtl::VideoMetaElement::New(); + videoMeta0->SetName("VIDEO_DESCRIPTION_0"); + videoMeta0->SetDeviceName("VIDEO_0"); + videoMeta0->SetPatientName("PATIENT_0"); + videoMeta0->SetPatientID("PATIENT_ID_0"); + videoMeta0->SetSize(512, 512, 64); + igtl::Matrix4x4 matrix; + matrix[0][0] = 1.0; matrix[1][0] = 0.0; matrix[2][0] = 0.0; matrix[3][0] = -75.0; + matrix[0][1] = 0.0; matrix[1][1] = -1.0; matrix[2][1] = 0.0; matrix[3][1] = -50.0; + matrix[0][2] = 0.0; matrix[1][2] = 0.0; matrix[2][2] = 1.0; matrix[3][2] = 10.5; + matrix[0][3] = 0.0; matrix[1][3] = 0.0; matrix[2][3] = 0.0; matrix[3][3] = 1.0; + videoMeta0->SetScalarType(igtl::VideoMessage::TYPE_UINT8); + + //--------------------------- + // Create 2nd meta data + igtl::VideoMetaElement::Pointer videoMeta1; + videoMeta1 = igtl::VideoMetaElement::New(); + videoMeta1->SetName("VIDEO_DESCRIPTION_1"); + videoMeta1->SetDeviceName("VIDEO_1"); + videoMeta1->SetPatientName("PATIENT_1"); + videoMeta1->SetPatientID("PATIENT_ID_1"); + videoMeta1->SetSize(256, 256, 64); + igtl::Matrix4x4 matrix1; + matrix1[0][0] = -1.0; matrix1[1][0] = 0.0; matrix1[2][0] = 0.0; matrix1[3][0] = -15.0; + matrix1[0][1] = 0.0; matrix1[1][1] = 1.0; matrix1[2][1] = 0.0; matrix1[3][1] = 50.0; + matrix1[0][2] = 0.0; matrix1[1][2] = 0.0; matrix1[2][2] = 1.0; matrix1[3][2] = 30.5; + matrix1[0][3] = 0.0; matrix1[1][3] = 0.0; matrix1[2][3] = 0.0; matrix1[3][3] = 1.0; + videoMeta1->SetScalarType(igtl::VideoMessage::TYPE_UINT16); + + //--------------------------- + // Create 3rd meta data + igtl::VideoMetaElement::Pointer videoMeta2; + videoMeta2 = igtl::VideoMetaElement::New(); + videoMeta2->SetName("VIDEO_DESCRIPTION_2"); + videoMeta2->SetDeviceName("VIDEO_2"); + videoMeta2->SetPatientName("PATIENT_2"); + videoMeta2->SetPatientID("PATIENT_ID_2"); + videoMeta2->SetSize(256, 128, 1); + igtl::Matrix4x4 matrix2; + matrix2[0][0] = 1.0; matrix2[1][0] = 0.0; matrix2[2][0] = 0.0; matrix2[3][0] = 15.0; + matrix2[0][1] = 0.0; matrix2[1][1] = 1.0; matrix2[2][1] = 0.0; matrix2[3][1] = 250.0; + matrix2[0][2] = 0.0; matrix2[1][2] = 0.0; matrix2[2][2] = -1.0; matrix2[3][2] = 7.6; + matrix2[0][3] = 0.0; matrix2[1][3] = 0.0; matrix2[2][3] = 0.0; matrix2[3][3] = 1.0; + videoMeta2->SetScalarType(igtl::VideoMessage::TYPE_UINT16); + + videoMetaMsg->AddVideoMetaElement(videoMeta0); + videoMetaMsg->AddVideoMetaElement(videoMeta1); + videoMetaMsg->AddVideoMetaElement(videoMeta2); + + videoMetaMsg->Pack(); + std::cerr << "Size of pack: " << videoMetaMsg->GetPackSize() << std::endl; + std::cerr << "Name of type: " << videoMetaMsg->GetDeviceType() << std::endl; + std::cerr << "Sending a VIDEOMETA message..." << std::endl; + + socket->Send(videoMetaMsg->GetPackPointer(), videoMetaMsg->GetPackSize()); + + return 1; + +} + + + + + + + + diff --git a/openigtlink/repo/Examples/VideoStreaming/VideoServer.cxx b/openigtlink/repo/Examples/VideoStreaming/VideoServer.cxx new file mode 100644 index 0000000..e5bb2bb --- /dev/null +++ b/openigtlink/repo/Examples/VideoStreaming/VideoServer.cxx @@ -0,0 +1,261 @@ +/*========================================================================= + + Program: OpenIGTLink -- Example for Tracker Server Program + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include "igtlVideoMessage.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_video.h" +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_util.h" +#include "igtlOSUtil.h" +#include "string.h" +#include +#include + +#if defined(OpenIGTLink_USE_H264) +#include "igtlH264Encoder.h" +#include "igtlH264Decoder.h" +#endif + +#if defined(OpenIGTLink_USE_VP9) +#include "igtlVP9Encoder.h" +#include "igtlVP9Decoder.h" +#endif + +#if defined (OpenIGTLink_USE_AV1) +#include "igtlAV1Encoder.h" +#include "igtlAV1Decoder.h" +#endif + +#include "igtlServerSocket.h" +#include "igtlMultiThreader.h" + +using namespace igtl; + +int Width = 256; +int Height = 256; +std::string testFileName(OpenIGTLink_SOURCE_ROOTDIR); +int startIndex = 0; +int inputFrameNum = 2000; + +void* ThreadFunction(void* ptr); + +typedef struct { + int nloop; + igtl::MutexLock::Pointer glock; + igtl::Socket::Pointer socket; + int interval; + int stop; +} ThreadData; + +void SendEncodedVideoMessage(igtl::Socket::Pointer& videoMsg, igtl::MutexLock::Pointer& glock, int interval); + +int main(int argc, char* argv[]) +{ + //------------------------------------------------------------ + // Parse Arguments + + if (argc != 2) // check number of arguments + { + // If not correct, print usage + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + exit(0); + } + + int port = atoi(argv[1]); + + igtl::ServerSocket::Pointer serverSocket; + serverSocket = igtl::ServerSocket::New(); + int r = serverSocket->CreateServer(port); + + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + ThreadData td; + igtl::Socket::Pointer socket; + + while (1) + { + int threadID = -1; + //------------------------------------------------------------ + // Waiting for Connection + socket = serverSocket->WaitForConnection(1000); + + if (socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + // Create a message buffer to receive header + td.interval = 100; + td.glock = glock; + td.socket = socket; + td.stop = 0; + threadID = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + // Create a message buffer to receive header + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + //------------------------------------------------------------ + // loop + for (;;) + { + // Initialize receive buffer + headerMsg->InitPack(); + + // Receive generic header from the socket + bool timeout(false); + igtlUint64 rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs <= 0) + { + if (threadID >= 0) + { + td.stop = 1; + threader->TerminateThread(threadID); + threadID = -1; + } + std::cerr << "Disconnecting the client." << std::endl; + td.socket = NULL; // VERY IMPORTANT. Completely remove the instance. + socket->CloseSocket(); + break; + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reachs to this section ...) + + socket->CloseSocket(); + +} + + +void* ThreadFunction(void * ptr) +{ + //------------------------------------------------------------ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + ThreadData* td = static_cast(info->UserData); + + //------------------------------------------------------------ + // Get user data + igtl::MutexLock::Pointer glock = td->glock; + long interval = td->interval; + std::cerr << "Interval = " << interval << " (ms)" << std::endl; + igtl::Socket::Pointer& socket = td->socket; + GenericEncoder * encoder = NULL; + +#if defined(OpenIGTLink_USE_VP9) + VP9Encoder* VP9StreamEncoder = new VP9Encoder(); + VP9StreamEncoder->SetPicWidthAndHeight(Width,Height); + VP9StreamEncoder->InitializeEncoder(); + VP9StreamEncoder->SetLosslessLink(true); + VP9StreamEncoder->SetKeyFrameDistance(50); + encoder = VP9StreamEncoder; +#elif defined(OpenIGTLink_USE_AV1) + igtlAV1Encoder* AV1StreamEncoder = new igtlAV1Encoder(); + AV1StreamEncoder->SetPicWidthAndHeight(Width, Height); + AV1StreamEncoder->InitializeEncoder(); + AV1StreamEncoder->SetLosslessLink(true); + encoder = AV1StreamEncoder; +#elif defined(OpenIGTLink_USE_H264) + H264Encoder* H264StreamEncoder = new H264Encoder(); + H264StreamEncoder->SetPicWidthAndHeight(Width,Height); + H264StreamEncoder->InitializeEncoder(); + encoder = H264StreamEncoder; +#endif + // Get thread information + int kiPicResSize = Width*Height; + igtl_uint8* imagePointer = new igtl_uint8[kiPicResSize*3/2]; + memset(imagePointer, 0, Width * Height * 3 / 2); + SourcePicture* pSrcPic = new SourcePicture(); + pSrcPic->colorFormat = FormatI420; + pSrcPic->picWidth = Width; // check the test image + pSrcPic->picHeight = Height; + pSrcPic->data[0] = imagePointer; + pSrcPic->data[1] = pSrcPic->data[0] + kiPicResSize; + pSrcPic->data[2] = pSrcPic->data[1] + kiPicResSize/4; + pSrcPic->stride[0] = pSrcPic->picWidth; + pSrcPic->stride[1] = pSrcPic->stride[2] = pSrcPic->stride[0] >> 1; + + SourcePicture* pDecodedPic = new SourcePicture(); + pDecodedPic->data[0] = new igtl_uint8[kiPicResSize*3/2]; + memset(pDecodedPic->data[0], 0, Width * Height * 3 / 2); + for(int i = 0; i stop) + { + break; + } + std::string sep = "/"; +#if defined(_WIN32) || defined(_WIN64) + sep = "\\"; +#endif + std::stringstream stream; + stream << (i%6+1); + std::string imageIndexStr = stream.str(); + std::string testIndexedFileName = std::string(testFileName); + testIndexedFileName.append(sep).append("Testing").append(sep).append("img").append(sep).append("igtlTestImage").append(imageIndexStr).append(".raw"); + FILE* pFileYUV = NULL; + pFileYUV = fopen (testIndexedFileName.c_str(), "rb"); + if (pFileYUV != NULL) { + if(fread (imagePointer, 1, kiPicResSize, pFileYUV ) == (kiPicResSize)) + { + bool isGrayImage = true; + igtl::VideoMessage::Pointer videoMessageSend = igtl::VideoMessage::New(); + videoMessageSend->SetDeviceName("Laparoscopy"); + videoMessageSend->SetHeaderVersion(IGTL_HEADER_VERSION_2); + int iEncFrames = encoder->EncodeSingleFrameIntoVideoMSG(pSrcPic, videoMessageSend, isGrayImage); + if(iEncFrames == 0 && !td->stop) + { + std::cerr<<"Encoding Frame index: " << i << std::endl; + std::cerr<<"Packet size: " << videoMessageSend->GetPackSize() << std::endl; + glock->Lock(); + socket->Send(videoMessageSend->GetPackPointer(), videoMessageSend->GetPackSize()); + glock->Unlock(); + igtl::Sleep(interval); // wait + } + else + { + break; + } + } + if (pFileYUV) + { + fclose(pFileYUV); + pFileYUV = NULL; + } + } + else + { + fprintf (stderr, "Unable to open image file, check corresponding path!\n"); + } + } + delete pSrcPic; + pSrcPic = NULL; + return NULL; +} + + \ No newline at end of file diff --git a/openigtlink/repo/Examples/WebSocket/CMakeLists.txt b/openigtlink/repo/Examples/WebSocket/CMakeLists.txt new file mode 100644 index 0000000..df45210 --- /dev/null +++ b/openigtlink/repo/Examples/WebSocket/CMakeLists.txt @@ -0,0 +1,18 @@ +PROJECT(WebSocket) + +cmake_minimum_required(VERSION 2.4) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +find_package(OpenIGTLink REQUIRED) + +include(${OpenIGTLink_USE_FILE}) + +## igtl::WebSocket examples +ADD_EXECUTABLE(WebSocketServer WebSocketServer.cxx) + +target_link_libraries(WebSocketServer OpenIGTLink ${Boost_LIBRARIES}) + +ADD_EXECUTABLE(WebSocketClient WebSocketClient.cxx) +TARGET_LINK_LIBRARIES(WebSocketClient OpenIGTLink ${Boost_LIBRARIES}) diff --git a/openigtlink/repo/Examples/WebSocket/WebSocketClient.cxx b/openigtlink/repo/Examples/WebSocket/WebSocketClient.cxx new file mode 100644 index 0000000..3eef0ee --- /dev/null +++ b/openigtlink/repo/Examples/WebSocket/WebSocketClient.cxx @@ -0,0 +1,110 @@ + +#include "igtlWebClientSocket.h" + +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlImageMessage.h" + +#include "igtlTrackingDataMessage.h" +#include "igtlMultiThreader.h" + +#include +#include +#include +#include +#include + +/** + * The telemetry server accepts connections and sends a message every second to + * each client containing an integer count. This example can be used as the + * basis for programs that expose a stream of telemetry data for logging, + * dashboards, etc. + * + * This example uses the timer based concurrency method and is self contained + * and singled threaded. Refer to telemetry client for an example of a similar + * telemetry setup using threads rather than timers. + * + * This example also includes an example simple HTTP server that serves a web + * dashboard displaying the count. This simple design is suitable for use + * delivering a small number of files to a small number of clients. It is ideal + * for cases like embedded dashboards that don't want the complexity of an extra + * HTTP server to serve static files. + * + * This design *will* fall over under high traffic or DoS conditions. In such + * cases you are much better off proxying to a real HTTP server for the http + * requests. + */ + +int ReceiveTrackingData(igtl::TrackingDataMessage::Pointer trackingData) +{ + std::cerr << "Receiving TDATA data type." << std::endl; + + //------------------------------------------------------------ + // Allocate TrackingData Message Class + int c = trackingData->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = trackingData->GetNumberOfTrackingDataElements(); + for (int i = 0; i < nElements; i ++) + { + igtl::TrackingDataElement::Pointer trackingElement; + trackingData->GetTrackingDataElement(i, trackingElement); + + igtl::Matrix4x4 matrix; + trackingElement->GetMatrix(matrix); + + + std::cerr << "========== Element #" << i << " ==========" << std::endl; + std::cerr << " Name : " << trackingElement->GetName() << std::endl; + std::cerr << " Type : " << (int) trackingElement->GetType() << std::endl; + std::cerr << " Matrix : " << std::endl; + igtl::PrintMatrix(matrix); + std::cerr << "================================" << std::endl; + } + return 1; + } + return 0; +} + +int main(int argc, char* argv[]) { + webSocketClient s; + + if (argc == 1) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << " : IP or host name" << std::endl; + std::cerr << " : Port # (18944 in Slicer default)" << std::endl; + return 1; + } + + const char* hostname = argv[1]; + int port = atoi(argv[2]); + // Create a thread to recevie the message + igtl::TrackingDataMessage::Pointer trackingData; + websocketpp::lib::thread client_thread(websocketpp::lib::bind(&webSocketClient::ConnectToServer, &s, hostname, port)); + + void* data; + int length; + while(1) + { + length = IGTL_HEADER_SIZE; + data = malloc(length); + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + s.Receive(headerMsg->GetPackPointer(), length); + headerMsg->Unpack(); + trackingData = igtl::TrackingDataMessage::New(); + trackingData->SetMessageHeader(headerMsg); + trackingData->AllocatePack(); + length = trackingData->GetPackBodySize(); + s.Receive(trackingData->GetPackBodyPointer(), length); + ReceiveTrackingData(trackingData); + } + return 0; +} diff --git a/openigtlink/repo/Examples/WebSocket/WebSocketServer.cxx b/openigtlink/repo/Examples/WebSocket/WebSocketServer.cxx new file mode 100644 index 0000000..2867b0b --- /dev/null +++ b/openigtlink/repo/Examples/WebSocket/WebSocketServer.cxx @@ -0,0 +1,186 @@ + +#include "igtlWebServerSocket.h" +#include +#include +#include +#include + +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlImageMessage.h" +#include "igtlServerSocket.h" +#include "igtlTrackingDataMessage.h" +#include "igtlMultiThreader.h" + +#include +#include +#include +#include +#include + +/** + * The telemetry server accepts connections and sends a message every second to + * each client containing an integer count. This example can be used as the + * basis for programs that expose a stream of telemetry data for logging, + * dashboards, etc. + * + * This example uses the timer based concurrency method and is self contained + * and singled threaded. Refer to telemetry client for an example of a similar + * telemetry setup using threads rather than timers. + * + * This example also includes an example simple HTTP server that serves a web + * dashboard displaying the count. This simple design is suitable for use + * delivering a small number of files to a small number of clients. It is ideal + * for cases like embedded dashboards that don't want the complexity of an extra + * HTTP server to serve static files. + * + * This design *will* fall over under high traffic or DoS conditions. In such + * cases you are much better off proxying to a real HTTP server for the http + * requests. + */ + +void GetRandomTestMatrix(igtl::Matrix4x4& matrix, float phi, float theta); + + +int PackTrackingData(igtl::TrackingDataMessage::Pointer trackingMsg) +{ + + static float phi0 = 0.0; + static float theta0 = 0.0; + static float phi1 = 0.0; + static float theta1 = 0.0; + static float phi2 = 0.0; + static float theta2 = 0.0; + + igtl::TrackingDataElement::Pointer trackElement0; + trackElement0 = igtl::TrackingDataElement::New(); + trackElement0->SetName("Channel 0"); + trackElement0->SetType(igtl::TrackingDataElement::TYPE_TRACKER); + + igtl::TrackingDataElement::Pointer trackElement1; + trackElement1 = igtl::TrackingDataElement::New(); + trackElement1->SetName("Channel 1"); + trackElement1->SetType(igtl::TrackingDataElement::TYPE_6D); + + igtl::TrackingDataElement::Pointer trackElement2; + trackElement2 = igtl::TrackingDataElement::New(); + trackElement2->SetName("Channel 2"); + trackElement2->SetType(igtl::TrackingDataElement::TYPE_5D); + + trackingMsg->AddTrackingDataElement(trackElement0); + trackingMsg->AddTrackingDataElement(trackElement1); + trackingMsg->AddTrackingDataElement(trackElement2); + + igtl::Matrix4x4 matrix; + igtl::TrackingDataElement::Pointer ptr; + + // Channel 0 + trackingMsg->GetTrackingDataElement(0, ptr); + GetRandomTestMatrix(matrix, phi0, theta0); + ptr->SetMatrix(matrix); + + // Channel 1 + trackingMsg->GetTrackingDataElement(1, ptr); + GetRandomTestMatrix(matrix, phi1, theta1); + ptr->SetMatrix(matrix); + + // Channel 2 + trackingMsg->GetTrackingDataElement(2, ptr); + GetRandomTestMatrix(matrix, phi2, theta2); + ptr->SetMatrix(matrix); + + trackingMsg->Pack(); + + phi0 += 0.1; + phi1 += 0.2; + phi2 += 0.3; + theta0 += 0.2; + theta1 += 0.1; + theta2 += 0.05; + + return 0; +} +//------------------------------------------------------------ +// Function to generate random matrix. +void GetRandomTestMatrix(igtl::Matrix4x4& matrix, float phi, float theta) +{ + float position[3]; + float orientation[4]; + + // random position + position[0] = 50.0 * cos(phi); + position[1] = 50.0 * sin(phi); + position[2] = 50.0 * cos(phi); + phi = phi + 0.2; + + // random orientation + orientation[0]=0.0; + orientation[1]=0.6666666666*cos(theta); + orientation[2]=0.577350269189626; + orientation[3]=0.6666666666*sin(theta); + theta = theta + 0.1; + + //igtl::Matrix4x4 matrix; + igtl::QuaternionToMatrix(orientation, matrix); + + matrix[0][3] = position[0]; + matrix[1][3] = position[1]; + matrix[2][3] = position[2]; + + //igtl::PrintMatrix(matrix); +} + + +int main(int argc, char* argv[]) { + + + std::string docroot; + uint16_t port = 9002; + + if (argc == 1) { + std::cout << "Usage: telemetry_server [documentroot] [port]" << std::endl; + return 1; + } + + if (argc >= 2) { + docroot = std::string(argv[1]); + } + + if (argc >= 3) { + int i = atoi(argv[2]); + if (i <= 0 || i > 65535) { + std::cout << "invalid port" << std::endl; + return 1; + } + + port = uint16_t(i); + } + + if(strcmp(&docroot.back(),"/") != 0) + { + docroot.append("/"); + } + + //s.CreateHTTPServer(docroot, port); // 100 ms interval + webSocketServer s; + s.m_docroot = docroot; + s.port = port; + try + { + websocketpp::lib::thread t(websocketpp::lib::bind(&webSocketServer::CreateHTTPServer, &s, docroot, port)); + while (1) + { + igtl::TrackingDataMessage::Pointer trackingMsg; + trackingMsg = igtl::TrackingDataMessage::New(); + trackingMsg->SetDeviceName("Tracker"); + PackTrackingData(trackingMsg); + s.Send(trackingMsg->GetPackPointer(), trackingMsg->GetPackSize()); + igtl::Sleep(200); + } + t.join(); + } + catch (websocketpp::exception const & e) { + std::cout << e.what() << std::endl; + } + return 0; +} diff --git a/openigtlink/repo/Examples/WebSocket/index.html b/openigtlink/repo/Examples/WebSocket/index.html new file mode 100644 index 0000000..9de1757 --- /dev/null +++ b/openigtlink/repo/Examples/WebSocket/index.html @@ -0,0 +1,100 @@ + + + +WebSocket++ TrackingData Client + + + + + + + +
+
+
+ +
+
+
+ + + diff --git a/openigtlink/repo/LICENSE.txt b/openigtlink/repo/LICENSE.txt new file mode 100644 index 0000000..21047ad --- /dev/null +++ b/openigtlink/repo/LICENSE.txt @@ -0,0 +1,30 @@ +Copyright (c) 2008, Insight Software Consortium + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the Insight Software Consortium nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/openigtlink/repo/OpenIGTLinkConfig.cmake.in b/openigtlink/repo/OpenIGTLinkConfig.cmake.in new file mode 100644 index 0000000..309f5a9 --- /dev/null +++ b/openigtlink/repo/OpenIGTLinkConfig.cmake.in @@ -0,0 +1,60 @@ +#----------------------------------------------------------------------------- +# +# OpenIGTLinkConfig.cmake - OpenIGTLink CMake configuration file for external projects. +# +# This file is configured by OpenIGTLink and used by the UseOpenIGTLink.cmake module +# to load OpenIGTLink's settings for an external project. +@OpenIGTLink_CONFIG_CODE@ + +# The OpenIGTLink include file directories. +SET(OpenIGTLink_INCLUDE_DIRS "@OpenIGTLink_INCLUDE_DIRS_CONFIG@") + +# The OpenIGTLink library directories. +SET(OpenIGTLink_LIBRARY_DIRS "@OpenIGTLink_LIBRARY_DIRS_CONFIG@") + +# The C and C++ flags added by OpenIGTLink to the cmake-configured flags. +SET(OpenIGTLink_REQUIRED_C_FLAGS "@OpenIGTLink_REQUIRED_C_FLAGS@") +SET(OpenIGTLink_REQUIRED_CXX_FLAGS "@OpenIGTLink_REQUIRED_CXX_FLAGS@") +SET(OpenIGTLink_REQUIRED_LINK_FLAGS "@OpenIGTLink_REQUIRED_LINK_FLAGS@") + +# The OpenIGTLink Library version number +SET(OpenIGTLink_VERSION_MAJOR "@OpenIGTLink_VERSION_MAJOR@") +SET(OpenIGTLink_VERSION_MINOR "@OpenIGTLink_VERSION_MINOR@") +SET(OpenIGTLink_VERSION_PATCH "@OpenIGTLink_VERSION_PATCH@") + +# The OpenIGTLink Protocol version number +SET(OpenIGTLink_PROTOCOL_VERSION "@OpenIGTLink_PROTOCOL_VERSION@") + +# The location of the UseOpenIGTLink.cmake file. +SET(OpenIGTLink_USE_FILE "@OpenIGTLink_USE_FILE@") + +# The build settings file. +SET(OpenIGTLink_BUILD_SETTINGS_FILE "@OpenIGTLink_BUILD_SETTINGS_FILE@") + +# Whether OpenIGTLink was built with shared libraries. +SET(OpenIGTLink_BUILD_SHARED "@BUILD_SHARED_LIBS@") + +# Whether OpenIGTLink was built with Tcl wrapping support. +SET(OpenIGTLink_CSWIG_TCL "@OpenIGTLink_CSWIG_TCL@") +SET(OpenIGTLink_CSWIG_PYTHON "@OpenIGTLink_CSWIG_PYTHON@") +SET(OpenIGTLink_CSWIG_JAVA "@OpenIGTLink_CSWIG_JAVA@") + +# Whether OpenIGTLink was built with video streaming library support +SET(OpenIGTLink_USE_H264 @OpenIGTLink_USE_H264@) +SET(OpenIGTLink_USE_VP9 @OpenIGTLink_USE_VP9@) +SET(OpenIGTLink_USE_X265 @OpenIGTLink_USE_X265@) +SET(OpenIGTLink_USE_OpenHEVC @OpenIGTLink_USE_OpenHEVC@) +SET(OpenIGTLink_USE_AV1 @OpenIGTLink_USE_AV1@) +SET(OpenIGTLink_ENABLE_VIDEOSTREAMING @OpenIGTLink_ENABLE_VIDEOSTREAMING@) +SET(OpenIGTLink_USE_WEBSOCKET @OpenIGTLink_USE_WEBSOCKET@) + +# Path to CableSwig configuration used by OpenIGTLink. +SET(OpenIGTLink_CableSwig_DIR "@OpenIGTLink_CableSwig_DIR_CONFIG@") + +# A list of all libraries for OpenIGTLink. Those listed here should +# automatically pull in their dependencies. +SET(OpenIGTLink_LIBRARIES OpenIGTLink) + +# The OpenIGTLink library targets. +SET(OpenIGTLink_LIBRARY_TARGETS_FILE "@OpenIGTLink_LIBRARY_TARGETS_FILE@") +include(${OpenIGTLink_LIBRARY_TARGETS_FILE}) diff --git a/openigtlink/repo/README.md b/openigtlink/repo/README.md new file mode 100644 index 0000000..cec1750 --- /dev/null +++ b/openigtlink/repo/README.md @@ -0,0 +1,45 @@ +The OpenIGTLink Library +======================= + +The OpenIGTLink Library is a C/C++ implementation of +[The OpenIGTLink Protocol](Documents/Protocol/index.md). + +OpenIGTLink is an open-source network communication interface specifically +designed for image-guided interventions. It aims to provide a plug-and-play +unified real-time communications (URTC) in operating rooms (ORs) for image-guided +interventions, where imagers, sensors, surgical robots,and computers from +different vendors work cooperatively. This URTC will ensure the seamless data +flow among those components and enable a closed-loop process of planning, control, +delivery, and feedback. The specification of OpenIGTLink is open, and can be +used without any license fee; hence OpenIGTLink is suitable for both industrial +and academic developers. + +The latest information of the protocol is available at [OpenIGTLink Web Page](http://openigtlink.org/). +The definition of the protocol used in the current version (one in this git repository) +can be found in [Protocol Documentation](Documents/Protocol/index.md) + +Build Status +------------ +* Linux/Mac(Github Action): [![Build Status](https://github.com/openigtlink/OpenIGTLink/actions/workflows/cmake.yml/badge.svg)](https://github.com/openigtlink/OpenIGTLink/actions?workflow=cmake) +* Windows: [![Build status](https://ci.appveyor.com/api/projects/status/beo8cej2nxu55ex0?svg=true)](https://ci.appveyor.com/project/openigtlink/openigtlink) + +Build Instruction +----------------- + +Please see [BUILD Instruction](BUILD.md). + +How to Contribute? +------------------ + +If you find any issues or have feature request, please feel free to post +to [Issues](https://github.com/openigtlink/OpenIGTLink/issues). + +The OpenIGTLink community is adapted to the collaborative development model on GitHub. +[GitHub's instruction](https://help.github.com/articles/about-collaborative-development-models/) +provides a nice overview of collaborative development models and workflows. + +License +------- +The code is distributed as open source under The 3-Clause BSD License. Please refer to the license terms +available at [Open Source Initiative Page](https://opensource.org/licenses/BSD-3-Clause) or +[LICENSE.txt](LICENSE.txt) included in the source repository. diff --git a/openigtlink/repo/Source/CMakeLists.txt b/openigtlink/repo/Source/CMakeLists.txt new file mode 100644 index 0000000..d08da4d --- /dev/null +++ b/openigtlink/repo/Source/CMakeLists.txt @@ -0,0 +1,288 @@ +# Build library dependency list +# Note: this part should be moved to OpenIGTLinkConfigPlatform.cmake +IF(WIN32) + # for Windows + LIST(APPEND LINK_LIBS + ws2_32 + wsock32 + ) + #For debug under win32 system, the run time check mode should be set to /RTCu for multithreading purpose + STRING(REPLACE "/RTC1" "/RTCu" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + SET(OpenIGTLink_REQUIRED_CXX_FLAGS ${OpenIGTLink_REQUIRED_CXX_FLAGS}) +ELSE() + # for POSIX-compatible OSs + LIST(APPEND LINK_LIBS + m + pthread + ) + IF(OpenIGTLink_PLATFORM_QNX) + LIST(APPEND LINK_LIBS + c + socket + ) + ENDIF() + IF(OpenIGTLink_PLATFORM_SUNOS) + LIST(APPEND LINK_LIBS + ${OpenIGTLink_STD_LINK_LIBRARIES} + ) + ENDIF() +ENDIF() + +#----------------------------------------------------------------------------- +# Include directories +SET(OpenIGTLink_INCLUDE_DIRS + ${OpenIGTLink_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/igtlutil + ${CMAKE_CURRENT_BINARY_DIR}/igtlutil + ) + +SET(OpenIGTLink_SOURCES + igtlutil/igtl_header.c + igtlutil/igtl_image.c + igtlutil/igtl_transform.c + igtlutil/igtl_status.c + igtlutil/igtl_util.c + igtlutil/igtl_position.c + igtlutil/igtl_capability.c + igtlClientSocket.cxx + igtlCapabilityMessage.cxx + igtlConditionVariable.cxx + igtlFastMutexLock.cxx + igtlImageMessage.cxx + igtlImageMessage2.cxx + igtlLightObject.cxx + igtlMath.cxx + igtlMessageBase.cxx + igtlMessageFactory.cxx + igtlMultiThreader.cxx + igtlMutexLock.cxx + igtlOSUtil.cxx + igtlObject.cxx + igtlObjectFactoryBase.cxx + igtlPositionMessage.cxx + igtlServerSocket.cxx + igtlSessionManager.cxx + igtlSimpleFastMutexLock.cxx + igtlSocket.cxx + igtlStatusMessage.cxx + igtlTimeStamp.cxx + igtlTransformMessage.cxx + ) + +Set(OpenIGTLink_INCLUDE_FILES + igtlutil/igtl_header.h + igtlutil/igtl_image.h + igtlutil/igtl_position.h + igtlutil/igtl_transform.h + igtlutil/igtl_types.h + igtlutil/igtl_util.h + igtlutil/igtl_capability.h + igtlutil/igtl_win32header.h + igtlMessageHandler.h + igtlMessageHandlerMacro.h + igtlCapabilityMessage.h + igtlClientSocket.h + igtlConditionVariable.h + igtlCreateObjectFunction.h + igtlFastMutexLock.h + igtlImageMessage.h + igtlImageMessage2.h + igtlLightObject.h + igtlMacro.h + igtlMath.h + igtlMessageBase.h + igtlMessageFactory.h + igtlMessageHeader.h + igtlMultiThreader.h + igtlMutexLock.h + igtlObjectFactory.h + igtlOSUtil.h + igtlObject.h + igtlObjectFactoryBase.h + igtlPositionMessage.h + igtlServerSocket.h + igtlSessionManager.h + igtlSimpleFastMutexLock.h + igtlSmartPointer.h + igtlSocket.h + igtlStatusMessage.h + igtlTimeStamp.h + igtlTransformMessage.h + igtlTypes.h + igtlWin32Header.h + igtlWindows.h + igtlCommon.h +) + +# Add support for OpenIGTLink version 2 +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "1") + LIST(APPEND OpenIGTLink_SOURCES + igtlutil/igtl_colortable.c + igtlutil/igtl_imgmeta.c + igtlutil/igtl_lbmeta.c + igtlutil/igtl_point.c + igtlutil/igtl_tdata.c + igtlutil/igtl_qtdata.c + igtlutil/igtl_trajectory.c + igtlutil/igtl_unit.c + igtlutil/igtl_sensor.c + igtlutil/igtl_string.c + igtlutil/igtl_ndarray.c + igtlutil/igtl_bind.c + igtlutil/igtl_qtrans.c + igtlutil/igtl_polydata.c + igtlColorTableMessage.cxx + igtlImageMetaMessage.cxx + igtlLabelMetaMessage.cxx + igtlPointMessage.cxx + igtlTrackingDataMessage.cxx + igtlPolyDataMessage.cxx + igtlQuaternionTrackingDataMessage.cxx + igtlTrajectoryMessage.cxx + igtlStringMessage.cxx + igtlUnit.cxx + igtlSensorMessage.cxx + igtlBindMessage.cxx + igtlNDArrayMessage.cxx + ) + LIST(APPEND OpenIGTLink_INCLUDE_FILES + igtlutil/igtl_colortable.h + igtlutil/igtl_imgmeta.h + igtlutil/igtl_lbmeta.h + igtlutil/igtl_point.h + igtlutil/igtl_tdata.h + igtlutil/igtl_qtdata.h + igtlutil/igtl_trajectory.h + igtlutil/igtl_unit.h + igtlutil/igtl_sensor.h + igtlutil/igtl_string.h + igtlutil/igtl_ndarray.h + igtlutil/igtl_bind.h + igtlutil/igtl_qtrans.h + igtlutil/igtl_polydata.h + igtlColorTableMessage.h + igtlImageMetaMessage.h + igtlLabelMetaMessage.h + igtlPointMessage.h + igtlTrackingDataMessage.h + igtlPolyDataMessage.h + igtlQuaternionTrackingDataMessage.h + igtlTrajectoryMessage.h + igtlStringMessage.h + igtlUnit.h + igtlSensorMessage.h + igtlBindMessage.h + igtlNDArrayMessage.h + ) +ENDIF() + +# Add support for OpenIGTLink version 3 +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "2") + LIST(APPEND OpenIGTLink_SOURCES + igtlCommandMessage.cxx + igtlQueryMessage.cxx + igtlutil/igtl_command.c + igtlutil/igtl_query.c + igtlMessageRTPWrapper.cxx + igtlGeneralSocket.cxx + igtlUDPClientSocket.cxx + igtlUDPServerSocket.cxx + ) + LIST(APPEND OpenIGTLink_INCLUDE_FILES + igtlCommandMessage.h + igtlQueryMessage.h + igtlutil/igtl_command.h + igtlutil/igtl_query.h + igtlMessageRTPWrapper.h + igtlGeneralSocket.h + igtlUDPClientSocket.h + igtlUDPServerSocket.h + ) +ENDIF() + +IF (NOT (${CMAKE_VERSION} VERSION_LESS 3.4)) + IF(OpenIGTLink_ENABLE_VIDEOSTREAMING) + INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/VideoStreaming/igtlVideoStreaming.cmake) + ENDIF() + + #----------------------------------------------------------------------------- + # Configure WebSocket + # Create the link to the WebSocket libraries + IF(OpenIGTLink_USE_WEBSOCKET) + FIND_PACKAGE(websocketpp REQUIRED) + INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/WebSocket/UseWebSocket.cmake) + # Copy the UseWebSocket.cmake file to the binary tree for setting up websocket build environment. + CONFIGURE_FILE(${OpenIGTLink_SOURCE_DIR}/Source/WebSocket/UseWebSocket.cmake + ${OpenIGTLink_BINARY_DIR}/UseWebSocket.cmake COPYONLY IMMEDIATE) + LIST(APPEND OpenIGTLink_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/WebSocket/igtlWebServerSocket.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/WebSocket/igtlWebClientSocket.cxx + ) + + LIST(APPEND OpenIGTLink_INCLUDE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/WebSocket/igtlWebServerSocket.h + ${CMAKE_CURRENT_SOURCE_DIR}/WebSocket/igtlWebClientSocket.h + ) + LIST(APPEND OpenIGTLink_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/WebSocket + ${WEBSOCKETPP_INCLUDE_DIR} + ) + ENDIF() +ELSE() + message(WARNING "CMake >= 3.4.0 recommended to enable the the video stream library and websocket option") +ENDIF() +#----------------------------------------------------------------------------- +# Create the library +IF(MSVC OR ${CMAKE_GENERATOR} MATCHES "Xcode") + ADD_LIBRARY(OpenIGTLink ${OpenIGTLink_SOURCES} ${OpenIGTLink_INCLUDE_FILES}) +ELSE() + ADD_LIBRARY(OpenIGTLink ${OpenIGTLink_SOURCES}) +ENDIF() +foreach(p IN LISTS OpenIGTLink_INCLUDE_DIRS) + target_include_directories(OpenIGTLink PUBLIC $) +endforeach() +target_include_directories(OpenIGTLink PUBLIC $) + +LIST(APPEND OpenIGTLink_DEPENDENCIES igtlutil) +IF (NOT (${CMAKE_VERSION} VERSION_LESS 3.4)) + IF(OpenIGTLink_ENABLE_VIDEOSTREAMING) + IF(OpenIGTLink_USE_H264 AND (NOT OpenH264_FOUND)) + add_dependencies(OpenIGTLink OpenH264) + ENDIF() + IF(OpenIGTLink_USE_VP9 AND (NOT VP9_FOUND)) + add_dependencies(OpenIGTLink VP9) + ENDIF() + IF(OpenIGTLink_USE_X265 AND (NOT X265_FOUND)) + add_dependencies(OpenIGTLink X265) + ENDIF() + IF(OpenIGTLink_USE_OpenHEVC AND (NOT OpenHEVC_FOUND)) + add_dependencies(OpenIGTLink OpenHEVC) + ENDIF() + IF(OpenIGTLink_USE_AV1 AND (NOT AV1_FOUND)) + add_dependencies(OpenIGTLink AV1) + ENDIF() + ENDIF() +ENDIF() + +TARGET_LINK_LIBRARIES(OpenIGTLink PUBLIC ${LINK_LIBS}) + +IF(MSVC) + target_compile_options(OpenIGTLink PRIVATE /MP) +ENDIF() + +SET_TARGET_PROPERTIES(OpenIGTLink PROPERTIES + VERSION ${OpenIGTLink_VERSION_MAJOR}.${OpenIGTLink_VERSION_MINOR}.${OpenIGTLink_VERSION_PATCH} + SOVERSION ${OpenIGTLink_VERSION_MAJOR} + ) + +INSTALL(FILES ${OpenIGTLink_INCLUDE_FILES} + DESTINATION ${OpenIGTLink_INSTALL_INCLUDE_DIR} + COMPONENT Development) +INSTALL(TARGETS OpenIGTLink EXPORT OpenIGTLink + RUNTIME DESTINATION ${OpenIGTLink_INSTALL_BIN_DIR} COMPONENT RuntimeLibraries + LIBRARY DESTINATION ${OpenIGTLink_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries + ARCHIVE DESTINATION ${OpenIGTLink_INSTALL_LIB_DIR} COMPONENT Development) + +SET(OpenIGTLink_INCLUDE_DIRS ${OpenIGTLink_INCLUDE_DIRS} PARENT_SCOPE) diff --git a/openigtlink/repo/Source/VideoStreaming/igtlAV1Decoder.cxx b/openigtlink/repo/Source/VideoStreaming/igtlAV1Decoder.cxx new file mode 100644 index 0000000..15db2a5 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlAV1Decoder.cxx @@ -0,0 +1,115 @@ +/*========================================================================= + + Program: AOMEncoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlAV1Decoder.h" + +// AV1 includes +#include "aomdx.h" +namespace igtl { + +static const AomInterfaceDecoder AV1StaticDecoder[] = { { &aom_codec_av1_dx } }; + +int igtlAV1Decoder::aom_img_plane_width(const aom_image_t *img, int plane) { + if (plane > 0 && img->x_chroma_shift > 0) + return (img->d_w + 1) >> img->x_chroma_shift; + else + return img->d_w; +} + +int igtlAV1Decoder::aom_img_plane_height(const aom_image_t *img, int plane) { + if (plane > 0 && img->y_chroma_shift > 0) + return (img->d_h + 1) >> img->y_chroma_shift; + else + return img->d_h; +} + + +igtlAV1Decoder::igtlAV1Decoder() +{ + decoder = &AV1StaticDecoder[0]; + aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0); + this->deviceName = ""; +} + +igtlAV1Decoder::~igtlAV1Decoder() +{ + aom_codec_destroy(&codec); + decoder = NULL; +} + +int igtlAV1Decoder::DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* pDecodedPic) +{ + if(videoMessage->GetBitStreamSize()) + { + igtl_int32 iWidth = videoMessage->GetWidth(); + igtl_int32 iHeight = videoMessage->GetHeight(); + igtl_uint64 iStreamSize = videoMessage->GetBitStreamSize(); + pDecodedPic->picWidth = iWidth; + pDecodedPic->picHeight = iHeight; + pDecodedPic->data[1]= pDecodedPic->data[0] + iWidth*iHeight; + pDecodedPic->data[2]= pDecodedPic->data[1] + iWidth*iHeight/4; + pDecodedPic->stride[0] = iWidth; + pDecodedPic->stride[1] = pDecodedPic->stride[2] = iWidth>>1; + pDecodedPic->stride[3] = 0; + igtl_uint32 dimensions[2] = {static_cast(iWidth), static_cast(iHeight)}; + return this->DecodeBitStreamIntoFrame(videoMessage->GetPackFragmentPointer(2), pDecodedPic->data[0], dimensions, iStreamSize); + } + return -1; +} + +void igtlAV1Decoder::ComposeByteSteam(igtl_uint8** inputData, int dimension[2], int iStride[3], igtl_uint8 *outputFrame) +{ + int plane; + int dimensionW [3] = {dimension[0],dimension[0]/2,dimension[0]/2}; + int dimensionH [3] = {dimension[1],dimension[1]/2,dimension[1]/2}; + int shift = 0; + for (plane = 0; plane < 3; ++plane) + { + const unsigned char *buf = inputData[plane]; + const int stride = iStride[plane]; + int w = dimensionW[plane]; + int h = dimensionH[plane]; + int y; + for (y = 0; y < h; ++y) + { + memcpy(outputFrame+shift + w*y, buf, w); + buf += stride; + } + shift += w*h; + } +} + + +int igtlAV1Decoder::DecodeBitStreamIntoFrame(unsigned char* bitstream, igtl_uint8* outputFrame, igtl_uint32 dimensions[2], igtl_uint64& iStreamSize) +{ + if (!aom_codec_decode(&codec, bitstream, (unsigned int)iStreamSize, NULL)) + { + iter = NULL; + if ((outputImage = aom_codec_get_frame(&codec, &iter)) != NULL) + { + int stride[3] = { outputImage->stride[0], outputImage->stride[1], outputImage->stride[2] }; + int convertedDimensions[2] = { aom_img_plane_width(outputImage, 0) * + ((outputImage->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1), aom_img_plane_height(outputImage, 0) }; + ComposeByteSteam(outputImage->planes, convertedDimensions, stride, outputFrame); + return 2; + } + } + else + { + aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0); + std::cerr << "decode failed" << std::endl; + } + return -1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/VideoStreaming/igtlAV1Decoder.h b/openigtlink/repo/Source/VideoStreaming/igtlAV1Decoder.h new file mode 100644 index 0000000..a6ce62b --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlAV1Decoder.h @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: AOMDecoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#ifndef __igtlAV1Decoder_h +#define __igtlAV1Decoder_h + +// OpenIGTLink includes +#include "igtlCodecCommonClasses.h" + +// AV1 includes +#include "aom_decoder.h" + +namespace igtl { + +#ifdef __cplusplus +extern "C" { +#endif + typedef struct AomInterfaceDecoder { + aom_codec_iface_t *(*const codec_interface)(); + } AomInterfaceDecoder; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#define NO_DELAY_DECODING +class IGTLCommon_EXPORT igtlAV1Decoder : public GenericDecoder +{ +public: + igtlTypeMacro(igtlAV1Decoder, GenericDecoder); + igtlNewMacro(igtlAV1Decoder); + + igtlAV1Decoder(); + ~igtlAV1Decoder(); + + int DecodeBitStreamIntoFrame(unsigned char* bitStream,igtl_uint8* outputFrame, igtl_uint32 iDimensions[2], igtl_uint64 &iStreamSize) override; + + int DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* pDecodedPic) override; + +private: + void ComposeByteSteam(igtl_uint8** inputData, int dimension[2], int iStride[2], igtl_uint8 *outputFrame) override; + + const AomInterfaceDecoder* decoder; + + int aom_img_plane_width(const aom_image_t *img, int plane); + + int aom_img_plane_height(const aom_image_t *img, int plane); + + aom_codec_ctx_t codec; + + aom_image_t* outputImage; + + aom_codec_iter_t iter; + +}; + + +}// Namepace igtl +#endif \ No newline at end of file diff --git a/openigtlink/repo/Source/VideoStreaming/igtlAV1Encoder.cxx b/openigtlink/repo/Source/VideoStreaming/igtlAV1Encoder.cxx new file mode 100644 index 0000000..e352b2f --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlAV1Encoder.cxx @@ -0,0 +1,291 @@ +/*========================================================================= + + Program: igtlAV1Encoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlAV1Encoder.h" + +// AV1 includes +#include "aomcx.h" + +namespace igtl { + +static const AomInterfaceEncoder AV1StaticEncoder[] = {{&aom_codec_av1_cx}}; + +void igtlAV1Encoder::error_output(aom_codec_ctx_t *ctx, const char *s) { + const char *detail = aom_codec_error_detail(ctx); + + printf("%s: %s\n", s, aom_codec_error(ctx)); + if (detail) printf(" %s\n", detail); + exit(EXIT_FAILURE); +} + + +// TODO(dkovalev): move this function to aom_image.{c, h}, so it will be part +// of aom_image_t support, this section will be removed when it is moved to aom_image +int igtlAV1Encoder::aom_img_plane_width(const aom_image_t *img, int plane) { + if (plane > 0 && img->x_chroma_shift > 0) + return (img->d_w + 1) >> img->x_chroma_shift; + else + return img->d_w; +} + +int igtlAV1Encoder::aom_img_plane_height(const aom_image_t *img, int plane) { + if (plane > 0 && img->y_chroma_shift > 0) + return (img->d_h + 1) >> img->y_chroma_shift; + else + return img->d_h; +} + + +igtlAV1Encoder::igtlAV1Encoder(char *configFile):GenericEncoder() +{ + this->encoder = &AV1StaticEncoder[0]; + codec = new aom_codec_ctx_t(); + encodedBuf = new aom_fixed_buf_t(); + inputImage = new aom_image_t(); + isLossLessLink = true; + codecSpeed = 0; + FillSpecificParameters (); +} + +igtlAV1Encoder::~igtlAV1Encoder() +{ + aom_codec_encode(codec, NULL, -1, 1, 0); //Flush the codec + aom_codec_destroy(codec); + if (inputImage) + { + delete inputImage; + } + if(this->encoder) + { + this->encoder = NULL; + } +} + +int igtlAV1Encoder::FillSpecificParameters() { + if (aom_codec_enc_config_default(encoder->codec_interface(), &cfg, 0)) + { + error_output(codec, "Failed to get default codec config."); + return -1; + } + cfg.g_error_resilient = true; + aom_codec_enc_init(codec, encoder->codec_interface(), &cfg, 0); + if(this->SetSpeed(FastestSpeed)!=0) + { + error_output(codec, "Failed to set the speed to be the fastest."); + return -1; + } + return 0; +} + +int igtlAV1Encoder::SetRCMode(int value) +{ + this->cfg.rc_end_usage = (aom_rc_mode) value; + if(aom_codec_enc_config_set(codec, &this->cfg)) + { + error_output(codec, "Failed to set RC mode"); + return -1; + } + return 0; +} + +int igtlAV1Encoder::SetKeyFrameDistance(int frameNum) +{ + this->cfg.kf_max_dist = frameNum; + this->cfg.kf_min_dist = frameNum; + if(aom_codec_enc_config_set(codec, &this->cfg)) + { + error_output(codec, "Failed to key frame distance"); + return -1; + } + return 0; +} + + +int igtlAV1Encoder::SetRCTargetBitRate(unsigned int bitRate) +{ + //// The bit rate in AOM is in Kilo + int bitRateInKilo = bitRate/1000; + this->cfg.rc_target_bitrate = bitRateInKilo; + if (aom_codec_enc_config_set(codec, &this->cfg)) + { + error_output(codec, "Failed to set target bit rate"); + return -1; + } + this->initializationDone = true; + return 0; +} + +int igtlAV1Encoder::SetQP(int maxQP, int minQP) +{ + this->cfg.rc_max_quantizer = maxQP<63?maxQP:63; + this->cfg.rc_min_quantizer = minQP>0?minQP:0; + this->cfg.rc_end_usage = AOM_Q; + if (aom_codec_enc_config_set(codec, &this->cfg)) + { + error_output(codec, "Failed to set QP"); + return -1; + } + this->initializationDone = true; + return 0; +} + +int igtlAV1Encoder::SetLosslessLink(bool linkMethod) +{ + this->isLossLessLink = linkMethod; + if (aom_codec_control_(codec, AV1E_SET_LOSSLESS, linkMethod)) + { + error_output(codec, "Failed to set lossless mode"); + return -1; + } + else + { + this->cfg.rc_end_usage = AOM_VBR; + return 0; + } +} + +int igtlAV1Encoder::SetSpeed(int speed) +{ + this->codecSpeed = speed; + if (speed>=SlowestSpeed && speed<=FastestSpeed) + { + aom_codec_control(codec, AOME_SET_CPUUSED, speed); + return 0; + } + return -1; +} + +int igtlAV1Encoder::InitializeEncoder() +{ + cfg.g_lag_in_frames = 0; + cfg.g_w = this->GetPicWidth(); + cfg.g_h = this->GetPicHeight(); + aom_img_alloc(inputImage, AOM_IMG_FMT_I420, cfg.g_w, + cfg.g_h, 1); + if (aom_codec_enc_init(codec, encoder->codec_interface(), &cfg, 0)) + { + error_output(codec, "Failed to initialize encoder"); + return -1; + } + + if (aom_codec_control_(codec, AV1E_SET_LOSSLESS, this->GetLosslessLink())) + { + error_output(codec, "Failed to set lossless mode"); + return -1; + } + + if (codecSpeed >= SlowestSpeed && codecSpeed <= FastestSpeed) + { + if (aom_codec_control(codec, AOME_SET_CPUUSED, codecSpeed)) + { + error_output(codec, "Failed to set Speed"); + return -1; + } + } + this->initializationDone = true; + return 0; +} + +int igtlAV1Encoder::SetPicWidthAndHeight(unsigned int width, unsigned int height) +{ + this->picWidth = width; + this->picHeight = height; + if(this->picHeight != this->cfg.g_h || this->picWidth != this->cfg.g_w ) + { + bool iRet = this->InitializeEncoder(); + if(iRet==0) + { + return 0; + } + } + return 0; +} + +int igtlAV1Encoder::ConvertToLocalImageFormat(SourcePicture* pSrcPic) +{ + if (pSrcPic->picWidth != this->cfg.g_w || pSrcPic->picHeight != this->cfg.g_h) + { + this->SetPicWidthAndHeight(pSrcPic->picWidth,pSrcPic->picHeight); + this->InitializeEncoder(); + } + int plane; + for (plane = 0; plane < 3; ++plane) + { + unsigned char *buf = inputImage->planes[plane]; + const int w = aom_img_plane_width(inputImage, plane) * + ((inputImage->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); + const int h = aom_img_plane_height(inputImage, plane); + memcpy(buf, pSrcPic->data[plane], w*h); + } + + return 1; +} + +int igtlAV1Encoder::EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage) +{ + int iSourceWidth = pSrcPic->picWidth; + int iSourceHeight = pSrcPic->picHeight; + if (iSourceWidth != this->cfg.g_w || iSourceHeight != this->cfg.g_h) + { + this->SetPicWidthAndHeight(iSourceWidth,iSourceHeight); + } + if (this->initializationDone == true) + { + static igtl_uint32 messageID = 6; + messageID ++; + this->ConvertToLocalImageFormat(pSrcPic); + const aom_codec_err_t res2 = aom_codec_encode(codec, inputImage, messageID, 1, 0); + if (res2 != AOM_CODEC_OK) + { + error_output(codec, "Failed to encode frame"); + return -1; + } + iter = NULL; + while ((pkt = aom_codec_get_cx_data(codec, &iter)) != NULL) + { + if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) + { + if((pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0) + { + encodedFrameType = FrameTypeKey; + } + else + { + // To do, assign other frame type too. + encodedFrameType = FrameTypeUnKnown; + } + videoMessage->SetBitStreamSize(pkt->data.frame.sz); + videoMessage->AllocateScalars(); + videoMessage->SetCodecType(IGTL_VIDEO_CODEC_NAME_AV1); + videoMessage->SetEndian(igtl_is_little_endian() == true ? 2 : 1); //little endian is 2 big endian is 1 + videoMessage->SetWidth(pSrcPic->picWidth); + videoMessage->SetHeight(pSrcPic->picHeight); + if (isGrayImage) + { + encodedFrameType = encodedFrameType << 8; + } + videoMessage->SetFrameType(encodedFrameType); + memcpy(videoMessage->GetPackFragmentPointer(2), pkt->data.frame.buf, pkt->data.frame.sz); + videoMessage->Pack(); + } + } + if (videoMessage->GetBitStreamSize()) + { + return 0; + } + return -1; + } + return -1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/VideoStreaming/igtlAV1Encoder.h b/openigtlink/repo/Source/VideoStreaming/igtlAV1Encoder.h new file mode 100644 index 0000000..b3bbae1 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlAV1Encoder.h @@ -0,0 +1,123 @@ +/*========================================================================= + + Program: OpenIGTLink + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlAV1Encoder_h +#define __igtlAV1Encoder_h + +// OpenIGTLink includes +#include "igtlCodecCommonClasses.h" + +// AV1 includes +#include "aom_encoder.h" + +namespace igtl { + +#ifdef __cplusplus +extern "C" { +#endif + typedef struct AomInterfaceEncoder { + aom_codec_iface_t *(*const codec_interface)(); + } AomInterfaceEncoder; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +class IGTLCommon_EXPORT igtlAV1Encoder : public GenericEncoder +{ +public: + igtlTypeMacro(igtlAV1Encoder, GenericEncoder); + igtlNewMacro(igtlAV1Encoder); + + igtlAV1Encoder(char * configFile = NULL); + ~igtlAV1Encoder(); + + int FillSpecificParameters() override; + + /** + Parse the configuration file to initialize the encoder and server. + */ + int InitializeEncoder() override; + + int ConvertToLocalImageFormat(SourcePicture* pSrcPic) override; + + /** + Encode a frame, for performance issue, before encode the frame, make sure the frame pointer is updated with a new frame. + Otherwize, the old frame will be encoded. + */ + int EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage = false ) override; + + int SetPicWidthAndHeight(unsigned int width, unsigned int height) override; + + unsigned int GetPicWidth() override {return this->picWidth;}; + + unsigned int GetPicHeight() override {return this->picHeight;}; + + int SetRCMode(int value) override; + + int SetKeyFrameDistance(int frameNum) override; + + int SetQP(int maxQP, int minQP) override; + + int SetRCTargetBitRate(unsigned int bitRate) override; + + int SetLosslessLink(bool linkMethod) override; + + /* Speed value Should be set between -8 to 8 for AV1. + Values greater than 0 will increase encoder speed at the expense of quality. + negative value is not used.*/ + enum + { + SlowestSpeed = 0, + FastestSpeed = 8 + }; + int SetSpeed(int speed) override; + + /*!\brief deadline parameter analogous to VPx REALTIME mode. */ + //#define VPX_DL_REALTIME (1) + /*!\brief deadline parameter analogous to VPx GOOD QUALITY mode. */ + //#define VPX_DL_GOOD_QUALITY (1000000) + /*!\brief deadline parameter analogous to VPx BEST QUALITY mode. */ + //#define VPX_DL_BEST_QUALITY (0) + /*!\brief Encode a frame*/ + int SetDeadlineMode(unsigned long mode); + +private: + + const AomInterfaceEncoder *encoder; + + void error_output(aom_codec_ctx_t *ctx, const char *s); + + int aom_img_plane_width(const aom_image_t *img, int plane); + + int aom_img_plane_height(const aom_image_t *img, int plane); + + aom_codec_enc_cfg_t cfg; + + aom_codec_ctx_t* codec; + + aom_image_t* inputImage; + + aom_codec_iter_t iter; + + const aom_fixed_buf_t *encodedBuf; + + const aom_codec_cx_pkt_t *pkt; + + unsigned long deadlineMode; + +}; + + +} // namespace igtl +#endif diff --git a/openigtlink/repo/Source/VideoStreaming/igtlCodecCommonClasses.cxx b/openigtlink/repo/Source/VideoStreaming/igtlCodecCommonClasses.cxx new file mode 100644 index 0000000..b4aa57c --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlCodecCommonClasses.cxx @@ -0,0 +1,322 @@ +// +// CodecCommonClasses.cpp +// OpenIGTLink +// +// Created by Longquan Chen on 3/30/17. +// +// + +#include "igtlCodecCommonClasses.h" + +namespace igtl { + +ReadConfigFile::ReadConfigFile() +: configFile(NULL) +, configFileName ("") +, lineNums(0) { +} + +ReadConfigFile::ReadConfigFile (const char* fileName) +: configFile (0) +, configFileName (fileName) +, lineNums (0) { + if (strlen (fileName) > 0) { + configFile = fopen (fileName, "r"); + } +} + +ReadConfigFile::ReadConfigFile (const std::string& fileName) +: configFile (0) +, configFileName (fileName.c_str()) +, lineNums (0) { + if (strlen (fileName.c_str()) > 0) { + configFile = fopen (fileName.c_str(), "r"); + } +} + +ReadConfigFile::~ReadConfigFile() { + if (configFile) { + fclose (configFile); + configFile = NULL; + } +} + +void ReadConfigFile::OpenFile (const char* strFile) { + if (strFile != NULL && strlen (strFile) > 0) { // confirmed_safe_unsafe_usage + configFileName = strFile; + configFile = fopen (strFile, "r"); + } +} + +long ReadConfigFile::ReadLine (std::string* var, const int valSize/* = 4*/) { + if (configFile == NULL || var == NULL || valSize <= 1) + return 0; + + std::string* strTags = &var[0]; + int nTagNum = 0, n = 0; + bool bCommentFlag = false; + + while (n < valSize) { + var[n] = ""; + ++ n; + } + do { + const char singleChar = (char)fgetc (configFile); + + if (singleChar == '\n' || feof (configFile)) { + ++ lineNums; + break; + } + if (singleChar == '#') + bCommentFlag = true; + if (!bCommentFlag) { + if (singleChar == '\t' || singleChar == ' ') { + if (nTagNum >= valSize-1) + break; + if (! (*strTags).empty()) { + ++ nTagNum; + strTags = &var[nTagNum]; + } + } else + *strTags += singleChar; + } + + } while (true); + + return 1 + nTagNum; +} + +const bool ReadConfigFile::EndOfFile() { + if (configFile == NULL) + return true; + return feof (configFile) ? true : false; +} + +const int ReadConfigFile::GetLines() { + return lineNums; +} + +const bool ReadConfigFile::ExistFile() { + return (configFile != NULL); +} + +const std::string& ReadConfigFile::GetFileName() { + return configFileName; +} + +void GenericDecoder::Write2File (FILE* pFp, unsigned char* pData[], igtl_uint32 iDimensions[], igtl_uint32 iStride[]) +{ + igtl_uint32 i; + unsigned char* pPtr = NULL; + igtl_uint32 iWidth = iDimensions[0]; + igtl_uint32 iHeight = iDimensions[1]; + pPtr = pData[0]; + for (i = 0; i < iHeight; i++) { + fwrite (pPtr, 1, iWidth, pFp); + pPtr += iStride[0]; + } + + iHeight = iHeight / 2; + iWidth = iWidth / 2; + pPtr = pData[1]; + for (i = 0; i < iHeight; i++) { + fwrite (pPtr, 1, iWidth, pFp); + pPtr += iStride[1]; + } + + pPtr = pData[2]; + for (i = 0; i < iHeight; i++) { + fwrite (pPtr, 1, iWidth, pFp); + pPtr += iStride[1]; + } +} + +int GenericDecoder::UnpackUncompressedData(igtl::VideoMessage* videoMessage, SourcePicture* decodedPic) +{ + igtl_int32 iWidth = videoMessage->GetWidth(); + igtl_int32 iHeight = videoMessage->GetHeight(); + if ((iWidth*iHeight*3>>1) != videoMessage->GetBitStreamSize()) + { + return -1; + } + igtl_uint16 frameType = videoMessage->GetFrameType(); + isGrayImage = false; + if (frameType>0X00FF) + { + frameType= frameType>>8; + isGrayImage = true; + } + decodedPic->picWidth = iWidth; + decodedPic->picHeight = iHeight; + decodedPic->data[1]= decodedPic->data[0] + iWidth*iHeight; + decodedPic->data[2]= decodedPic->data[1] + iWidth*iHeight/4; + decodedPic->stride[0] = iWidth; + decodedPic->stride[1] = decodedPic->stride[2] = iWidth>>1; + decodedPic->stride[3] = 0; + memcpy(decodedPic->data[0], videoMessage->GetPackFragmentPointer(2), iWidth*iHeight*3>>1); + return 1; +} + +igtl_int64 GenericDecoder::getCurrentTime() +{ +#if defined(_WIN32) + SYSTEMTIME sysTime = {0}; + GetLocalTime(&sysTime); + return sysTime.wMilliseconds; +#else + struct timeval tv_date; + gettimeofday(&tv_date, NULL); + return ((igtl_int64)tv_date.tv_sec * 1000000 + (igtl_int64)tv_date.tv_usec); +#endif +} + +int GenericDecoder::ConvertYUVToRGB(igtl_uint8 *YUVFrame, igtl_uint8* RGBFrame, int iHeight, int iWidth) +{ + int componentLength = iHeight*iWidth; + const igtl_uint8 *srcY = YUVFrame; + const igtl_uint8 *srcU = YUVFrame+componentLength; + const igtl_uint8 *srcV = YUVFrame+componentLength*5/4; + igtl_uint8 * YUV444 = new igtl_uint8[componentLength * 3]; + igtl_uint8 *dstY = YUV444; + igtl_uint8 *dstU = dstY + componentLength; + igtl_uint8 *dstV = dstU + componentLength; + + memcpy(dstY, srcY, componentLength); + const int halfHeight = iHeight/2; + const int halfWidth = iWidth/2; + +#pragma omp parallel for default(none) shared(dstV,dstU,srcV,srcU,iWidth) + for (int y = 0; y < halfHeight; y++) + { + for (int x = 0; x < halfWidth; x++) + { + dstU[2 * x + 2 * y*iWidth] = dstU[2 * x + 1 + 2 * y*iWidth] = srcU[x + y*iWidth/2]; + dstV[2 * x + 2 * y*iWidth] = dstV[2 * x + 1 + 2 * y*iWidth] = srcV[x + y*iWidth/2]; + } + memcpy(&dstU[(2 * y + 1)*iWidth], &dstU[(2 * y)*iWidth], iWidth); + memcpy(&dstV[(2 * y + 1)*iWidth], &dstV[(2 * y)*iWidth], iWidth); + } + + + const int yOffset = 16; + const int cZero = 128; + int yMult, rvMult, guMult, gvMult, buMult; + yMult = 298; + rvMult = 409; + guMult = -100; + gvMult = -208; + buMult = 517; + + static unsigned char clp_buf[384+256+384]; + static unsigned char *clip_buf = clp_buf+384; + + // initialize clipping table + memset(clp_buf, 0, 384); + + for (int i = 0; i < 256; i++) + { + clp_buf[384+i] = i; + } + memset(clp_buf+384+256, 255, 384); + + +#pragma omp parallel for default(none) shared(dstY,dstU,dstV,RGBFrame,yMult,rvMult,guMult,gvMult,buMult,clip_buf,componentLength)// num_threads(2) + for (int i = 0; i < componentLength; ++i) + { + const int Y_tmp = ((int)dstY[i] - yOffset) * yMult; + const int U_tmp = (int)dstU[i] - cZero; + const int V_tmp = (int)dstV[i] - cZero; + + const int R_tmp = (Y_tmp + V_tmp * rvMult ) >> 8;//32 to 16 bit conversion by left shifting + const int G_tmp = (Y_tmp + U_tmp * guMult + V_tmp * gvMult ) >> 8; + const int B_tmp = (Y_tmp + U_tmp * buMult ) >> 8; + + RGBFrame[3*i] = clip_buf[R_tmp]; + RGBFrame[3*i+1] = clip_buf[G_tmp]; + RGBFrame[3*i+2] = clip_buf[B_tmp]; + } + delete [] YUV444; + YUV444 = NULL; + dstY = NULL; + dstU = NULL; + dstV = NULL; + return 1; +} + +int GenericDecoder::ConvertYUVToGrayImage(igtl_uint8 * YUV420Frame, igtl_uint8 *GrayFrame, int iHeight, int iWidth) +{ + int componentLength = iHeight*iWidth; + for (int i = 0,j= 0; i < 3*componentLength; i=i+3,j++) { + GrayFrame[i] = YUV420Frame[j]; + GrayFrame[i+1] = YUV420Frame[j]; + GrayFrame[i+2] = YUV420Frame[j]; + } + return 1; +} + +void GenericEncoder::ConvertRGBToYUV(igtlUint8 *rgb, igtlUint8 *destination, unsigned int width, unsigned int height) +{ + size_t image_size = width * height; + size_t upos = image_size; + size_t vpos = upos + upos / 4; + size_t i = 0; + + for (size_t line = 0; line < height; ++line) + { + if (!(line % 2)) + { + for (size_t x = 0; x < width; x += 2) + { + igtlUint8 r = rgb[3 * i]; + igtlUint8 g = rgb[3 * i + 1]; + igtlUint8 b = rgb[3 * i + 2]; + + destination[i++] = ((66 * r + 129 * g + 25 * b) >> 8) + 16; + + destination[upos++] = ((-38 * r - 74 * g + 112 * b) >> 8) + 128; + destination[vpos++] = ((112 * r - 94 * g -18 * b) >> 8) + 128; + + r = rgb[3 * i]; + g = rgb[3 * i + 1]; + b = rgb[3 * i + 2]; + + destination[i++] = ((66 * r + 129 * g + 25 * b) >> 8) + 16; + } + } + else + { + for (size_t x = 0; x < width; x += 1) + { + igtlUint8 r = rgb[3 * i]; + igtlUint8 g = rgb[3 * i + 1]; + igtlUint8 b = rgb[3 * i + 2]; + + destination[i++] = ((66 * r + 129 * g + 25 * b) >> 8) + 16; + } + } + } +} + +int GenericEncoder::PackUncompressedData(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage) +{ + int iSourceWidth = pSrcPic->picWidth; + int iSourceHeight = pSrcPic->picHeight; + long kiPicResSize = iSourceWidth*iSourceHeight * 3 >> 1; + videoMessage->SetBitStreamSize(kiPicResSize); + videoMessage->AllocateScalars(); + int endian = (igtl_is_little_endian() == 1 ? IGTL_VIDEO_ENDIAN_LITTLE : IGTL_VIDEO_ENDIAN_BIG); + videoMessage->SetEndian(endian); //little endian is 2 big endian is 1 + videoMessage->SetWidth(pSrcPic->picWidth); + videoMessage->SetHeight(pSrcPic->picHeight); + encodedFrameType = FrameTypeKey; + if (isGrayImage) + { + encodedFrameType = FrameTypeKey << 8; + } + videoMessage->SetFrameType(encodedFrameType); + memcpy(videoMessage->GetPackFragmentPointer(2), pSrcPic->data[0], kiPicResSize); + videoMessage->Pack(); + return 0; +} + +} //namespace igtl \ No newline at end of file diff --git a/openigtlink/repo/Source/VideoStreaming/igtlCodecCommonClasses.h b/openigtlink/repo/Source/VideoStreaming/igtlCodecCommonClasses.h new file mode 100644 index 0000000..caaca80 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlCodecCommonClasses.h @@ -0,0 +1,292 @@ +// +// CodecCommonClasses.h +// OpenIGTLink +// +// Created by Longquan Chen on 3/30/17. +// +// + +#ifndef igtlCodecCommonClasses_h +#define igtlCodecCommonClasses_h + +#include +#if defined(_WIN32) /*&& defined(_DEBUG)*/ +#include +#include +#include +#include +#else +#include +#endif +#include +#include +#include +#include +#include "igtlVideoMessage.h" + + +namespace igtl { + +/** + * @brief Enumerate the type of video format, Only YV12, I420, I422, I444 images are supported in the codec. RGB format are not supported yet. + */ +typedef enum { + FormatI420 = 1, //// YUV420 + FormatI444 = 2 //// I444, +} VideoFormatType; + +typedef enum { + FrameTypeInvalid, ///< encoder not ready or parameters are invalidate + FrameTypeKey, ///< Key Frame + FrameTypeIntraPrediction, ///< Intra Prediction Frame + FrameTypeInterPrediction, ///< Inter Prediction Frame + FrameTypeSkip, ///< skip the frame based encoder kernel + FrameTypeUnKnown /// +} VideoFrameType; + +/** + * @brief Enumerate return type + */ +typedef enum { + ResultSuccess, ///< successful + InitParaError, ///< parameters are invalid + UnknownReason, + MallocMemeError, ///< malloc a memory error + InitExpected, ///< initial action is expected + UnsupportedData +} cmRETURN; + +typedef struct { + int colorFormat; ///< color space type + int stride[4]; ///< stride for each plane pData + unsigned char* data[4]; ///< plane pData + int picWidth; ///< luma picture width in x coordinate + int picHeight; ///< luma picture height in y coordinate + long long timeStamp; ///< timestamp of the source picture, unit: millisecond +} SourcePicture; + +class IGTLCommon_EXPORT ReadConfigFile { +public: + ReadConfigFile(); + ReadConfigFile (const char* pConfigFileName); + ReadConfigFile (const std::string& pConfigFileName); + ~ReadConfigFile(); + + void OpenFile (const char* strFile); + long ReadLine (std::string* strVal, const int iValSize = 4); + const bool EndOfFile(); + const int GetLines(); + const bool ExistFile(); + const std::string& GetFileName(); + +private: + FILE* configFile; + std::string configFileName; + unsigned int lineNums; +}; + +class IGTLCommon_EXPORT GenericEncoder : public Object +{ +public: + igtlTypeMacro(GenericEncoder, Object); + + GenericEncoder(){ + this->configFile = std::string(""); + + this->encodedFrameType = -1; + + this->isLossLessLink = true; + + this->initializationDone = false; + + this->picWidth = 0; + + this->picHeight = 0; + + this->codecSpeed = 0; + }; + virtual ~GenericEncoder(){}; + //void UpdateHashFromFrame (SFrameBSInfo& info, SHA1Context* ctx); + + //bool CompareHash (const unsigned char* digest, const char* hashStr); + + /** + Parse the configuration file to initialize the encoder and server. + */ + virtual int InitializeEncoder() = 0; + + + virtual void SetConfigurationFile(std::string configFile){this->configFile = std::string(configFile);}; + + virtual int FillSpecificParameters(){return -1;}; + + /** + Encode a frame, for performance issue, before encode the frame, make sure the frame pointer is updated with a new frame. + Otherwize, the old frame will be encoded. + */ + virtual int EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage = false ){return -1;}; + + /** + Get the encoder and server initialization status. + */ + virtual bool GetInitializationStatus(){return initializationDone;}; + + /** + Get the type of encoded frame + */ + + /** + Convert the generic image format to local specific data format of the codec + */ + virtual int ConvertToLocalImageFormat(SourcePicture* pSrcPic){return 0;}; + + virtual int GetVideoFrameType(){return encodedFrameType;}; + + virtual unsigned int GetPicWidth(){return this->picWidth;}; + + virtual unsigned int GetPicHeight(){return this->picHeight;}; + + virtual int SetLosslessLink(bool linkMethod){this->isLossLessLink = linkMethod; return 0;}; + + virtual bool GetLosslessLink(){return this->isLossLessLink;}; + + virtual int SetSpeed(int speed){return -1;}; + + virtual int SetRCMode(int value){return -1;}; + + virtual int SetKeyFrameDistance(int frameNum){return -1;}; + + virtual int SetQP(int maxQP, int minQP){return -1;}; + + virtual int SetRCTaregetBitRate(unsigned int bitRate){return -1;}; + + virtual int SetPicWidthAndHeight(unsigned int Width, unsigned int Height){return -1;}; + + static void ConvertRGBToYUV(igtlUint8 *rgb, igtlUint8 *destination, unsigned int width, unsigned int height); + + int PackUncompressedData(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage); + +protected: + + unsigned int picWidth; + + unsigned int picHeight; + + int encodedFrameType; + + ReadConfigFile cRdCfg; + + std::string configFile; + + bool initializationDone; + + bool isLossLessLink; + + int codecSpeed; + +}; + +class IGTLCommon_EXPORT GenericDecoder : public Object +{ +public: + igtlTypeMacro(igtl::GenericDecoder, igtl::Object); + + GenericDecoder(){deviceName = ""; isGrayImage = false;}; + virtual ~GenericDecoder(){}; + + virtual int DecodeBitStreamIntoFrame(unsigned char* bitStream,igtl_uint8* outputFrame,igtl_uint32 iDimensions[], igtl_uint64 &iStreamSize) = 0; + + static void Write2File (FILE* pFp, unsigned char* pData[], igtl_uint32 iDimensions[], igtl_uint32 iStride[]); + + virtual int DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* decodedPic){return -1;}; + + virtual igtl_int64 getCurrentTime(); + + virtual std::string GetDeviceName() + { + return this->deviceName; + }; + + virtual void SetDeviceName(std::string name) + { + this->deviceName = std::string(name); + }; + + virtual bool GetIsGrayImage() + { + return this->isGrayImage; + }; + + virtual void SetIsGrayImage(bool grayImage) + { + this->isGrayImage = grayImage; + }; + + /** + The conversion equations between RGB and YUV is Keith Jack's book "Video Demystified" (ISBN 1-878707-09-4). The equations are: + RGB to YUV Conversion + Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16 + + U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 + + V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 + + YUV to RGB Conversion + R = 1.164(Y - 16) + 1.596(V - 128) + + G = 1.164(Y - 16) - 0.391(U - 128) - 0.813(V - 128) + + B = 1.164(Y - 16) + 2.018(U - 128) + + To speed up the computation, float point multiplication is achieved via bitwise operator + RGB to YUV Conversion + Y = (16843 * R + 33030 * G + 6423 * B) >> 16 + 16 + + U = -(9699 * R - 19071 * G + 28770 * B) >> 16 + 128 + + V = (28770 * R - 24117 * G - 4653 * B) >> 16 + 128 + + Or + + Y = (66 * R + 129 * G + 25 * B) >> 8 + 16 + + U = (-38 * R - 74 * G + 112 * B) >> 8 + 128 + + V = (112 * R - 94 * G - 18 * B) >> 8 + 128 + + YUV to RGB Conversion + R = (76284 * (Y - 16) + 104595 * (V - 128)) >> 16 + + G = (76284 * (Y - 16) - 25625 * (U - 128) - 53280 * (V - 128)) >> 16 + + B = (76284 * (Y - 16) + 132252 * (U - 128)) >> 16 + + Or + + R = (298 * (Y - 16) + 409 * (V - 128)) >> 8 + + G = (298 * (Y - 16) - 100 * (U - 128) - 208 * (V - 128)) >> 8 + + B = (298 * (Y - 16) + 517 * (U - 128)) >> 8 + + To do, use the latest conversion Scheme from ITU. + https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2020-2-201510-I!!PDF-E.pdf + */ + static int ConvertYUVToRGB(igtl_uint8 *YUVFrame, igtl_uint8* RGBFrame, int iHeight, int iWidth); + + static int ConvertYUVToGrayImage(igtl_uint8 * YUV420Frame, igtl_uint8 *GrayFrame, int iHeight, int iWidth); + + int UnpackUncompressedData(igtl::VideoMessage* videoMessage, SourcePicture* decodedPic); + +protected: + + virtual void ComposeByteSteam(igtl_uint8** inputData, int dimension[2], int iStride[2], igtl_uint8 *outputFrame){}; + + std::string deviceName; + + bool isGrayImage; + +}; + +} // namespace igtl +#endif diff --git a/openigtlink/repo/Source/VideoStreaming/igtlH264Decoder.cxx b/openigtlink/repo/Source/VideoStreaming/igtlH264Decoder.cxx new file mode 100644 index 0000000..bb3bbf1 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlH264Decoder.cxx @@ -0,0 +1,278 @@ +/*========================================================================= + + Program: H264Encoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +/*! + * \copy + * Copyright (c) 2013, Cisco Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "igtlH264Decoder.h" + +namespace igtl { + +H264Decoder::H264Decoder() +{ + WelsCreateDecoder (&this->pDecoder); + memset (&this->decParam, 0, sizeof (SDecodingParam)); + this->decParam.uiTargetDqLayer = UCHAR_MAX; + this->decParam.eEcActiveIdc = ERROR_CON_SLICE_COPY; + this->decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; + this->pDecoder->Initialize (&decParam); + this->deviceName = ""; +} + +H264Decoder::~H264Decoder() +{ + WelsDestroyDecoder(pDecoder); + pDecoder = NULL; +} + + +int H264Decoder::Process (void* pDst[3], SBufferInfo* pInfo, FILE* pFp) { + + int iRet = 0; + + if (pDst[0] && pDst[1] && pDst[2] && pInfo) { + igtl_uint32 iStride[2]; + int iWidth = pInfo->UsrData.sSystemBuffer.iWidth; + int iHeight = pInfo->UsrData.sSystemBuffer.iHeight; + iStride[0] = pInfo->UsrData.sSystemBuffer.iStride[0]; + iStride[1] = pInfo->UsrData.sSystemBuffer.iStride[1]; + if(pFp) + { + igtl_uint32 dimensions[2] = {static_cast(iWidth), static_cast(iHeight)}; + Write2File (pFp, (unsigned char**)pDst, dimensions, iStride); + } + } + return iRet; +} + +igtl_int32 iFrameCountTotal = 0; + + +void H264Decoder::ComposeByteSteam(igtl_uint8** inputData, int dimension[2], int iStride[2], igtl_uint8 *outputFrame) +{ + int iWidth = dimension[0]; + int iHeight = dimension[1]; +#pragma omp parallel for default(none) shared(outputByteStream,inputData, iStride, iHeight, iWidth) + for (int i = 0; i < iHeight; i++) + { + igtl_uint8* pPtr = inputData[0]+i*iStride[0]; + for (int j = 0; j < iWidth; j++) + { + outputFrame[i*iWidth + j] = pPtr[j]; + } + } +#pragma omp parallel for default(none) shared(outputByteStream,inputData, iStride, iHeight, iWidth) + for (int i = 0; i < iHeight/2; i++) + { + igtl_uint8* pPtr = inputData[1]+i*iStride[1]; + for (int j = 0; j < iWidth/2; j++) + { + outputFrame[i*iWidth/2 + j + iHeight*iWidth] = pPtr[j]; + } + } +#pragma omp parallel for default(none) shared(outputByteStream, inputData, iStride, iHeight, iWidth) + for (int i = 0; i < iHeight/2; i++) + { + igtl_uint8* pPtr = inputData[2]+i*iStride[1]; + for (int j = 0; j < iWidth/2; j++) + { + outputFrame[i*iWidth/2 + j + iHeight*iWidth*5/4] = pPtr[j]; + } + } +} + + +int H264Decoder::DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* pDecodedPic) +{ + if(videoMessage->GetBitStreamSize()) + { + igtl_int32 iWidth = videoMessage->GetWidth(); + igtl_int32 iHeight = videoMessage->GetHeight(); + igtl_uint64 iStreamSize = videoMessage->GetBitStreamSize(); + igtl_uint16 frameType = videoMessage->GetFrameType(); + isGrayImage = false; + if (frameType>0X00FF) + { + frameType= frameType>>8; + isGrayImage = true; + } + pDecodedPic->picWidth = iWidth; + pDecodedPic->picHeight = iHeight; + pDecodedPic->data[1]= pDecodedPic->data[0] + iWidth*iHeight; + pDecodedPic->data[2]= pDecodedPic->data[1] + iWidth*iHeight/4; + pDecodedPic->stride[0] = iWidth; + pDecodedPic->stride[1] = pDecodedPic->stride[2] = iWidth>>1; + pDecodedPic->stride[3] = 0; + igtl_uint32 dimensions[2] = {static_cast(iWidth), static_cast(iHeight)}; + return this->DecodeBitStreamIntoFrame(videoMessage->GetPackFragmentPointer(2), pDecodedPic->data[0], dimensions, iStreamSize); + } + return -1; +} + +int H264Decoder::DecodeBitStreamIntoFrame(unsigned char* kpH264BitStream,igtl_uint8* outputFrame, igtl_uint32 dimensions[2], igtl_uint64& iStreamSize) { + + unsigned long long uiTimeStamp = 0; + igtl_int64 iStart = 0, iEnd = 0, iTotal = 0; + igtl_int32 iSliceSize; + igtl_int32 iSliceIndex = 0; + igtl_uint32 iWidth = dimensions[0]; + igtl_uint32 iHeight = dimensions[1]; + unsigned char* pBuf = NULL; + unsigned char uiStartCode[4] = {0, 0, 0, 1}; + + unsigned char* pData[3] = {NULL}; + SBufferInfo sDstBufInfo; + + igtl_int32 iBufPos = 0; + igtl_int32 i = 0; + igtl_int32 iFrameCount = 0; + igtl_int32 iEndOfStreamFlag = 0; + //for coverage test purpose + igtl_int32 iErrorConMethod = (igtl_int32) ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE; + pDecoder->SetOption (DECODER_OPTION_ERROR_CON_IDC, &iErrorConMethod); + //~end for + double dElapsed = 0; + + if (iStreamSize <= 0) + { + //fprintf (stderr, "Current Bit Stream File is too small, read error!!!!\n"); + goto label_exit; + } + pBuf = new unsigned char[iStreamSize + 5]; + if (pBuf == NULL) + { + //fprintf (stderr, "new buffer failed!\n"); + goto label_exit; + } + memcpy (pBuf, kpH264BitStream, iStreamSize); + memcpy (pBuf + iStreamSize, &uiStartCode[0], 4); //confirmed_safe_unsafe_usage + + while (true) + { + if (iBufPos >= iStreamSize) + { + iEndOfStreamFlag = true; + if (iEndOfStreamFlag) + pDecoder->SetOption (DECODER_OPTION_END_OF_STREAM, (void*)&iEndOfStreamFlag); + break; + } + for (i = 0; i < iStreamSize; i++) + { + if ((pBuf[iBufPos + i] == 0 && pBuf[iBufPos + i + 1] == 0 && pBuf[iBufPos + i + 2] == 0 && pBuf[iBufPos + i + 3] == 1 + && i > 0) || (pBuf[iBufPos + i] == 0 && pBuf[iBufPos + i + 1] == 0 && pBuf[iBufPos + i + 2] == 1 && i > 0)) + { + break; + } + } + iSliceSize = i; + if (iSliceSize < 4) + { //too small size, no effective data, ignore + iBufPos += iSliceSize; + continue; + } + + iStart = getCurrentTime(); + pData[0] = NULL; + pData[1] = NULL; + pData[2] = NULL; + uiTimeStamp ++; + memset (&sDstBufInfo, 0, sizeof (SBufferInfo)); + sDstBufInfo.uiInBsTimeStamp = uiTimeStamp; + sDstBufInfo.UsrData.sSystemBuffer.iWidth = +#ifndef NO_DELAY_DECODING + pDecoder->DecodeFrameNoDelay (pBuf + iBufPos, iSliceSize, pData, &sDstBufInfo); +#else + pDecoder->DecodeFrame2 (pBuf + iBufPos, iSliceSize, pData, &sDstBufInfo); +#endif + + iEnd = getCurrentTime(); + iTotal = iEnd - iStart; + if (sDstBufInfo.iBufferStatus == 1) + { + Process ((void**)pData, &sDstBufInfo, NULL); + iWidth = sDstBufInfo.UsrData.sSystemBuffer.iWidth; + iHeight = sDstBufInfo.UsrData.sSystemBuffer.iHeight; + ++ iFrameCount; + } + +#ifdef NO_DELAY_DECODING + iStart = getCurrentTime(); + pData[0] = NULL; + pData[1] = NULL; + pData[2] = NULL; + memset (&sDstBufInfo, 0, sizeof (SBufferInfo)); + sDstBufInfo.uiInBsTimeStamp = uiTimeStamp; + pDecoder->DecodeFrame2 (NULL, 0, pData, &sDstBufInfo); + iEnd = getCurrentTime(); + iTotal = iEnd - iStart; + if (sDstBufInfo.iBufferStatus == 1) + { + Process ((void**)pData, &sDstBufInfo, NULL); + int dimension[2] = {static_cast(iWidth), static_cast(iHeight)}; + int stride[2] = {sDstBufInfo.UsrData.sSystemBuffer.iStride[0],sDstBufInfo.UsrData.sSystemBuffer.iStride[1]}; + ComposeByteSteam(pData, dimension, stride, outputFrame); + iWidth = sDstBufInfo.UsrData.sSystemBuffer.iWidth; + iHeight = sDstBufInfo.UsrData.sSystemBuffer.iHeight; + ++ iFrameCount; + } +#endif + if (iFrameCount) + { + dElapsed = iTotal / 1e6; + } + iBufPos += iSliceSize; + ++ iSliceIndex; + } + // coverity scan uninitial +label_exit: + if (pBuf) { + delete[] pBuf; + pBuf = NULL; + } + if (iFrameCount) + { + return 2; + } + return -1; +} + +}// Namespace igtl diff --git a/openigtlink/repo/Source/VideoStreaming/igtlH264Decoder.h b/openigtlink/repo/Source/VideoStreaming/igtlH264Decoder.h new file mode 100644 index 0000000..ffa40aa --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlH264Decoder.h @@ -0,0 +1,88 @@ +/*========================================================================= + + Program: H264Encoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +/*! + * \copy + * Copyright (c) 2013, Cisco Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __igtlH264Decoder_h +#define __igtlH264Decoder_h + +#include +#include +#include +#include "codec_api.h" +#include "codec_app_def.h" +#include "igtl_types.h" +#include "igtlVideoMessage.h" +#include "igtlCodecCommonClasses.h" + +#define NO_DELAY_DECODING + +namespace igtl { + +class IGTLCommon_EXPORT H264Decoder:public GenericDecoder +{ +public: + igtlTypeMacro(H264Decoder, GenericDecoder); + igtlNewMacro(H264Decoder); + + H264Decoder(); + ~H264Decoder(); + + int DecodeBitStreamIntoFrame(unsigned char* bitStream,igtl_uint8* outputFrame, igtl_uint32 iDimensions[2], igtl_uint64 &iStreamSize) override; + + int DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* pDecodedPic) override; + + int Process (void* pDst[3], SBufferInfo* pInfo, FILE* pFp); + +private: + + void ComposeByteSteam(igtl_uint8** inputData, int dimension[2], int iStride[2], igtl_uint8 *outputFrame) override; + + ISVCDecoder* pDecoder; + + SDecodingParam decParam; + +}; + + +} // Namespace igtl +#endif \ No newline at end of file diff --git a/openigtlink/repo/Source/VideoStreaming/igtlH264Encoder.cxx b/openigtlink/repo/Source/VideoStreaming/igtlH264Encoder.cxx new file mode 100644 index 0000000..32d7944 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlH264Encoder.cxx @@ -0,0 +1,816 @@ +/*========================================================================= + + Program: H264Encoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +/*! + * \copy + * Copyright (c) 2013, Cisco Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +#define _CRT_SECURE_NO_WARNINGS +#include +#include +#include +#include +#include +#include +#if defined (ANDROID_NDK) +#include +#endif +#ifdef ONLY_ENC_FRAMES_NUM +#undef ONLY_ENC_FRAMES_NUM +#endif//ONLY_ENC_FRAMES_NUM +#define ONLY_ENC_FRAMES_NUM INT_MAX // 2, INT_MAX // type the num you try to encode here, 2, 10, etc + +#if defined (WINDOWS_PHONE) +float g_fFPS = 0.0; +double g_dEncoderTime = 0.0; +int g_iEncodedFrame = 0; +#endif + +#if defined (ANDROID_NDK) +#define LOG_TAG "welsenc" +#define LOGI(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) +#define printf(...) LOGI(__VA_ARGS__) +#define fprintf(a, ...) LOGI(__VA_ARGS__) +#endif + +#ifdef _MSC_VER +#include /* _setmode() */ +#include /* _O_BINARY */ +#endif//_MSC_VER + +#include "codec_def.h" +#include "codec_api.h" + +#ifdef _WIN32 +#ifdef WINAPI_FAMILY +#include +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define HAVE_PROCESS_AFFINITY +#endif +#else /* defined(WINAPI_FAMILY) */ +#define HAVE_PROCESS_AFFINITY +#endif +#endif /* _WIN32 */ + +#if defined(__linux__) || defined(__unix__) +#define _FILE_OFFSET_BITS 64 +#endif + + +#include "igtlH264Encoder.h" +#include "igtlVideoMessage.h" + +namespace igtl { + +/* Ctrl-C handler */ +static int g_iCtrlC = 0; +static void SigIntHandler (int a) { + g_iCtrlC = 1; +} + +#define CALC_BI_STRIDE(width,bitcount) ((((width * bitcount) + 31) & ~31) >> 3) + +H264Encoder::H264Encoder(char *configFile):GenericEncoder() +{ + this->pSVCEncoder = NULL; + + memset (&sFbi, 0, sizeof (SFrameBSInfo)); + +#ifdef _MSC_VER + _setmode (_fileno (stdin), _O_BINARY); /* thanks to Marcoss Morais */ + _setmode (_fileno (stdout), _O_BINARY); + +#endif + + /* Control-C handler */ + signal (SIGINT, SigIntHandler); + + WelsCreateSVCEncoder(&(this->pSVCEncoder)); + + this->pSVCEncoder->GetDefaultParams (&sSvcParam); + + FillSpecificParameters (); +} + +H264Encoder::~H264Encoder() +{ + WelsDestroySVCEncoder (this->pSVCEncoder); + this->pSVCEncoder = NULL; +} + +int H264Encoder::FillSpecificParameters() { + /* Test for temporal, spatial, SNR scalability */ + sSvcParam.iUsageType = CAMERA_VIDEO_REAL_TIME; + sSvcParam.fMaxFrameRate = 200.0f; // input frame rate + sSvcParam.iPicWidth = 256; // width of picture in samples + sSvcParam.iPicHeight = 256; // height of picture in samples + sSvcParam.iTargetBitrate = 2500000; // target bitrate desired + sSvcParam.iMaxBitrate = UNSPECIFIED_BIT_RATE; + sSvcParam.iRCMode = RC_OFF_MODE; // rc mode control + sSvcParam.bIsLosslessLink = true; + sSvcParam.iTemporalLayerNum = 1; // layer number at temporal level + sSvcParam.iSpatialLayerNum = 1; // layer number at spatial level + sSvcParam.iEntropyCodingModeFlag = 1; + sSvcParam.bEnableDenoise = 0; // denoise control + sSvcParam.bEnableBackgroundDetection = 1; // background detection control + sSvcParam.bEnableAdaptiveQuant = 1; // adaptive quantization control + sSvcParam.bEnableFrameSkip = 0; // frame skipping + sSvcParam.bEnableLongTermReference = 0; // long term reference control + sSvcParam.iLtrMarkPeriod = 30; + sSvcParam.uiIntraPeriod = 16; // period of Intra frame + sSvcParam.bUseLoadBalancing = false; + sSvcParam.eSpsPpsIdStrategy = INCREASING_ID; + sSvcParam.bPrefixNalAddingCtrl = 0; + sSvcParam.iComplexityMode = HIGH_COMPLEXITY; + sSvcParam.bSimulcastAVC = false; + sSvcParam.iMaxQp = 51; + sSvcParam.iMinQp = 0; + int iIndexLayer = 0; + sSvcParam.sSpatialLayers[iIndexLayer].uiProfileIdc = PRO_BASELINE; + sSvcParam.sSpatialLayers[iIndexLayer].uiLevelIdc = LEVEL_5_2; + sSvcParam.sSpatialLayers[iIndexLayer].iVideoWidth = 256; + sSvcParam.sSpatialLayers[iIndexLayer].iVideoHeight = 256; + sSvcParam.sSpatialLayers[iIndexLayer].iDLayerQp = 1; + sSvcParam.sSpatialLayers[iIndexLayer].fFrameRate = 60.0; + sSvcParam.sSpatialLayers[iIndexLayer].iSpatialBitrate = 1500000; + sSvcParam.sSpatialLayers[iIndexLayer].iMaxSpatialBitrate = UNSPECIFIED_BIT_RATE; + sSvcParam.sSpatialLayers[iIndexLayer].sSliceArgument.uiSliceMode = SM_SINGLE_SLICE; + sSvcParam.sSpatialLayers[iIndexLayer].sSliceArgument.uiSliceNum = 1; + + float fMaxFr = sSvcParam.sSpatialLayers[sSvcParam.iSpatialLayerNum - 1].fFrameRate; + for (int32_t i = sSvcParam.iSpatialLayerNum - 2; i >= 0; --i) { + if (sSvcParam.sSpatialLayers[i].fFrameRate > (fMaxFr+EPSN)) + fMaxFr = sSvcParam.sSpatialLayers[i].fFrameRate; + } + sSvcParam.fMaxFrameRate = fMaxFr; + + return 0; +} + +int H264Encoder::SetRCTaregetBitRate(unsigned int bitRate) +{ + this->sSvcParam.iTargetBitrate = bitRate; + for (int i = 0; i < this->sSvcParam.iSpatialLayerNum; i++) + { + this->sSvcParam.sSpatialLayers[i].iSpatialBitrate = bitRate/this->sSvcParam.iSpatialLayerNum; + } + if (this->pSVCEncoder->InitializeExt (&sSvcParam)) { + fprintf (stderr, "Set target bit rate failed. \n"); + return -1; + } + this->initializationDone = true; + return 0; +} + +int H264Encoder::SetRCMode(int value) +{ + sSvcParam.iRCMode = (RC_MODES)value; + if(sSvcParam.iRCMode == RC_QUALITY_MODE || sSvcParam.iRCMode == RC_BITRATE_MODE || sSvcParam.iRCMode == RC_TIMESTAMP_MODE) + { + sSvcParam.bEnableFrameSkip = true; + } + if (this->pSVCEncoder->InitializeExt (&sSvcParam)) { + fprintf (stderr, "Set RC mode failed. \n"); + return -1; + } + this->initializationDone = true; + return 0; +} + +int H264Encoder::SetQP(int maxQP, int minQP) +{ + sSvcParam.iMaxQp = maxQP<51?maxQP:51; + sSvcParam.iMinQp = minQP>0?minQP:0; + for(int i = 0; i pSVCEncoder->InitializeExt (&sSvcParam)) { + fprintf (stderr, "Set QP value failed.\n"); + return -1; + } + this->initializationDone = true; + return 0; +} + +int H264Encoder::ParseLayerConfig (string strTag[], const int iLayer, SEncParamExt& pSvcParam) { + + SSpatialLayerConfig* pDLayer = &pSvcParam.sSpatialLayers[iLayer]; + int iLeftTargetBitrate = (pSvcParam.iRCMode != RC_OFF_MODE) ? pSvcParam.iTargetBitrate : 0; + SLayerPEncCtx sLayerCtx; + memset (&sLayerCtx, 0, sizeof (SLayerPEncCtx)); + + string str_ ("SlicesAssign"); + const int kiSize = (int)str_.size(); + + if (!strTag[0].empty()) + { + if (strTag[0].compare ("FrameWidth") == 0) + { + pDLayer->iVideoWidth = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("FrameHeight") == 0) + { + pDLayer->iVideoHeight = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("FrameRateOut") == 0) + { + pDLayer->fFrameRate = (float)atof (strTag[1].c_str()); + } + else if (strTag[0].compare ("ProfileIdc") == 0) + { + pDLayer->uiProfileIdc = (EProfileIdc)atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("SpatialBitrate") == 0) + { + pDLayer->iSpatialBitrate = 1000 * atoi (strTag[1].c_str()); + if (pSvcParam.iRCMode != RC_OFF_MODE) + { + if (pDLayer->iSpatialBitrate <= 0) + { + fprintf (stderr, "Invalid spatial bitrate(%d) in dependency layer #%d.\n", pDLayer->iSpatialBitrate, iLayer); + return -1; + } + if (pDLayer->iSpatialBitrate > iLeftTargetBitrate) + { + fprintf (stderr, "Invalid spatial(#%d) bitrate(%d) setting due to unavailable left(%d)!\n", iLayer, + pDLayer->iSpatialBitrate, iLeftTargetBitrate); + return -1; + } + iLeftTargetBitrate -= pDLayer->iSpatialBitrate; + } + } + else if (strTag[0].compare ("MaxSpatialBitrate") == 0) + { + pDLayer->iMaxSpatialBitrate = 1000 * atoi (strTag[1].c_str()); + if (pSvcParam.iRCMode != RC_OFF_MODE) + { + if (pDLayer->iMaxSpatialBitrate < 0) + { + fprintf (stderr, "Invalid max spatial bitrate(%d) in dependency layer #%d.\n", pDLayer->iMaxSpatialBitrate, iLayer); + return -1; + } + if (pDLayer->iMaxSpatialBitrate > 0 && pDLayer->iMaxSpatialBitrate < pDLayer->iSpatialBitrate) + { + fprintf (stderr, "Invalid max spatial(#%d) bitrate(%d) setting::: < layerBitrate(%d)!\n", iLayer, + pDLayer->iMaxSpatialBitrate, pDLayer->iSpatialBitrate); + return -1; + } + } + } + else if (strTag[0].compare ("InitialQP") == 0) + { + sLayerCtx.iDLayerQp = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("SliceMode") == 0) + { + sLayerCtx.sSliceArgument.uiSliceMode = (SliceModeEnum)atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("SliceSize") == 0) + { //SM_SIZELIMITED_SLICE + sLayerCtx.sSliceArgument.uiSliceSizeConstraint = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("SliceNum") == 0) + { + sLayerCtx.sSliceArgument.uiSliceNum = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare (0, kiSize, str_) == 0) + { + const char* kpString = strTag[0].c_str(); + int uiSliceIdx = atoi (&kpString[kiSize]); + sLayerCtx.sSliceArgument.uiSliceMbNum[uiSliceIdx] = atoi (strTag[1].c_str()); + } + } + pDLayer->iDLayerQp = sLayerCtx.iDLayerQp; + pDLayer->sSliceArgument.uiSliceMode = sLayerCtx.sSliceArgument.uiSliceMode; + + memcpy (&pDLayer->sSliceArgument, &sLayerCtx.sSliceArgument, sizeof (SSliceArgument)); // confirmed_safe_unsafe_usage + memcpy (&pDLayer->sSliceArgument.uiSliceMbNum[0], &sLayerCtx.sSliceArgument.uiSliceMbNum[0], + sizeof (sLayerCtx.sSliceArgument.uiSliceMbNum)); // confirmed_safe_unsafe_usage + + return 0; +} + +int H264Encoder::ParseConfig() { + string strTag[4]; + + while (!cRdCfg.EndOfFile()) + { + long iRd = cRdCfg.ReadLine (&strTag[0]); + if (iRd > 0) + { + if (strTag[0].empty()) + continue; + if (strTag[0].compare ("PicWidth") == 0) + { + sSvcParam.iPicWidth = atoi(strTag[1].c_str()); + } + if (strTag[0].compare ("PicHeight") == 0) + { + sSvcParam.iPicHeight = atoi(strTag[1].c_str()); + } + if (strTag[0].compare ("UsageType") == 0) + { + sSvcParam.iUsageType = (EUsageType)atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("SimulcastAVC") == 0) + { + sSvcParam.bSimulcastAVC = atoi (strTag[1].c_str()) ? true : false; + } + else if (strTag[0].compare ("TemporalLayerNum") == 0) + { + sSvcParam.iTemporalLayerNum = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("IntraPeriod") == 0) + { + sSvcParam.uiIntraPeriod = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("MaxNalSize") == 0) + { + sSvcParam.uiMaxNalSize = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("SpsPpsIDStrategy") == 0) + { + int32_t iValue = atoi (strTag[1].c_str()); + switch (iValue) + { + case 0: + sSvcParam.eSpsPpsIdStrategy = CONSTANT_ID; + break; + case 0x01: + sSvcParam.eSpsPpsIdStrategy = INCREASING_ID; + break; + case 0x02: + sSvcParam.eSpsPpsIdStrategy = SPS_LISTING; + break; + case 0x03: + sSvcParam.eSpsPpsIdStrategy = SPS_LISTING_AND_PPS_INCREASING; + break; + case 0x06: + sSvcParam.eSpsPpsIdStrategy = SPS_PPS_LISTING; + break; + default: + sSvcParam.eSpsPpsIdStrategy = CONSTANT_ID; + break; + } + } + else if (strTag[0].compare ("EnableScalableSEI") == 0) + { + sSvcParam.bEnableSSEI = atoi (strTag[1].c_str()) ? true : false; + } + else if (strTag[0].compare ("EnableFrameCropping") == 0) + { + sSvcParam.bEnableFrameCroppingFlag = (atoi (strTag[1].c_str()) != 0); + } + else if (strTag[0].compare ("EntropyCodingModeFlag") == 0) + { + sSvcParam.iEntropyCodingModeFlag = (atoi (strTag[1].c_str()) != 0); + } + else if (strTag[0].compare ("LoopFilterDisableIDC") == 0) + { + sSvcParam.iLoopFilterDisableIdc = (int8_t)atoi (strTag[1].c_str()); + if (sSvcParam.iLoopFilterDisableIdc > 6 || sSvcParam.iLoopFilterDisableIdc < 0) + { + fprintf (stderr, "Invalid parameter in iLoopFilterDisableIdc: %d.\n", sSvcParam.iLoopFilterDisableIdc); + return -1; + } + } + else if (strTag[0].compare ("LoopFilterAlphaC0Offset") == 0) + { + sSvcParam.iLoopFilterAlphaC0Offset = (int8_t)atoi (strTag[1].c_str()); + if (sSvcParam.iLoopFilterAlphaC0Offset < -6) + sSvcParam.iLoopFilterAlphaC0Offset = -6; + else if (sSvcParam.iLoopFilterAlphaC0Offset > 6) + sSvcParam.iLoopFilterAlphaC0Offset = 6; + } + else if (strTag[0].compare ("LoopFilterBetaOffset") == 0) + { + sSvcParam.iLoopFilterBetaOffset = (int8_t)atoi (strTag[1].c_str()); + if (sSvcParam.iLoopFilterBetaOffset < -6) + sSvcParam.iLoopFilterBetaOffset = -6; + else if (sSvcParam.iLoopFilterBetaOffset > 6) + sSvcParam.iLoopFilterBetaOffset = 6; + } + else if (strTag[0].compare ("MultipleThreadIdc") == 0) + { + // # 0: auto(dynamic imp. internal encoder); 1: multiple threads imp. disabled; > 1: count number of threads; + sSvcParam.iMultipleThreadIdc = atoi (strTag[1].c_str()); + if (sSvcParam.iMultipleThreadIdc < 0) + sSvcParam.iMultipleThreadIdc = 0; + else if (sSvcParam.iMultipleThreadIdc > MAX_THREADS_NUM) + sSvcParam.iMultipleThreadIdc = MAX_THREADS_NUM; + } + else if (strTag[0].compare ("UseLoadBalancing") == 0) + { + sSvcParam.bUseLoadBalancing = (atoi (strTag[1].c_str())) ? true : false; + } + else if (strTag[0].compare ("RCMode") == 0) + { + sSvcParam.iRCMode = (RC_MODES) atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("TargetBitrate") == 0) + { + sSvcParam.iTargetBitrate = 1000 * atoi (strTag[1].c_str()); + if ((sSvcParam.iRCMode != RC_OFF_MODE) && sSvcParam.iTargetBitrate <= 0) + { + fprintf (stderr, "Invalid target bitrate setting due to RC enabled. Check TargetBitrate field please!\n"); + return -1; + } + } + else if (strTag[0].compare ("MaxOverallBitrate") == 0) + { + sSvcParam.iMaxBitrate = 1000 * atoi (strTag[1].c_str()); + if ((sSvcParam.iRCMode != RC_OFF_MODE) && sSvcParam.iMaxBitrate < 0) + { + fprintf (stderr, "Invalid max overall bitrate setting due to RC enabled. Check MaxOverallBitrate field please!\n"); + return -1; + } + } + else if (strTag[0].compare ("MaxQp") == 0) + { + sSvcParam.iMaxQp = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("MinQp") == 0) + { + sSvcParam.iMinQp = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("EnableDenoise") == 0) + { + sSvcParam.bEnableDenoise = atoi (strTag[1].c_str()) ? true : false; + } + else if (strTag[0].compare ("EnableSceneChangeDetection") == 0) + { + sSvcParam.bEnableSceneChangeDetect = atoi (strTag[1].c_str()) ? true : false; + } + else if (strTag[0].compare ("EnableBackgroundDetection") == 0) + { + sSvcParam.bEnableBackgroundDetection = atoi (strTag[1].c_str()) ? true : false; + } + else if (strTag[0].compare ("EnableAdaptiveQuantization") == 0) + { + sSvcParam.bEnableAdaptiveQuant = atoi (strTag[1].c_str()) ? true : false; + } + else if (strTag[0].compare ("EnableFrameSkip") == 0) + { + sSvcParam.bEnableFrameSkip = atoi (strTag[1].c_str()) ? true : false; + } + else if (strTag[0].compare ("EnableLongTermReference") == 0) + { + sSvcParam.bEnableLongTermReference = atoi (strTag[1].c_str()) ? true : false; + } + else if (strTag[0].compare ("LongTermReferenceNumber") == 0) + { + sSvcParam.iLTRRefNum = atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("LtrMarkPeriod") == 0) + { + sSvcParam.iLtrMarkPeriod = (uint32_t)atoi (strTag[1].c_str()); + } + else if (strTag[0].compare ("LosslessLink") == 0) + { + sSvcParam.bIsLosslessLink = atoi (strTag[1].c_str()) ? true : false; + } + else if (strTag[0].compare ("NumLayers") == 0) + { + sSvcParam.iSpatialLayerNum = (int8_t)atoi (strTag[1].c_str()); + if (sSvcParam.iSpatialLayerNum > MAX_DEPENDENCY_LAYER || sSvcParam.iSpatialLayerNum <= 0) + { + fprintf (stderr, "Invalid parameter in iSpatialLayerNum: %d.\n", sSvcParam.iSpatialLayerNum); + return -1; + } + break; + } + else if (strTag[0].compare ("PrefixNALAddingCtrl") == 0) + { + int ctrl_flag = atoi (strTag[1].c_str()); + if (ctrl_flag > 1) + ctrl_flag = 1; + else if (ctrl_flag < 0) + ctrl_flag = 0; + sSvcParam.bPrefixNalAddingCtrl = ctrl_flag ? true : false; + } + } + } + igtlUint8 actLayerConfigNum = 0; + igtlUint8 layerIndex = -1; + while (!cRdCfg.EndOfFile()) + { + long iRd = cRdCfg.ReadLine (&strTag[0]); + if (iRd > 0) + { + if (strTag[0].empty()) + continue; + if (strTag[0].compare ("LayerIndex") == 0) + { + layerIndex = atoi(strTag[1].c_str()); + if(layerIndex>=0) + { + SSpatialLayerConfig* pDLayer = &sSvcParam.sSpatialLayers[layerIndex]; + pDLayer->iVideoWidth = this->sSvcParam.iPicWidth; + pDLayer->iVideoHeight = this->sSvcParam.iPicHeight; + actLayerConfigNum++; + } + } + if(layerIndex>=0) + { + this->ParseLayerConfig(strTag, layerIndex, sSvcParam); + } + } + } + + const igtlUint8 kiActualLayerNum = sSvcParam.iSpatialLayerNum + kiActualLayerNum) { // fixed number of dependency layer due to parameter error in settings + sSvcParam.iSpatialLayerNum = kiActualLayerNum; + } + return 0; +} + +int H264Encoder::SetLosslessLink(bool linkMethod) +{ + this->isLossLessLink = linkMethod; + this->sSvcParam.bIsLosslessLink = isLossLessLink; + if (this->pSVCEncoder->InitializeExt (&sSvcParam)) + { + fprintf (stderr, "parse svc parameter config file failed.\n"); + return -1; + } + this->initializationDone = true; + return 0; +} + +int H264Encoder::SetSpeed(int speed) +{ + speed = speed>=LOW_COMPLEXITY?speed:LOW_COMPLEXITY; + speed = speed<=HIGH_COMPLEXITY?speed:HIGH_COMPLEXITY; + this->codecSpeed = speed; + this->sSvcParam.iComplexityMode = (ECOMPLEXITY_MODE)(2-this->codecSpeed); + if (this->pSVCEncoder->InitializeExt (&sSvcParam)) + { + fprintf (stderr, "Set speed mode failed.\n"); + return -1; + } + return 0; +} + +int H264Encoder::InitializeEncoder() +{ + //------------------------------------------------------------ + int iRet = 0; + + if (this->configFile=="" && this->pSVCEncoder) + { + fprintf (stderr, "No configuration file specified. Use Default Parameters\n"); + iRet = this->pSVCEncoder->InitializeExt (&sSvcParam); + if (iRet) { + fprintf (stderr, "parse svc parameter config file failed.\n"); + goto INSIDE_MEM_FREE; + } + this->initializationDone = true; + return iRet; + } + else + { + cRdCfg.OpenFile (this->configFile.c_str());// to do get the first augments from this->augments. + if (cRdCfg.ExistFile()) + { + iRet = ParseConfig(); + if (iRet) { + fprintf (stderr, "parse svc parameter config file failed.\n"); + goto INSIDE_MEM_FREE; + } + } + else + { + fprintf (stderr, "Specified file: %s not exist, maybe invalid path or parameter settting.\n", + cRdCfg.GetFileName().c_str()); + iRet = 1; + goto INSIDE_MEM_FREE; + } + static int g_LevelSetting = WELS_LOG_ERROR; + this->pSVCEncoder->SetOption (ENCODER_OPTION_TRACE_LEVEL, &g_LevelSetting); + //finish reading the configuration + + // sSvcParam.bSimulcastAVC = true; + if (cmResultSuccess != this->pSVCEncoder->InitializeExt (&sSvcParam)) { // SVC encoder initialization + fprintf (stderr, "SVC encoder Initialize failed\n"); + iRet = 1; + goto INSIDE_MEM_FREE; + } + this->initializationDone = true; + return 0; + } + +INSIDE_MEM_FREE: + this->initializationDone = false; + return -1; +} + +int H264Encoder::SetPicWidthAndHeight(unsigned int Width, unsigned int Height) +{ + this->sSvcParam.iPicWidth = Width; + this->sSvcParam.iPicHeight = Height; + if(sSvcParam.iSpatialLayerNum) + { + SSpatialLayerConfig* pDLayer = &sSvcParam.sSpatialLayers[0]; //reset only the first spatial layer + pDLayer->iVideoWidth = this->sSvcParam.iPicWidth; + pDLayer->iVideoHeight = this->sSvcParam.iPicHeight; + } + if (this->pSVCEncoder->InitializeExt (&sSvcParam)) { + fprintf (stderr, "parse svc parameter config file failed.\n"); + return -1; + } + this->initializationDone = true; + return 0; +} + + +igtlInt32 H264Encoder::InitPic (const void* kpSrc, const int32_t colorspace, const int32_t width, const int32_t height) { + SSourcePicture* pSrcPic = (SSourcePicture*)kpSrc; + + if (NULL == pSrcPic || width == 0 || height == 0) + return 1; + + pSrcPic->iColorFormat = colorspace; + pSrcPic->iPicWidth = width; + pSrcPic->iPicHeight = height; + + //currently encoder only supports videoFormatI420. + if ((colorspace & (~videoFormatVFlip)) != videoFormatI420) + return 2; + switch (colorspace & (~videoFormatVFlip)) { + case videoFormatI420: + case videoFormatYV12: + pSrcPic->pData[0] = NULL; + pSrcPic->pData[1] = NULL; + pSrcPic->pData[2] = NULL; + pSrcPic->pData[3] = NULL; + pSrcPic->iStride[0] = width; + pSrcPic->iStride[2] = pSrcPic->iStride[1] = width >> 1; + pSrcPic->iStride[3] = 0; + break; + case videoFormatYUY2: + case videoFormatYVYU: + case videoFormatUYVY: + pSrcPic->pData[0] = NULL; + pSrcPic->pData[1] = NULL; + pSrcPic->pData[2] = NULL; + pSrcPic->pData[3] = NULL; + pSrcPic->iStride[0] = CALC_BI_STRIDE (width, 16); + pSrcPic->iStride[3] = pSrcPic->iStride[2] = pSrcPic->iStride[1] = 0; + break; + case videoFormatRGB: + case videoFormatBGR: + pSrcPic->pData[0] = NULL; + pSrcPic->pData[1] = NULL; + pSrcPic->pData[2] = NULL; + pSrcPic->pData[3] = NULL; + pSrcPic->iStride[0] = CALC_BI_STRIDE (width, 24); + pSrcPic->iStride[3] = pSrcPic->iStride[2] = pSrcPic->iStride[1] = 0; + if (colorspace & videoFormatVFlip) + pSrcPic->iColorFormat = colorspace & (~videoFormatVFlip); + else + pSrcPic->iColorFormat = colorspace | videoFormatVFlip; + break; + case videoFormatBGRA: + case videoFormatRGBA: + case videoFormatARGB: + case videoFormatABGR: + pSrcPic->pData[0] = NULL; + pSrcPic->pData[1] = NULL; + pSrcPic->pData[2] = NULL; + pSrcPic->pData[3] = NULL; + pSrcPic->iStride[0] = width << 2; + pSrcPic->iStride[3] = pSrcPic->iStride[2] = pSrcPic->iStride[1] = 0; + if (colorspace & videoFormatVFlip) + pSrcPic->iColorFormat = colorspace & (~videoFormatVFlip); + else + pSrcPic->iColorFormat = colorspace | videoFormatVFlip; + break; + default: + return 2; // any else? + } + + return 0; +} + +int H264Encoder::ConvertToLocalImageFormat(SourcePicture* pSrcPic) +{ + if(pSrcPic->colorFormat==FormatI420) + { + if((pSrcPic->picWidth != this->h264SrcPicture.iPicWidth || pSrcPic->picHeight != this->h264SrcPicture.iPicHeight)) + { + InitPic (&this->h264SrcPicture, videoFormatI420, pSrcPic->picWidth, pSrcPic->picHeight); + } + for(int i = 0; i < 4; i++) + { + h264SrcPicture.iStride[i] = pSrcPic->stride[i]; + h264SrcPicture.pData[i] = pSrcPic->data[i]; + } + h264SrcPicture.iPicWidth = pSrcPic->picWidth; + h264SrcPicture.iPicHeight = pSrcPic->picHeight; + return 1; + } + return -1;// image format not supported +} + + +int H264Encoder::EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage) +{ + int encodeRet = -1; + int iSourceWidth = pSrcPic->picWidth; + int iSourceHeight = pSrcPic->picHeight; + if (iSourceWidth != this->sSvcParam.iPicWidth || iSourceHeight != this->sSvcParam.iPicHeight) + { + this->SetPicWidthAndHeight(iSourceWidth, iSourceHeight); + this->InitializeEncoder(); + } + if (this->initializationDone == true) + { + pSrcPic->stride[0] = iSourceWidth; + pSrcPic->stride[1] = pSrcPic->stride[2] = pSrcPic->stride[0] >> 1; + int frameSize = 0; + int iLayer = 0; + this->ConvertToLocalImageFormat(pSrcPic); + encodeRet = pSVCEncoder->EncodeFrame(&h264SrcPicture, &sFbi); + videoMessage->SetBitStreamSize(sFbi.iFrameSizeInBytes); + videoMessage->AllocateScalars(); + videoMessage->SetCodecType(IGTL_VIDEO_CODEC_NAME_H264); + videoMessage->SetEndian(igtl_is_little_endian()==true?2:1); //little endian is 2 big endian is 1 + videoMessage->SetWidth(pSrcPic->picWidth); + videoMessage->SetHeight(pSrcPic->picHeight); + if (sFbi.eFrameType == videoFrameTypeIDR) + { + encodedFrameType = FrameTypeKey; + } + else + { + // To do, assign other frame type too. + encodedFrameType = FrameTypeUnKnown; + } + if (isGrayImage) + { + encodedFrameType = sFbi.eFrameType<<8; + } + videoMessage->SetFrameType(encodedFrameType); + while (iLayer < sFbi.iLayerNum) { + SLayerBSInfo* pLayerBsInfo = &sFbi.sLayerInfo[iLayer]; + if (pLayerBsInfo != NULL) { + int iLayerSize = 0; + int iNalIdx = pLayerBsInfo->iNalCount - 1; + do { + iLayerSize += pLayerBsInfo->pNalLengthInByte[iNalIdx]; + -- iNalIdx; + } while (iNalIdx >= 0); + frameSize += iLayerSize; + for (int i = 0; i < iLayerSize ; i++) + { + videoMessage->GetPackFragmentPointer(2)[frameSize-iLayerSize+i] = pLayerBsInfo->pBsBuf[i]; + } + } + ++ iLayer; + } + videoMessage->Pack(); + } + return encodeRet; +}; + +} // Namespace igtl diff --git a/openigtlink/repo/Source/VideoStreaming/igtlH264Encoder.h b/openigtlink/repo/Source/VideoStreaming/igtlH264Encoder.h new file mode 100644 index 0000000..dbb6660 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlH264Encoder.h @@ -0,0 +1,187 @@ +/*========================================================================= + + Program: OpenIGTLink + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +/*! + * \copy + * Copyright (c) 2013, Cisco Systems + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __igtlH264Encoder_h +#define __igtlH264Encoder_h + +#include +#if defined(_WIN32) /*&& defined(_DEBUG)*/ + #include + #include + #include + #include +#else + #include +#endif +#include + +#include +#include +#include +#include + +#include "igtlCodecCommonClasses.h" +#include "igtl_header.h" +#include "igtl_video.h" +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlVideoMessage.h" +#include "igtlTimeStamp.h" +#include "codec_def.h" +#include "codec_app_def.h" + +#define MAX_DEPENDENCY_LAYER 4 +#define MAX_THREADS_NUM 4 +#define EPSN (0.000001f) + +using namespace std; + +class ISVCEncoder; + +namespace igtl { + +typedef struct LayerpEncCtx_s { + int32_t iDLayerQp; + SSliceArgument sSliceArgument; +} SLayerPEncCtx; + +/** + * @brief Enumerate video frame type + * This is H264 related frame types. + */ +typedef enum { + H264FrameTypeInvalid, ///< encoder not ready or parameters are invalidate + H264FrameTypeIDR, ///< IDR frame in H.264 + H264FrameTypeI, ///< I frame type + H264FrameTypeP, ///< P frame type + H264FrameTypeSkip, ///< skip the frame based encoder kernel + H264FrameTypeIPMixed ///< a frame where I and P slices are mixing, not supported yet +} H264VideoFrameType; + + +class IGTLCommon_EXPORT H264Encoder: public GenericEncoder +{ +public: + igtlTypeMacro(H264Encoder, GenericEncoder); + igtlNewMacro(H264Encoder); + + H264Encoder(char * configFile = NULL); + ~H264Encoder(); + + int FillSpecificParameters() override; + + /** + * @brief Enumerate the type of rate control mode + typedef enum { + RC_QUALITY_MODE = 0, ///< quality mode + RC_BITRATE_MODE = 1, ///< bitrate mode + RC_BUFFERBASED_MODE = 2, ///< no bitrate control,only using buffer status,adjust the video quality + RC_TIMESTAMP_MODE = 3, //rate control based timestamp + RC_BITRATE_MODE_POST_SKIP = 4, ///< this is in-building RC MODE, WILL BE DELETED after algorithm tuning! + RC_OFF_MODE = -1, ///< rate control off mode + } RC_MODES; + */ + int SetRCMode(int value) override; + + int SetKeyFrameDistance(int frameNum) override {return -1;}; + + int SetQP(int maxQP, int minQP) override; + + /** + Parse the configuration file to initialize the encoder and server. + */ + int InitializeEncoder() override; + + int ConvertToLocalImageFormat(SourcePicture* pSrcPic) override; + + /** + Encode a frame, for performance issue, before encode the frame, make sure the frame pointer is updated with a new frame. + Otherwize, the old frame will be encoded. + */ + int EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage = false ) override; + + int SetPicWidthAndHeight(unsigned int Width, unsigned int Height) override; + + unsigned int GetPicWidth() override {return this->sSvcParam.iPicWidth;}; + + unsigned int GetPicHeight() override {return this->sSvcParam.iPicHeight;}; + + int SetLosslessLink(bool linkMethod) override; + + /** + typedef enum { + LOW_COMPLEXITY, ///< the lowest compleixty,the fastest speed, + MEDIUM_COMPLEXITY, ///< medium complexity, medium speed,medium quality + HIGH_COMPLEXITY ///< high complexity, lowest speed, high quality + } ECOMPLEXITY_MODE; + */ + int SetSpeed(int speed) override; + + int SetRCTaregetBitRate(unsigned int bitRate) override; + + bool GetLosslessLink() override {return this->sSvcParam.bIsLosslessLink;}; + +private: + int ParseLayerConfig (string strTag[], const int iLayer, SEncParamExt& pSvcParam); + + int ParseConfig(); + + igtlInt32 InitPic (const void* kpSrc, const int32_t colorspace, const int32_t width, const int32_t height); + + ISVCEncoder* pSVCEncoder; + + SEncParamExt sSvcParam; + + std::string layerConfigFiles[MAX_DEPENDENCY_LAYER]; + // for configuration file + + SFrameBSInfo sFbi; + + SSourcePicture h264SrcPicture; + +}; + + +}//Namespace igtl +#endif diff --git a/openigtlink/repo/Source/VideoStreaming/igtlH265Decoder.cxx b/openigtlink/repo/Source/VideoStreaming/igtlH265Decoder.cxx new file mode 100644 index 0000000..9362c49 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlH265Decoder.cxx @@ -0,0 +1,168 @@ +/*========================================================================= + + Program: H265Encoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlH265Decoder.h" + +namespace igtl { + + +H265Decoder::H265Decoder() +{ + this->nb_pthreads = 4; + openHevcHandle = libOpenHevcInit(this->nb_pthreads, MULTITHREAD_SLICE/*, pFormatCtx*/); + libOpenHevcSetCheckMD5(openHevcHandle, false); + libOpenHevcSetDebugMode(openHevcHandle, 0); + libOpenHevcStartDecoder(openHevcHandle); + openHevcFrame.pvY = NULL; + openHevcFrame.pvU = NULL; + openHevcFrame.pvV = NULL; +} + +H265Decoder::~H265Decoder() +{ + libOpenHevcClose(openHevcHandle); + if(openHevcFrame.pvY) { + free(openHevcFrame.pvY); + free(openHevcFrame.pvU); + free(openHevcFrame.pvV); + } +} + +void H265Decoder::ComposeByteSteam(igtl_uint8** inputData, int dimension[2], int iStride[2], igtl_uint8 *outputFrame) +{ + int iWidth = dimension[0]; + int iHeight = dimension[1]; +#pragma omp parallel for default(none) shared(outputByteStream,inputData, iStride, iHeight, iWidth) + for (int i = 0; i < iHeight; i++) + { + igtl_uint8* pPtr = inputData[0]+i*iStride[0]; + for (int j = 0; j < iWidth; j++) + { + outputFrame[i*iWidth + j] = pPtr[j]; + } + } +#pragma omp parallel for default(none) shared(outputByteStream,inputData, iStride, iHeight, iWidth) + for (int i = 0; i < iHeight/2; i++) + { + igtl_uint8* pPtr = inputData[1]+i*iStride[1]; + for (int j = 0; j < iWidth/2; j++) + { + outputFrame[i*iWidth/2 + j + iHeight*iWidth] = pPtr[j]; + } + } +#pragma omp parallel for default(none) shared(outputByteStream, inputData, iStride, iHeight, iWidth) + for (int i = 0; i < iHeight/2; i++) + { + igtl_uint8* pPtr = inputData[2]+i*iStride[1]; + for (int j = 0; j < iWidth/2; j++) + { + outputFrame[i*iWidth/2 + j + iHeight*iWidth*5/4] = pPtr[j]; + } + } +} + + +int H265Decoder::DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* pDecodedPic) +{ + if(videoMessage->GetBitStreamSize()) + { + igtl_int32 iWidth = videoMessage->GetWidth(); + igtl_int32 iHeight = videoMessage->GetHeight(); + igtl_uint64 iStreamSize = videoMessage->GetBitStreamSize(); + igtl_uint16 frameType = videoMessage->GetFrameType(); + isGrayImage = false; + if (frameType>0X00FF) + { + frameType= frameType>>8; + isGrayImage = true; + } + pDecodedPic->picWidth = iWidth; + pDecodedPic->picHeight = iHeight; + pDecodedPic->data[1]= pDecodedPic->data[0] + iWidth*iHeight; + pDecodedPic->data[2]= pDecodedPic->data[1] + iWidth*iHeight/4; + pDecodedPic->stride[0] = iWidth; + pDecodedPic->stride[1] = pDecodedPic->stride[2] = iWidth>>1; + pDecodedPic->stride[3] = 0; + igtl_uint32 dimensions[2] = {static_cast(iWidth), static_cast(iHeight)}; + return this->DecodeBitStreamIntoFrame(videoMessage->GetPackFragmentPointer(2), pDecodedPic->data[0], dimensions, iStreamSize); + } + return -1; +} + +int H265Decoder::DecodeBitStreamIntoFrame(unsigned char* kpH265BitStream,igtl_uint8* outputFrame, igtl_uint32 dimensions[2], igtl_uint64& iStreamSize) +{ + static int timePts = 0; + timePts++; + int got_picture = libOpenHevcDecode(openHevcHandle, kpH265BitStream, iStreamSize, timePts); + if (got_picture > 0) { + libOpenHevcGetPictureInfo(openHevcHandle, &openHevcFrame.frameInfo); + if ((dimensions[0] != openHevcFrame.frameInfo.nWidth) || (dimensions[1] != openHevcFrame.frameInfo.nHeight) || openHevcFrame.pvY==NULL) { + openHevcFrame.frameInfo.nWidth = dimensions[0]; + openHevcFrame.frameInfo.nHeight = dimensions[1]; + if(openHevcFrame.pvY) { + free(openHevcFrame.pvY); + free(openHevcFrame.pvU); + free(openHevcFrame.pvV); + } + int format = openHevcFrame.frameInfo.chromat_format == YUV420 ? 1 : 0; + openHevcFrame.pvY = calloc (openHevcFrame.frameInfo.nYPitch * openHevcFrame.frameInfo.nHeight, sizeof(unsigned char)); + openHevcFrame.pvU = calloc (openHevcFrame.frameInfo.nUPitch * openHevcFrame.frameInfo.nHeight >> format, sizeof(unsigned char)); + openHevcFrame.pvV = calloc (openHevcFrame.frameInfo.nVPitch * openHevcFrame.frameInfo.nHeight >> format, sizeof(unsigned char)); + } + libOpenHevcGetOutputCpy(openHevcHandle, 1, &openHevcFrame); + ReconstructFrame(&openHevcFrame, outputFrame); + return 1; + } + return -1; +} + +int H265Decoder::ReconstructFrame(OpenHevc_Frame_cpy *openHevcFrame,igtl_uint8* outputFrame) +{ + int y; + int y_offset, y_offset2; + int height, format, width; + int src_stride; + int dst_stride; + int src_stride_c; + int dst_stride_c; + + format = openHevcFrame->frameInfo.chromat_format == YUV420 ? 1 : 0; + src_stride = openHevcFrame->frameInfo.nYPitch; + src_stride_c = openHevcFrame->frameInfo.nUPitch; + height = openHevcFrame->frameInfo.nHeight; + width = openHevcFrame->frameInfo.nWidth;; + dst_stride = openHevcFrame->frameInfo.nWidth; + dst_stride_c = openHevcFrame->frameInfo.nWidth>>1; + y_offset = y_offset2 = 0; + + for (y = 0; y < height; y++) + { + memcpy(outputFrame+y_offset2, ((char*)openHevcFrame->pvY)+y_offset, dst_stride); + y_offset += src_stride; + y_offset2 += dst_stride; + } + + y_offset = y_offset2 = 0; + + for (y = 0; y < height >> format; y++) + { + memcpy(outputFrame+y_offset2+width*height, ((char*)openHevcFrame->pvU)+y_offset, dst_stride_c); + memcpy(outputFrame+y_offset2+width*height*5/4, ((char*)openHevcFrame->pvV)+y_offset, dst_stride_c); + y_offset += src_stride_c; + y_offset2 += dst_stride_c; + } + return 1; +} + +}// namespace igtl + diff --git a/openigtlink/repo/Source/VideoStreaming/igtlH265Decoder.h b/openigtlink/repo/Source/VideoStreaming/igtlH265Decoder.h new file mode 100644 index 0000000..b01e4ce --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlH265Decoder.h @@ -0,0 +1,79 @@ +/*========================================================================= + + Program: H265Encoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ +#ifndef __igtlH265Decoder_h +#define __igtlH265Decoder_h + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +#include +#include +#include +#include +#include "igtl_types.h" +#include "igtlVideoMessage.h" +#include "igtlCodecCommonClasses.h" + +#include "openHevcWrapper.h" + +#define FRAME_CONCEALMENT 0 + +namespace igtl { + + class IGTLCommon_EXPORT H265Decoder:public GenericDecoder + { + public: + igtlTypeMacro(H265Decoder, GenericDecoder); + igtlNewMacro(H265Decoder); + + H265Decoder(); + ~H265Decoder(); + + typedef struct Info { + int NbFrame; + int Poc; + int Tid; + int Qid; + int type; + int size; + } Info; + + enum { + MULTITHREAD_FRAME = 1, ///< Put frames into multiple threads + MULTITHREAD_SLICE = 2, ///< Put slices of a frame into multiple threads + MULTITHREAD_FRAME_SLICE = 4 ///< Put slices of multiple frames into multiple threads + }; + + int DecodeBitStreamIntoFrame(unsigned char* bitStream,igtl_uint8* outputFrame, igtl_uint32 iDimensions[2], igtl_uint64 &iStreamSize) override; + + int DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* pDecodedPic) override; + + private: + + void ComposeByteSteam(igtl_uint8** inputData, int dimension[2], int iStride[2], igtl_uint8 *outputFrame) override; + + int ReconstructFrame(OpenHevc_Frame_cpy *openHevcFrame,igtl_uint8* outputFrame); + + OpenHevc_Handle openHevcHandle; + + OpenHevc_Frame_cpy openHevcFrame; + + int nb_pthreads; + + }; + +} // namespace igtl + +#endif \ No newline at end of file diff --git a/openigtlink/repo/Source/VideoStreaming/igtlH265Encoder.cxx b/openigtlink/repo/Source/VideoStreaming/igtlH265Encoder.cxx new file mode 100644 index 0000000..9490a29 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlH265Encoder.cxx @@ -0,0 +1,279 @@ +/*========================================================================= + + Program: H265Encoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlH265Encoder.h" +#include "igtlVideoMessage.h" +#include + +namespace igtl { + +template +std::string ToString(T variable) +{ + stringstream stream; + stream << variable; + return stream.str(); +} + +H265Encoder::H265Encoder(char *configFile):GenericEncoder() +{ + this->sSvcParam=x265_param_alloc(); + FillSpecificParameters(); + pSVCEncoder=x265_encoder_open(this->sSvcParam); + H265SrcPicture = x265_picture_alloc(); + x265_picture_init(sSvcParam,H265SrcPicture); + pNals = NULL; + this->codecSpeed = 9; +} + +H265Encoder::~H265Encoder() +{ + x265_encoder_close(this->pSVCEncoder); + x265_picture_free(this->H265SrcPicture); + x265_param_free(this->sSvcParam); + this->pNals = NULL; + this->pSVCEncoder = NULL; + this->H265SrcPicture = NULL; + this->sSvcParam = NULL; +} + +int H265Encoder::FillSpecificParameters() { + /* Test for temporal, spatial, SNR scalability */ + + x265_param_default_preset(this->sSvcParam,ToString(9-this->codecSpeed).c_str(),"zerolatency");// second parameter is the speed. + this->sSvcParam->internalCsp=X265_CSP_I420; + this->sSvcParam->bRepeatHeaders=1;//write sps,pps before keyframe + this->sSvcParam->fpsNum=200; + this->sSvcParam->fpsDenom=1; + this->sSvcParam->sourceWidth=1920; + this->sSvcParam->sourceHeight=1080; + this->sSvcParam->bEnableTemporalSubLayers = false; + this->sSvcParam->maxNumReferences = 1; + this->sSvcParam->maxNumMergeCand = 1; + this->sSvcParam->bLossless = false; + return 0; +} + +int H265Encoder::SetRCTaregetBitRate(unsigned int bitRate) +{ + this->sSvcParam->rc.aqMode = X265_AQ_VARIANCE; + this->sSvcParam->rc.rateControlMode = X265_RC_ABR; + this->sSvcParam->rc.bitrate = bitRate/1000; // bit rate in h265 is represented in kbps + /*for (int i = 0; i < this->sSvcParam.iSpatialLayerNum; i++) + { + this->sSvcParam.sSpatialLayers[i].iSpatialBitrate = bitRate/this->sSvcParam.iSpatialLayerNum; + }*/ + x265_encoder_close(this->pSVCEncoder); + pSVCEncoder=x265_encoder_open(this->sSvcParam); + H265SrcPicture = x265_picture_alloc(); + x265_picture_init(sSvcParam,H265SrcPicture); + /*if (x265_encoder_reconfig(this->pSVCEncoder, sSvcParam)<0) { + fprintf (stderr, "Set target bit rate failed. \n"); + return -1; + }*/ + this->initializationDone = true; + return 0; +} + +int H265Encoder::SetRCMode(int value) +{ + this->sSvcParam->rc.aqMode = X265_AQ_VARIANCE; + this->sSvcParam->rc.rateControlMode = value; //X265_RC_ABR; + if (x265_encoder_reconfig(this->pSVCEncoder, sSvcParam)<0) { + fprintf (stderr, "Set RC mode failed. \n"); + return -1; + } + this->initializationDone = true; + return 0; +} + +int H265Encoder::SetQP(int maxQP, int minQP) +{ + sSvcParam->rc.qpMax= maxQP<51?maxQP:51; + sSvcParam->rc.qpMin = minQP>0?minQP:0; + if (x265_encoder_reconfig(this->pSVCEncoder, sSvcParam)<0) + { + fprintf (stderr, "Set QP value failed.\n"); + return -1; + } + this->initializationDone = true; + return 0; +} + +void H265Encoder::CopySettingToAnother(x265_param* srcSetting, x265_param* dstSetting) +{ + dstSetting->rc.qpMax = srcSetting->rc.qpMax; + dstSetting->rc.qpMin = srcSetting->rc.qpMin; + dstSetting->rc.aqMode = srcSetting->rc.aqMode; + dstSetting->rc.rateControlMode = srcSetting->rc.rateControlMode; + dstSetting->rc.bitrate = srcSetting->rc.bitrate; + dstSetting->sourceWidth = srcSetting->sourceWidth; + dstSetting->sourceHeight = srcSetting->sourceHeight; + dstSetting->internalCsp = srcSetting->internalCsp; + dstSetting->bRepeatHeaders = srcSetting->bRepeatHeaders;//write sps,pps before keyframe + dstSetting->fpsNum = srcSetting->fpsNum; + dstSetting->fpsDenom = srcSetting->fpsDenom; + dstSetting->bEnableTemporalSubLayers = srcSetting->bEnableTemporalSubLayers; + dstSetting->maxNumReferences = srcSetting->maxNumReferences; + dstSetting->maxNumMergeCand = srcSetting->maxNumMergeCand; + dstSetting->bLossless = srcSetting->bLossless; +} + +int H265Encoder::SetSpeed(int speed) +{ + speed = speed>=0?speed:0; + speed = speed<=9?speed:9; + this->codecSpeed = speed; + x265_param* previousSetting = x265_param_alloc(); + + this->CopySettingToAnother(this->sSvcParam, previousSetting); + x265_param_default_preset(this->sSvcParam,ToString(9-speed).c_str(),"zerolatency"); // In OpenIGTLink, lower speed value corresponding to slower coding speed. In x265, the speed setting is reversed. + this->CopySettingToAnother(previousSetting, this->sSvcParam); + x265_param_free(previousSetting); + if (x265_encoder_reconfig(this->pSVCEncoder, sSvcParam)<0) + { + fprintf (stderr, "Set speed mode failed.\n"); + return -1; + } + return 0; +} + +int H265Encoder::InitializeEncoder() +{ + //------------------------------------------------------------ + int iRet = 0; + + if (this->configFile=="" && this->pSVCEncoder) + { + fprintf (stderr, "No configuration file specified. Use Default Parameters\n"); + iRet = x265_encoder_reconfig(this->pSVCEncoder, sSvcParam); + if (iRet<0) + { + fprintf (stderr, "parse svc parameter config file failed.\n"); + return -1; + } + this->initializationDone = true; + return iRet; + } + this->initializationDone = false; + return -1; +} + +int H265Encoder::SetPicWidthAndHeight(unsigned int Width, unsigned int Height) +{ + this->sSvcParam->sourceWidth = Width; + this->sSvcParam->sourceHeight = Height; + if (x265_encoder_reconfig(this->pSVCEncoder, sSvcParam)<0) + { + fprintf (stderr, "parse svc parameter config file failed.\n"); + return -1; + } + x265_picture_init(sSvcParam,H265SrcPicture); + this->initializationDone = true; + return 0; +} + +int H265Encoder::SetLosslessLink(bool linkMethod) +{ + this->sSvcParam->bLossless = linkMethod; + x265_encoder_close(this->pSVCEncoder); + pSVCEncoder=x265_encoder_open(this->sSvcParam); + H265SrcPicture = x265_picture_alloc(); + x265_picture_init(sSvcParam,H265SrcPicture); + return 0; +} + + +int H265Encoder::ConvertToLocalImageFormat(SourcePicture* pSrcPic) +{ + if(pSrcPic->colorFormat==FormatI420) + { + if((pSrcPic->picWidth*pSrcPic->picHeight*3/2 != this->H265SrcPicture->framesize || pSrcPic->picHeight != this->H265SrcPicture->height)) + { + this->SetPicWidthAndHeight(pSrcPic->picWidth, pSrcPic->picHeight); + x265_picture_init(this->sSvcParam, H265SrcPicture); + } + for(int i = 0; i < 3; i++) + { + H265SrcPicture->stride[i] = pSrcPic->stride[i]; + H265SrcPicture->planes[i] = pSrcPic->data[i]; + } + return 1; + } + return -1;// image format not supported +} + + +int H265Encoder::EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage) +{ + int encodeRet = -1; + int iSourceWidth = pSrcPic->picWidth; + int iSourceHeight = pSrcPic->picHeight; + if (iSourceWidth != this->sSvcParam->sourceWidth || iSourceHeight != this->sSvcParam->sourceHeight) + { + this->SetPicWidthAndHeight(iSourceWidth, iSourceHeight); + this->InitializeEncoder(); + } + if (this->initializationDone == true) + { + pSrcPic->stride[0] = iSourceWidth; + pSrcPic->stride[1] = pSrcPic->stride[2] = pSrcPic->stride[0] >> 1; + this->ConvertToLocalImageFormat(pSrcPic); + + igtl_uint32 iNal = 0; + encodeRet =x265_encoder_encode(this->pSVCEncoder,&pNals,&iNal,this->H265SrcPicture,NULL); + //encodeRet =x265_encoder_encode(this->pSVCEncoder,&pNals,&iNal,NULL,NULL); + if (encodeRet>=1) + { + igtl_uint64 totalBitStreamSize = 0; + for(int j=0;jSetFrameType(encodedFrameType); + videoMessage->SetBitStreamSize(totalBitStreamSize); + videoMessage->AllocateScalars(); + videoMessage->SetCodecType(IGTL_VIDEO_CODEC_NAME_X265); + videoMessage->SetEndian(igtl_is_little_endian()==true?2:1); //little endian is 2 big endian is 1 + videoMessage->SetWidth(pSrcPic->picWidth); + videoMessage->SetHeight(pSrcPic->picHeight); + encodedFrameType = pNals[iNal-1].type; + if (isGrayImage) + { + encodedFrameType = pNals[iNal-1].type<<8; + } + videoMessage->SetFrameType(encodedFrameType); + int nalSize = 0; + FILE* testFile = fopen("Test.265", "a"); + for(int j=0;jGetPackFragmentPointer(2)[nalSize]), pNals[j].payload, pNals[j].sizeBytes); + nalSize += pNals[j].sizeBytes; + //fwrite(pNals[j].payload, 1 , pNals[j].sizeBytes, testFile); + } + fclose(testFile); + videoMessage->Pack(); + return 0; + } + } + return -1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/VideoStreaming/igtlH265Encoder.h b/openigtlink/repo/Source/VideoStreaming/igtlH265Encoder.h new file mode 100644 index 0000000..c18203e --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlH265Encoder.h @@ -0,0 +1,140 @@ +/*========================================================================= + + Program: OpenIGTLink + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#ifndef __igtlH265Encoder_h +#define __igtlH265Encoder_h + +#include +#if defined(_WIN32) /*&& defined(_DEBUG)*/ +#include +#include +#include +#include +#include +#else +#include +#endif +#include + +#include +#include +#include +#include + +#include "igtlCodecCommonClasses.h" +#include "igtl_header.h" +#include "igtl_video.h" +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlVideoMessage.h" +#include "igtlTimeStamp.h" + +#if defined ( __cplusplus) + extern "C" + { +#include "x265.h" + }; +#else +#include "x265.h" +#endif + +using namespace std; + +namespace igtl { + +/** + * @brief Enumerate video frame type + * This is H265 related frame types. + */ +typedef enum { + H265FrameTypeInvalid, ///< encoder not ready or parameters are invalidate + H265FrameTypeIDR, ///< IDR frame in H.264 + H265FrameTypeI, ///< I frame type + H265FrameTypeP, ///< P frame type + H265FrameTypeSkip, ///< skip the frame based encoder kernel + H265FrameTypeIPMixed ///< a frame where I and P slices are mixing, not supported yet +} H265VideoFrameType; + +class IGTLCommon_EXPORT H265Encoder: public GenericEncoder +{ +public: + igtlTypeMacro(H265Encoder, GenericEncoder); + igtlNewMacro(H265Encoder); + + H265Encoder(char * configFile = NULL); + ~H265Encoder(); + + int FillSpecificParameters() override; + + /** + * @brief Enumerate the type of rate control mode + typedef enum { + RC_QUALITY_MODE = 0, ///< quality mode + RC_BITRATE_MODE = 1, ///< bitrate mode + RC_BUFFERBASED_MODE = 2, ///< no bitrate control,only using buffer status,adjust the video quality + RC_TIMESTAMP_MODE = 3, //rate control based timestamp + RC_BITRATE_MODE_POST_SKIP = 4, ///< this is in-building RC MODE, WILL BE DELETED after algorithm tuning! + RC_OFF_MODE = -1, ///< rate control off mode + } RC_MODES; + */ + int SetRCMode(int value) override; + + int SetKeyFrameDistance(int frameNum) override {return -1;}; + + int SetQP(int maxQP, int minQP) override; + + /** + Parse the configuration file to initialize the encoder and server. + */ + int InitializeEncoder() override; + + int ConvertToLocalImageFormat(SourcePicture* pSrcPic) override; + + /** + Encode a frame, for performance issue, before encode the frame, make sure the frame pointer is updated with a new frame. + Otherwize, the old frame will be encoded. + */ + int EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage = false ) override; + + int SetPicWidthAndHeight(unsigned int Width, unsigned int Height) override; + + unsigned int GetPicWidth() override {return this->sSvcParam->sourceWidth;}; + + unsigned int GetPicHeight() override {return this->sSvcParam->sourceHeight;}; + + int SetLosslessLink(bool linkMethod) override; + + int SetSpeed(int speed) override; + + int SetRCTaregetBitRate(unsigned int bitRate) override; + + bool GetLosslessLink() override {return this->sSvcParam->bLossless;}; + +protected: + + void CopySettingToAnother(x265_param* srcSetting, x265_param* dstSetting); + +private: + + x265_encoder* pSVCEncoder; + + x265_param* sSvcParam; + + x265_nal *pNals; + + x265_picture* H265SrcPicture; + +}; + +} //namespace igtl +#endif \ No newline at end of file diff --git a/openigtlink/repo/Source/VideoStreaming/igtlI420Decoder.cxx b/openigtlink/repo/Source/VideoStreaming/igtlI420Decoder.cxx new file mode 100644 index 0000000..3a8deb7 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlI420Decoder.cxx @@ -0,0 +1,32 @@ +/*========================================================================= + +Program: OpenIGTLink +Language: C++ + +Copyright (c) Insight Software Consortium. All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlI420Decoder.h" + +namespace igtl { + + I420Decoder::I420Decoder() + { + this->deviceName = ""; + } + + I420Decoder::~I420Decoder() + { + } + + int I420Decoder::DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* pDecodedPic) + { + return this->UnpackUncompressedData(videoMessage, pDecodedPic); + } + +}// namespace igtl diff --git a/openigtlink/repo/Source/VideoStreaming/igtlI420Decoder.h b/openigtlink/repo/Source/VideoStreaming/igtlI420Decoder.h new file mode 100644 index 0000000..a9d32ec --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlI420Decoder.h @@ -0,0 +1,40 @@ +/*========================================================================= + +Program: OpenIGTLink +Language: C++ + +Copyright (c) Insight Software Consortium. All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlI420Decoder_h +#define __igtlI420Decoder_h + +#include "igtl_types.h" +#include "igtlVideoMessage.h" +#include "igtlCodecCommonClasses.h" + +namespace igtl { + +#define NO_DELAY_DECODING + class IGTLCommon_EXPORT I420Decoder :public GenericDecoder + { + public: + igtlTypeMacro(I420Decoder, GenericDecoder); + igtlNewMacro(I420Decoder); + + I420Decoder(); + ~I420Decoder(); + + int DecodeBitStreamIntoFrame(unsigned char* bitStream, igtl_uint8* outputFrame, igtl_uint32 iDimensions[2], igtl_uint64 &iStreamSize) override { return -1; }; + int DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* pDecodedPic) override; + + }; + +} // namespace igtl + +#endif diff --git a/openigtlink/repo/Source/VideoStreaming/igtlI420Encoder.cxx b/openigtlink/repo/Source/VideoStreaming/igtlI420Encoder.cxx new file mode 100644 index 0000000..bb5a902 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlI420Encoder.cxx @@ -0,0 +1,34 @@ +/*========================================================================= + + Program: OpenIGTLink + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + + +#include "igtlI420Encoder.h" +#include "igtlVideoMessage.h" + +namespace igtl { + +I420Encoder::I420Encoder(char *configFile):GenericEncoder() +{ +} + +I420Encoder::~I420Encoder() +{ +} + +int I420Encoder::EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage) +{ + videoMessage->SetCodecType(IGTL_VIDEO_CODEC_NAME_I420); + return this->PackUncompressedData(pSrcPic, videoMessage, isGrayImage); +} + +}// namespace igtl diff --git a/openigtlink/repo/Source/VideoStreaming/igtlI420Encoder.h b/openigtlink/repo/Source/VideoStreaming/igtlI420Encoder.h new file mode 100644 index 0000000..8570266 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlI420Encoder.h @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: OpenIGTLink + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlI420Encoder_h +#define __igtlI420Encoder_h + +#include "igtlCodecCommonClasses.h" + +namespace igtl { + +using namespace std; + +class IGTLCommon_EXPORT I420Encoder: public GenericEncoder +{ +public: + igtlTypeMacro(I420Encoder, GenericEncoder); + igtlNewMacro(I420Encoder); + + I420Encoder(char * configFile = NULL); + ~I420Encoder(); + + int InitializeEncoder() override { return 0; }; + + /** + Encode a frame, for performance issue, before encode the frame, make sure the frame pointer is updated with a new frame. + Otherwize, the old frame will be encoded. + */ + int EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage = false ) override; +}; + + +}// Namespace igtl +#endif diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVP9Decoder.cxx b/openigtlink/repo/Source/VideoStreaming/igtlVP9Decoder.cxx new file mode 100644 index 0000000..343c5ae --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVP9Decoder.cxx @@ -0,0 +1,180 @@ +/*========================================================================= + + Program: VPXEncoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlVP9Decoder.h" + +namespace igtl { + +static const VpxInterfaceDecoder vp9StaticDecoder[] = {{&vpx_codec_vp9_dx}}; + +// TODO(dkovalev): move this function to vpx_image.{c, h}, so it will be part +// of vpx_image_t support, this section will be removed when it is moved to vpx_image +int VP9Decoder::vpx_img_plane_width(const vpx_image_t *img, int plane) { + if (plane > 0 && img->x_chroma_shift > 0) + return (img->d_w + 1) >> img->x_chroma_shift; + else + return img->d_w; +} + +int VP9Decoder::vpx_img_plane_height(const vpx_image_t *img, int plane) { + if (plane > 0 && img->y_chroma_shift > 0) + return (img->d_h + 1) >> img->y_chroma_shift; + else + return img->d_h; +} + + +VP9Decoder::VP9Decoder() +{ + decoder = &vp9StaticDecoder[0]; + vpx_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0); + this->deviceName = ""; +} + +VP9Decoder::~VP9Decoder() +{ + vpx_codec_destroy(&codec); + decoder = NULL; +} + +int VP9Decoder::DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* pDecodedPic) +{ + if(videoMessage->GetBitStreamSize()) + { + igtl_int32 iWidth = videoMessage->GetWidth(); + igtl_int32 iHeight = videoMessage->GetHeight(); + igtl_uint64 iStreamSize = videoMessage->GetBitStreamSize(); + pDecodedPic->picWidth = iWidth; + pDecodedPic->picHeight = iHeight; + if (!vpx_codec_decode(&codec, videoMessage->GetPackFragmentPointer(2), (unsigned int)iStreamSize, NULL, 0)) + { + iter = NULL; + if ((outputImage = vpx_codec_get_frame(&codec, &iter)) != NULL) + { + int stride[3] = { outputImage->stride[0], outputImage->stride[1], outputImage->stride[2] }; + int convertedDimensions[2] = { vpx_img_plane_width(outputImage, 0) * + ((outputImage->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1), vpx_img_plane_height(outputImage, 0) }; + if (outputImage->fmt == VPX_IMG_FMT_I420) + { + pDecodedPic->data[1]= pDecodedPic->data[0] + iWidth*iHeight; + pDecodedPic->data[2]= pDecodedPic->data[1] + iWidth*iHeight/4; + pDecodedPic->stride[0] = iWidth; + pDecodedPic->stride[1] = pDecodedPic->stride[2] = iWidth>>1; + pDecodedPic->stride[3] = 0; + ComposeByteSteam(outputImage->planes, convertedDimensions, stride, pDecodedPic->data[0], FormatI420); + } + else if (outputImage->fmt == VPX_IMG_FMT_I444) + { + pDecodedPic->data[1]= pDecodedPic->data[0] + iWidth*iHeight; + pDecodedPic->data[2]= pDecodedPic->data[1] + iWidth*iHeight; + pDecodedPic->stride[0] = iWidth; + pDecodedPic->stride[1] = pDecodedPic->stride[2] = iWidth; + pDecodedPic->stride[3] = 0; + ComposeByteSteam(outputImage->planes, convertedDimensions, stride, pDecodedPic->data[0], FormatI444); + } + else + { + return -1; + } + return 2; + } + } + else + { + vpx_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0); + std::cerr << "decode failed" << std::endl; + } + return -1; + } + return -1; +} + +void VP9Decoder::ComposeByteSteam(igtl_uint8** inputData, int dimension[2], int iStride[3], igtl_uint8 *outputFrame, VideoFormatType format) +{ + int plane; + int dimensionW [3]; + int dimensionH [3]; + if(format==FormatI420) + { + dimensionW [0] = dimension[0]; + dimensionW [1] = dimension[0]/2; + dimensionW [2] = dimension[0]/2; + dimensionH [0] = dimension[1]; + dimensionH [1] = dimension[1]/2; + dimensionH [2] = dimension[1]/2; + } + else if(format==FormatI444) + { + dimensionW [0] = dimension[0]; + dimensionW [1] = dimension[0]; + dimensionW [2] = dimension[0]; + dimensionH [0] = dimension[0]; + dimensionH [1] = dimension[1]; + dimensionH [2] = dimension[1]; + } + else + { + return; + } + int shift = 0; + for (plane = 0; plane < 3; ++plane) + { + const unsigned char *buf = inputData[plane]; + const int stride = iStride[plane]; + int w = dimensionW[plane]; + int h = dimensionH[plane]; + int y; + for (y = 0; y < h; ++y) + { + memcpy(outputFrame+shift + w*y, buf, w); + buf += stride; + } + shift += w*h; + } +} + + +int VP9Decoder::DecodeBitStreamIntoFrame(unsigned char* bitstream,igtl_uint8* outputFrame, igtl_uint32 dimensions[2], igtl_uint64& iStreamSize) +{ + if (!vpx_codec_decode(&codec, bitstream, (unsigned int)iStreamSize, NULL, 0)) + { + iter = NULL; + if ((outputImage = vpx_codec_get_frame(&codec, &iter)) != NULL) + { + int stride[3] = { outputImage->stride[0], outputImage->stride[1], outputImage->stride[2] }; + int convertedDimensions[2] = { vpx_img_plane_width(outputImage, 0) * + ((outputImage->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1), vpx_img_plane_height(outputImage, 0) }; + if (outputImage->fmt == VPX_IMG_FMT_I420) + { + ComposeByteSteam(outputImage->planes, convertedDimensions, stride, outputFrame, FormatI420); + } + else if (outputImage->fmt == VPX_IMG_FMT_I444) + { + ComposeByteSteam(outputImage->planes, convertedDimensions, stride, outputFrame, FormatI444); + } + else + { + return -1; + } + return 2; + } + } + else + { + vpx_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0); + std::cerr << "decode failed" << std::endl; + } + return -1; +} + +}// namespace igtl diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVP9Decoder.h b/openigtlink/repo/Source/VideoStreaming/igtlVP9Decoder.h new file mode 100644 index 0000000..021318d --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVP9Decoder.h @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: VPXEncoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#ifndef __igtlVP9Decoder_h +#define __igtlVP9Decoder_h + +#include +#if defined(_WIN32) /*&& defined(_DEBUG)*/ + #include + #include + #include + #include +#else + #include +#endif + +#include +#include +#include +#include "igtl_types.h" +#include "igtlVideoMessage.h" +#include "igtlCodecCommonClasses.h" +#include "vpx_decoder.h" +#include "vp8dx.h" +#include "vpx_codec.h" +#include "vpx_image.h" +#include "vpx_integer.h" + +namespace igtl { + + +#ifdef __cplusplus +extern "C" { +#endif + typedef struct VpxInterfaceDecoder { + vpx_codec_iface_t *(*const codec_interface)(); + } VpxInterfaceDecoder; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#define NO_DELAY_DECODING +class IGTLCommon_EXPORT VP9Decoder:public GenericDecoder +{ +public: + igtlTypeMacro(VP9Decoder, GenericDecoder); + igtlNewMacro(VP9Decoder); + + VP9Decoder(); + ~VP9Decoder(); + + int DecodeBitStreamIntoFrame(unsigned char* bitStream,igtl_uint8* outputFrame, igtl_uint32 iDimensions[2], igtl_uint64 &iStreamSize) override; + + int DecodeVideoMSGIntoSingleFrame(igtl::VideoMessage* videoMessage, SourcePicture* pDecodedPic) override; + +private: + using GenericDecoder::ComposeByteSteam; // disable the clang warning about virtual function overload. + virtual void ComposeByteSteam(igtl_uint8** inputData, int dimension[2], int iStride[2], igtl_uint8 *outputFrame, VideoFormatType format); + + const VpxInterfaceDecoder* decoder; + + int vpx_img_plane_width(const vpx_image_t *img, int plane); + + int vpx_img_plane_height(const vpx_image_t *img, int plane); + + vpx_codec_ctx_t codec; + + vpx_image_t* outputImage; + + vpx_codec_iter_t iter; + +}; + +} // namespace igtl + +#endif diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVP9Encoder.cxx b/openigtlink/repo/Source/VideoStreaming/igtlVP9Encoder.cxx new file mode 100644 index 0000000..8e384ac --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVP9Encoder.cxx @@ -0,0 +1,335 @@ +/*========================================================================= + + Program: VP9Encoder + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + + +#include "igtlVP9Encoder.h" +#include "igtlVideoMessage.h" + +namespace igtl { + + +static const VpxInterfaceEncoder vp9StaticEncoder[] = {{&vpx_codec_vp9_cx}}; + +void VP9Encoder::error_output(vpx_codec_ctx_t *ctx, const char *s) { + const char *detail = vpx_codec_error_detail(ctx); + + printf("%s: %s\n", s, vpx_codec_error(ctx)); + if (detail) printf(" %s\n", detail); + exit(EXIT_FAILURE); +} + + +// TODO(dkovalev): move this function to vpx_image.{c, h}, so it will be part +// of vpx_image_t support, this section will be removed when it is moved to vpx_image +int VP9Encoder::vpx_img_plane_width(const vpx_image_t *img, int plane) { + if (plane > 0 && img->x_chroma_shift > 0) + return (img->d_w + 1) >> img->x_chroma_shift; + else + return img->d_w; +} + +int VP9Encoder::vpx_img_plane_height(const vpx_image_t *img, int plane) { + if (plane > 0 && img->y_chroma_shift > 0) + return (img->d_h + 1) >> img->y_chroma_shift; + else + return img->d_h; +} + + +VP9Encoder::VP9Encoder(char *configFile):GenericEncoder() +{ + this->encoder = &vp9StaticEncoder[0]; + codec = new vpx_codec_ctx_t(); + encodedBuf = new vpx_fixed_buf_t(); + inputImage = new vpx_image_t(); + deadlineMode = VPX_DL_REALTIME; + isLossLessLink = true; + codecSpeed = 0; + FillSpecificParameters (); + SetImageFormat(FormatI420); +} + +VP9Encoder::~VP9Encoder() +{ + vpx_codec_encode(codec, NULL, -1, 1, 0, deadlineMode); //Flush the codec + vpx_codec_destroy(codec); + if (inputImage) + { + delete inputImage; + } + if(this->encoder) + { + this->encoder = NULL; + } +} + +int VP9Encoder::FillSpecificParameters() { + if (vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0)) + { + error_output(codec, "Failed to get default codec config."); + return -1; + } + cfg.g_error_resilient = true; + vpx_codec_enc_init(codec, encoder->codec_interface(), &cfg, 0); + if(this->SetSpeed(FastestSpeed)!=0) + { + error_output(codec, "Failed to set the speed to be the fastest."); + return -1; + } + return 0; +} + +int VP9Encoder::SetRCMode(int value) +{ + this->cfg.rc_end_usage = (vpx_rc_mode) value; + if(vpx_codec_enc_config_set(codec, &this->cfg)) + { + error_output(codec, "Failed to set RC mode"); + return -1; + } + return 0; +} + +int VP9Encoder::SetImageFormat(VideoFormatType value) +{ + if (value == FormatI420) + { + this->cfg.g_profile = 0; + inputImage->fmt = VPX_IMG_FMT_I420; + } + else if (value == FormatI444) + { + this->cfg.g_profile = 1; + inputImage->fmt = VPX_IMG_FMT_I444; + } + else + { + error_output(codec, "Not supported image format"); + return -1; + } + return 0; +} + +int VP9Encoder::SetKeyFrameDistance(int frameNum) +{ + this->cfg.kf_max_dist = frameNum; + this->cfg.kf_min_dist = frameNum; + if(vpx_codec_enc_config_set(codec, &this->cfg)) + { + error_output(codec, "Failed to key frame distance"); + return -1; + } + return 0; +} + + +int VP9Encoder::SetRCTaregetBitRate(unsigned int bitRate) +{ + // The bit rate in VPX is in Kilo + int bitRateInKilo = bitRate/1000; + this->cfg.rc_target_bitrate = bitRateInKilo; + this->cfg.layer_target_bitrate[0] = bitRateInKilo; + for (unsigned int i = 0; i < this->cfg.ss_number_layers; i++) + { + this->cfg.ss_target_bitrate[i] = bitRateInKilo/this->cfg.ss_number_layers; + } + if (vpx_codec_enc_config_set(codec, &this->cfg)) + { + error_output(codec, "Failed to set target bit rate"); + return -1; + } + this->initializationDone = true; + return 0; +} + +int VP9Encoder::SetQP(int maxQP, int minQP) +{ + this->cfg.rc_max_quantizer = maxQP<63?maxQP:63; + this->cfg.rc_min_quantizer = minQP>0?minQP:0; + this->cfg.rc_end_usage = VPX_Q; + if (vpx_codec_enc_config_set(codec, &this->cfg)) + { + error_output(codec, "Failed to set QP"); + return -1; + } + this->initializationDone = true; + return 0; +} + +int VP9Encoder::SetLosslessLink(bool linkMethod) +{ + this->SetDeadlineMode(VPX_DL_GOOD_QUALITY); + this->isLossLessLink = linkMethod; + if (vpx_codec_control_(codec, VP9E_SET_LOSSLESS, linkMethod)) + { + error_output(codec, "Failed to set lossless mode"); + return -1; + } + else + { + this->cfg.rc_end_usage = VPX_VBR; + return 0; + } +} + +int VP9Encoder::SetSpeed(int speed) +{ + this->SetDeadlineMode(VPX_DL_REALTIME); + this->codecSpeed = speed; + if (speed>=SlowestSpeed && speed<=FastestSpeed) + { + vpx_codec_control(codec, VP8E_SET_CPUUSED, speed); + return 0; + } + return -1; +} + +int VP9Encoder::InitializeEncoder() +{ + cfg.g_lag_in_frames = 0; + cfg.g_w = this->GetPicWidth(); + cfg.g_h = this->GetPicHeight(); + if (inputImage->fmt == VPX_IMG_FMT_NONE) + { + return -1; + } + vpx_img_alloc(inputImage, inputImage->fmt, cfg.g_w, + cfg.g_h, 1); + if (vpx_codec_enc_init(codec, encoder->codec_interface(), &cfg, 0)) + { + error_output(codec, "Failed to initialize encoder"); + return -1; + } + + if (vpx_codec_control_(codec, VP9E_SET_LOSSLESS, this->GetLosslessLink())) + { + error_output(codec, "Failed to set lossless mode"); + return -1; + } + + if (codecSpeed >= SlowestSpeed && codecSpeed <= FastestSpeed) + { + if (vpx_codec_control(codec, VP8E_SET_CPUUSED, codecSpeed)) + { + error_output(codec, "Failed to set Speed"); + return -1; + } + } + this->initializationDone = true; + return 0; +} + +int VP9Encoder::SetPicWidthAndHeight(unsigned int width, unsigned int height) +{ + this->picWidth = width; + this->picHeight = height; + if(this->picHeight != this->cfg.g_h || this->picWidth != this->cfg.g_w ) + { + bool iRet = (this->InitializeEncoder() == 1); + if(iRet==0) + { + return 0; + } + } + return 0; +} + +int VP9Encoder::SetDeadlineMode(unsigned long mode) +{ + this->deadlineMode = mode; + return 0; +} + +int VP9Encoder::ConvertToLocalImageFormat(SourcePicture* pSrcPic) +{ + if (pSrcPic->picWidth != this->cfg.g_w || pSrcPic->picHeight != this->cfg.g_h) + { + this->SetPicWidthAndHeight(pSrcPic->picWidth,pSrcPic->picHeight); + this->InitializeEncoder(); + } + int plane; + for (plane = 0; plane < 3; ++plane) + { + unsigned char *buf ; + const int w = vpx_img_plane_width(inputImage, plane) * + ((inputImage->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); + const int h = vpx_img_plane_height(inputImage, plane); + buf = inputImage->planes[plane]; + memcpy(buf, pSrcPic->data[plane], w*h); + } + + return 1; +} + +int VP9Encoder::EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage) +{ + int iSourceWidth = pSrcPic->picWidth; + int iSourceHeight = pSrcPic->picHeight; + if (iSourceWidth != this->cfg.g_w || iSourceHeight != this->cfg.g_h) + { + this->SetPicWidthAndHeight(iSourceWidth,iSourceHeight); + } + if (this->initializationDone == true) + { + static igtl_uint32 messageID = 6; + messageID ++; + this->ConvertToLocalImageFormat(pSrcPic); + const vpx_codec_err_t res2 = vpx_codec_encode(codec, inputImage, messageID, 1, 0, this->deadlineMode); + if (res2 != VPX_CODEC_OK) + { + error_output(codec, "Failed to encode frame"); + return -1; + } + iter = NULL; + while ((pkt = vpx_codec_get_cx_data(codec, &iter)) != NULL) + { + if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) + { + if((pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0) + { + encodedFrameType = FrameTypeKey; + } + else + { + // To do, assign other frame type too. + encodedFrameType = FrameTypeUnKnown; + } + videoMessage->SetFrameType(encodedFrameType); + videoMessage->SetBitStreamSize(pkt->data.frame.sz); + videoMessage->AllocateScalars(); + videoMessage->SetCodecType(IGTL_VIDEO_CODEC_NAME_VP9); + int endian = (igtl_is_little_endian() == 1 ? IGTL_VIDEO_ENDIAN_LITTLE : IGTL_VIDEO_ENDIAN_BIG); + videoMessage->SetEndian(endian); //little endian is 2 big endian is 1 + videoMessage->SetWidth(pSrcPic->picWidth); + videoMessage->SetHeight(pSrcPic->picHeight); + if (isGrayImage) + { + encodedFrameType = encodedFrameType << 8; + } + videoMessage->SetFrameType(encodedFrameType); + memcpy(videoMessage->GetPackFragmentPointer(2), pkt->data.frame.buf, pkt->data.frame.sz); + videoMessage->Pack(); + } + } + if (videoMessage->GetBitStreamSize()) + { + return 0; + } + } + return -1; +} + + +}// namespace igtl + + diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVP9Encoder.h b/openigtlink/repo/Source/VideoStreaming/igtlVP9Encoder.h new file mode 100644 index 0000000..42045ee --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVP9Encoder.h @@ -0,0 +1,135 @@ +/*========================================================================= + + Program: OpenIGTLink + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlVP9Encoder_h +#define __igtlVP9Encoder_h + +#include +#include +#include + +#include "vp8cx.h" +#include "vpx_image.h" + +#include "igtlCodecCommonClasses.h" +#include "igtl_header.h" +#include "igtl_video.h" +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlVideoMessage.h" +#include "igtlTimeStamp.h" + +namespace igtl { + +#ifdef __cplusplus +extern "C" { +#endif + typedef struct VpxInterfaceEncoder { + vpx_codec_iface_t *(*const codec_interface)(); + } VpxInterfaceEncoder; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +using namespace std; + +class IGTLCommon_EXPORT VP9Encoder: public GenericEncoder +{ +public: + igtlTypeMacro(VP9Encoder, GenericEncoder); + igtlNewMacro(VP9Encoder); + + VP9Encoder(char * configFile = NULL); + ~VP9Encoder(); + + int FillSpecificParameters() override; + + /** + Parse the configuration file to initialize the encoder and server. + */ + int InitializeEncoder() override; + + int ConvertToLocalImageFormat(SourcePicture* pSrcPic) override; + + /** + Encode a frame, for performance issue, before encode the frame, make sure the frame pointer is updated with a new frame. + Otherwize, the old frame will be encoded. + */ + int EncodeSingleFrameIntoVideoMSG(SourcePicture* pSrcPic, igtl::VideoMessage* videoMessage, bool isGrayImage = false ) override; + + int SetPicWidthAndHeight(unsigned int width, unsigned int height) override; + + unsigned int GetPicWidth() override {return this->picWidth;}; + + unsigned int GetPicHeight() override {return this->picHeight;}; + + int SetRCMode(int value) override; + + virtual int SetImageFormat(VideoFormatType value); + + int SetKeyFrameDistance(int frameNum) override; + + int SetQP(int maxQP, int minQP) override; + + int SetRCTaregetBitRate(unsigned int bitRate) override; + + int SetLosslessLink(bool linkMethod) override; + + /* Speed value Should be set between -8 to 8 for VP9. + Values greater than 0 will increase encoder speed at the expense of quality. + negative value is not used.*/ + enum + { + SlowestSpeed = 0, + FastestSpeed = 8 + }; + int SetSpeed(int speed) override; + + /*!\brief deadline parameter analogous to VPx REALTIME mode. */ + //#define VPX_DL_REALTIME (1) + /*!\brief deadline parameter analogous to VPx GOOD QUALITY mode. */ + //#define VPX_DL_GOOD_QUALITY (1000000) + /*!\brief deadline parameter analogous to VPx BEST QUALITY mode. */ + //#define VPX_DL_BEST_QUALITY (0) + /*!\brief Encode a frame*/ + int SetDeadlineMode(unsigned long mode); + +private: + + const VpxInterfaceEncoder *encoder; + + void error_output(vpx_codec_ctx_t *ctx, const char *s); + + int vpx_img_plane_width(const vpx_image_t *img, int plane); + + int vpx_img_plane_height(const vpx_image_t *img, int plane); + + vpx_codec_enc_cfg_t cfg; + + vpx_codec_ctx_t* codec; + + vpx_image_t* inputImage; + + vpx_codec_iter_t iter; + + const vpx_fixed_buf_t *encodedBuf; + + const vpx_codec_cx_pkt_t *pkt; + + unsigned long deadlineMode; + +}; + + +}// Namespace igtl +#endif diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVideoMessage.cxx b/openigtlink/repo/Source/VideoStreaming/igtlVideoMessage.cxx new file mode 100755 index 0000000..dc83b7a --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVideoMessage.cxx @@ -0,0 +1,576 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlVideoMessage.h" + +#include + +namespace igtl { + + + StartVideoMessage::~StartVideoMessage() + { + } + + int StartVideoMessage::GetBodyPackSize() + { + return IGTL_STT_VIDEO_SIZE; + } + + igtlUint64 StartVideoMessage::CalculateContentBufferSize() + { + return IGTL_STT_VIDEO_SIZE; + } + + int StartVideoMessage::PackContent() + { + AllocatePack(); + + igtl_stt_video* stt_video = (igtl_stt_video*)this->m_Content; + strncpy(stt_video->codec, this->m_CodecType.c_str(), IGTL_VIDEO_CODEC_NAME_SIZE); + stt_video->time_interval = this->m_TimeInterval; + + igtl_stt_video_convert_byte_order(stt_video); + + return 1; + + } + + + int StartVideoMessage::UnpackContent() + { + igtl_stt_video* stt_video = (igtl_stt_video*)this->m_Content; + + igtl_stt_video_convert_byte_order(stt_video); + + this->m_TimeInterval = stt_video->time_interval; + this->m_CodecType = std::string(stt_video->codec); + return 1; + } + + + + VideoMessage::VideoMessage(): + MessageBase() + { + endian = ENDIAN_BIG; + m_FrameHeader = NULL; + m_Frame = NULL; + + for (int i = 0; i < 3; i++) + { + dimensions[i] = 0; + spacing[i] = 0.0; + subDimensions[i] = 0; + subOffset[i] = 0; + } + dimensions[2] = 1; + subDimensions[2] = 1; + + m_SendMessageType = "VIDEO"; + this->m_CodecType = IGTL_VIDEO_CODEC_NAME_VP9; + this->coordinate = COORDINATE_RAS; + + this->m_Body = NULL; + m_Frame = NULL; + m_FrameHeader = NULL; + } + + + VideoMessage::~VideoMessage() + { + } + + int VideoMessage::SetCodecType(const char codecType[]) + { + if (strcmp(codecType, IGTL_VIDEO_CODEC_NAME_I420) == 0 || strcmp(codecType, IGTL_VIDEO_CODEC_NAME_X265) == 0 || strcmp(codecType, IGTL_VIDEO_CODEC_NAME_VP9) == 0 || strcmp(codecType, IGTL_VIDEO_CODEC_NAME_H264) == 0 || strcmp(codecType, IGTL_VIDEO_CODEC_NAME_OPENHEVC) == 0) + { + this->m_CodecType = std::string(codecType); + return 0; + } + else + { + return -1; + } + } + + /// This should only be called when the data is unpacked + int VideoMessage::GetBitStreamSize() + { + #if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + return GetPackBodySize()-IGTL_VIDEO_HEADER_SIZE - IGTL_EXTENDED_HEADER_SIZE - GetMetaDataHeaderSize() - GetMetaDataSize(); + } + else + { + return GetPackBodySize()-IGTL_VIDEO_HEADER_SIZE; + } + #else + return GetPackBodySize()-IGTL_VIDEO_HEADER_SIZE; + #endif + }; + + void VideoMessage::SetBitStreamSize(int size) + { + bitStreamSize = size; + #if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + m_MessageSize = IGTL_HEADER_SIZE + bitStreamSize + IGTL_EXTENDED_HEADER_SIZE + GetMetaDataHeaderSize() + GetMetaDataSize() + IGTL_VIDEO_HEADER_SIZE; + } + else + { + m_MessageSize = size + IGTL_VIDEO_HEADER_SIZE + IGTL_HEADER_SIZE; + + } + #else + m_MessageSize = size + IGTL_HEADER_SIZE; + #endif + }; + + // Get the packed bit stream size + int VideoMessage::GetPackedBitStreamSize() + { + if(m_IsBodyPacked) + return bitStreamSize; + return -1; + } + + void VideoMessage::AllocateScalars() + { + MessageBase::AllocateBuffer(); + #if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + this->m_FrameHeader = &m_Body[IGTL_EXTENDED_HEADER_SIZE]; + } + else + { + this->m_FrameHeader = m_Body; + } + this->m_Frame = &m_FrameHeader[IGTL_VIDEO_HEADER_SIZE]; + #else + this->m_FrameHeader = m_Body; + this->m_Frame = m_Body; + #endif + } + + + igtlUint64 VideoMessage::CalculateContentBufferSize() + { + return IGTL_VIDEO_HEADER_SIZE + GetBitStreamSize(); + } + + unsigned char* VideoMessage::GetPackFragmentPointer(int id) + { + if (id == 0) + { + return this->m_Header; + } + else if (id == 1) + { + return this->m_FrameHeader; + } + else if (id == 2) + { + return this->m_Frame; + } + return NULL; + } + + + int VideoMessage::GetPackFragmentSize(int id) + { + if (id == 0) + { + return IGTL_HEADER_SIZE; + } + else if (id == 1) + { + return IGTL_VIDEO_HEADER_SIZE; + } + else if (id == 2) + { + return GetBitStreamSize(); + } + return 0; + } + + int VideoMessage::PackContent() + { + igtl_frame_header* frame_header = (igtl_frame_header*)this->m_FrameHeader; + + frame_header->header_version = IGTL_VIDEO_HEADER_VERSION; + strncpy(frame_header->encoding, this->m_CodecType.c_str(), IGTL_VIDEO_CODEC_NAME_SIZE); + frame_header->endian = this->endian; + frame_header->frameType = this->videoFrameType; + frame_header->coord = this->coordinate; + + float origin[3]; + float norm_i[3]; + float norm_j[3]; + float norm_k[3]; + + for (int i = 0; i < 3; i++) + { + norm_i[i] = matrix[i][0]; + norm_j[i] = matrix[i][1]; + norm_k[i] = matrix[i][2]; + origin[i] = matrix[i][3]; + + frame_header->size[i] = this->dimensions[i]; + frame_header->subvol_size[i] = this->subDimensions[i]; + frame_header->subvol_offset[i] = this->subOffset[i]; + } + + igtl_frame_set_matrix(this->spacing, origin, + norm_i, norm_j, norm_k, + frame_header); + + igtl_frame_convert_byte_order(frame_header); + + #if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + m_MetaDataHeader = &m_Body[CalculateContentBufferSize()+IGTL_EXTENDED_HEADER_SIZE]; + } + #endif + return 1; + } + + + int VideoMessage::UnpackContent() + { + #if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + this->m_FrameHeader = &m_Body[IGTL_EXTENDED_HEADER_SIZE]; + } + else + { + this->m_FrameHeader = m_Body; + } + this->m_Frame = &m_FrameHeader[IGTL_VIDEO_HEADER_SIZE]; + #else + this->m_FrameHeader = m_Body; + this->m_Frame = m_Body; + #endif + + igtl_frame_header* frame_header = (igtl_frame_header*)m_FrameHeader; + igtl_frame_convert_byte_order(frame_header); + + if (frame_header->header_version == IGTL_VIDEO_HEADER_VERSION) + { + // Video format version 1 + this->m_CodecType.clear(); + this->m_CodecType.append(frame_header->encoding, IGTL_VIDEO_CODEC_NAME_SIZE); + this->endian = frame_header->endian; + this->videoFrameType = frame_header->frameType; + + // Set image orientation + float rspacing[3]; + float origin[3]; + float norm_i[3]; + float norm_j[3]; + float norm_k[3]; + + igtl_frame_get_matrix(rspacing, origin, + norm_i, norm_j, norm_k, + frame_header); + + for (int i = 0; i < 3; i++) + { + this->spacing[i] = rspacing[i]; + matrix[i][0] = norm_i[i]; + matrix[i][1] = norm_j[i]; + matrix[i][2] = norm_k[i]; + matrix[i][3] = origin[i]; + + this->dimensions[i] = frame_header->size[i]; + this->subDimensions[i] = frame_header->subvol_size[i]; + this->subOffset[i] = frame_header->subvol_offset[i]; + } + + matrix[3][0] = 0.0; + matrix[3][1] = 0.0; + matrix[3][2] = 0.0; + matrix[3][3] = 1.0; + + this->m_Frame = this->m_FrameHeader; + this->m_Frame += IGTL_VIDEO_HEADER_SIZE; + + return 1; + } + else + { + // Incompatible version. + return 0; + } + } + + void VideoMessage::SetSpacing(float s[3]) + { + spacing[0] = s[0]; + spacing[1] = s[1]; + spacing[2] = s[2]; + } + + void VideoMessage::SetSpacing(float si, float sj, float sk) + { + spacing[0] = si; + spacing[1] = sj; + spacing[2] = sk; + } + + void VideoMessage::GetSpacing(float s[3]) + { + s[0] = spacing[0]; + s[1] = spacing[1]; + s[2] = spacing[2]; + } + + void VideoMessage::GetSpacing(float &si, float &sj, float &sk) + { + si = spacing[0]; + sj = spacing[1]; + sk = spacing[2]; + } + + void VideoMessage::SetOrigin(float p[3]) + { + matrix[0][3] = p[0]; + matrix[1][3] = p[1]; + matrix[2][3] = p[2]; + } + + void VideoMessage::SetOrigin(float px, float py, float pz) + { + matrix[0][3] = px; + matrix[1][3] = py; + matrix[2][3] = pz; + } + + void VideoMessage::GetOrigin(float p[3]) + { + p[0] = matrix[0][3]; + p[1] = matrix[1][3]; + p[2] = matrix[2][3]; + } + + void VideoMessage::GetOrigin(float &px, float &py, float &pz) + { + px = matrix[0][3]; + py = matrix[1][3]; + pz = matrix[2][3]; + } + + void VideoMessage::SetNormals(float o[3][3]) + { + matrix[0][0] = o[0][0]; + matrix[0][1] = o[0][1]; + matrix[0][2] = o[0][2]; + matrix[1][0] = o[1][0]; + matrix[1][1] = o[1][1]; + matrix[1][2] = o[1][2]; + matrix[2][0] = o[2][0]; + matrix[2][1] = o[2][1]; + matrix[2][2] = o[2][2]; + } + + void VideoMessage::SetNormals(float t[3], float s[3], float n[3]) + { + matrix[0][0] = t[0]; + matrix[1][0] = t[1]; + matrix[2][0] = t[2]; + matrix[0][1] = s[0]; + matrix[1][1] = s[1]; + matrix[2][1] = s[2]; + matrix[0][2] = n[0]; + matrix[1][2] = n[1]; + matrix[2][2] = n[2]; + } + + void VideoMessage::GetNormals(float o[3][3]) + { + o[0][0] = matrix[0][0]; + o[0][1] = matrix[0][1]; + o[0][2] = matrix[0][2]; + o[1][0] = matrix[1][0]; + o[1][1] = matrix[1][1]; + o[1][2] = matrix[1][2]; + o[2][0] = matrix[2][0]; + o[2][1] = matrix[2][1]; + o[2][2] = matrix[2][2]; + } + + void VideoMessage::GetNormals(float t[3], float s[3], float n[3]) + { + t[0] = matrix[0][0]; + t[1] = matrix[1][0]; + t[2] = matrix[2][0]; + s[0] = matrix[0][1]; + s[1] = matrix[1][1]; + s[2] = matrix[2][1]; + n[0] = matrix[0][2]; + n[1] = matrix[1][2]; + n[2] = matrix[2][2]; + } + + void VideoMessage::SetMatrix(Matrix4x4& mat) + { + matrix[0][0] = mat[0][0]; + matrix[1][0] = mat[1][0]; + matrix[2][0] = mat[2][0]; + matrix[3][0] = mat[3][0]; + + matrix[0][1] = mat[0][1]; + matrix[1][1] = mat[1][1]; + matrix[2][1] = mat[2][1]; + matrix[3][1] = mat[3][1]; + + matrix[0][2] = mat[0][2]; + matrix[1][2] = mat[1][2]; + matrix[2][2] = mat[2][2]; + matrix[3][2] = mat[3][2]; + + matrix[0][3] = mat[0][3]; + matrix[1][3] = mat[1][3]; + matrix[2][3] = mat[2][3]; + matrix[3][3] = mat[3][3]; + } + + void VideoMessage::GetMatrix(Matrix4x4& mat) + { + mat[0][0] = matrix[0][0]; + mat[1][0] = matrix[1][0]; + mat[2][0] = matrix[2][0]; + mat[3][0] = matrix[3][0]; + + mat[0][1] = matrix[0][1]; + mat[1][1] = matrix[1][1]; + mat[2][1] = matrix[2][1]; + mat[3][1] = matrix[3][1]; + + mat[0][2] = matrix[0][2]; + mat[1][2] = matrix[1][2]; + mat[2][2] = matrix[2][2]; + mat[3][2] = matrix[3][2]; + + mat[0][3] = matrix[0][3]; + mat[1][3] = matrix[1][3]; + mat[2][3] = matrix[2][3]; + mat[3][3] = matrix[3][3]; + } + + void VideoMessage::SetDimensions(int s[3]) + { + for (int i = 0; i < 3; ++i) + { + this->dimensions[i] = s[i]; + this->subDimensions[i] = s[i]; + } + } + + void VideoMessage::SetDimensions(int i, int j, int k) + { + dimensions[0] = i; + subDimensions[0] = i; + + dimensions[1] = i; + subDimensions[1] = i; + + dimensions[2] = i; + subDimensions[2] = i; + } + + void VideoMessage::GetDimensions(int s[3]) + { + for (int i = 0; i < 3; ++i) + { + s[i] = dimensions[i]; + } + } + + void VideoMessage::GetDimensions(int &i, int &j, int &k) + { + i = dimensions[0]; + j = dimensions[1]; + k = dimensions[2]; + } + + int VideoMessage::SetSubVolume(int dim[3], int off[3]) + { + // make sure that sub-volume fits in the dimensions + if (off[0] + dim[0] <= dimensions[0] && + off[1] + dim[1] <= dimensions[1] && + off[2] + dim[2] <= dimensions[2]) + { + subDimensions[0] = dim[0]; + subDimensions[1] = dim[1]; + subDimensions[2] = dim[2]; + subOffset[0] = off[0]; + subOffset[1] = off[1]; + subOffset[2] = off[2]; + return 1; + } + else + { + return 0; + } + } + + int VideoMessage::SetSubVolume(int dimi, int dimj, int dimk, int offi, int offj, int offk) + { + // make sure that sub-volume fits in the dimensions + if (offi + dimi <= dimensions[0] && + offj + dimj <= dimensions[1] && + offk + dimk <= dimensions[2]) + { + subDimensions[0] = dimi; + subDimensions[1] = dimj; + subDimensions[2] = dimk; + subOffset[0] = offi; + subOffset[1] = offj; + subOffset[2] = offk; + return 1; + } + else + { + return 0; + } + } + + void VideoMessage::GetSubVolume(int dim[3], int off[3]) + { + dim[0] = subDimensions[0]; + dim[1] = subDimensions[1]; + dim[2] = subDimensions[2]; + off[0] = subOffset[0]; + off[1] = subOffset[1]; + off[2] = subOffset[2]; + } + + void VideoMessage::GetSubVolume(int &dimi, int &dimj, int &dimk, + int &offi, int &offj, int &offk) + { + dimi = subDimensions[0]; + dimj = subDimensions[1]; + dimk = subDimensions[2]; + offi = subOffset[0]; + offj = subOffset[1]; + offk = subOffset[2]; + } + +} // namespace igtl \ No newline at end of file diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVideoMessage.h b/openigtlink/repo/Source/VideoStreaming/igtlVideoMessage.h new file mode 100755 index 0000000..6da008b --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVideoMessage.h @@ -0,0 +1,355 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlVideoMessage_h +#define __igtlVideoMessage_h + +#include + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" + +#include "igtl_header.h" +#include "igtl_video.h" + +namespace igtl +{ + /// A class for the STT_TDATA message type. +class IGTLCommon_EXPORT StartVideoMessage: public MessageBase +{ + +public: + igtlTypeMacro(igtl::StartVideoMessage, igtl::MessageBase); + igtlNewMacro(igtl::StartVideoMessage); + +public: + /// Sets the time resolution for streaming of QTDATA messages + void SetTimeInterval(igtlInt32 interval) { this->m_TimeInterval = interval; }; // ms + + /// Gets the time resolution for streaming of QTDATA messages + igtlInt32 GetTimeInterval() { return this->m_TimeInterval; }; + + void SetCodecType(const char codecType[]){ this->m_CodecType = std::string(codecType); }; + + std::string GetCodecType() { return this->m_CodecType; }; + +protected: + StartVideoMessage() : MessageBase() + { + this->m_SendMessageType = "STT_VIDEO"; + this->m_TimeInterval = 50; + this->m_CodecType = IGTL_VIDEO_CODEC_NAME_VP9; + }; + ~StartVideoMessage(); + + /// Gets the size of the serialized content. + igtlUint64 CalculateContentBufferSize() override; + +protected: + virtual int GetBodyPackSize(); + int PackContent() override; + int UnpackContent() override; + +protected: + + /// codec is define here, "VP9" is the default + /// A variable for codec protocal + std::string m_CodecType; + /// Minimum time between two frames (ms). Use 0 for as fast as possible. + igtlInt32 m_TimeInterval; + +}; + + +class IGTLCommon_EXPORT VideoMessageHeader: public MessageHeader +{ +public: + igtlTypeMacro(igtl::VideoMessageHeader, igtl::MessageBase); + igtlNewMacro(igtl::VideoMessageHeader); + virtual int GetBodyPackSize() { return m_BodySizeToRead; }; + +protected: + VideoMessageHeader() : MessageBase() { this->m_SendMessageType = "VIDEO_HEADER"; }; + ~VideoMessageHeader() {}; +protected: + virtual int PackBody() { AllocatePack(); return 1; }; + virtual int UnpackBody() { return 1; }; +}; + + +class IGTLCommon_EXPORT StopVideoMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::StopVideoMessage, igtl::MessageBase); + igtlNewMacro(igtl::StopVideoMessage); + +protected: + StopVideoMessage() : MessageBase() { this->m_SendMessageType = "STP_VIDEO"; }; + ~StopVideoMessage() {}; +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; +}; + +class IGTLCommon_EXPORT VideoMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::VideoMessage, igtl::MessageBase) + igtlNewMacro(igtl::VideoMessage); + +public: + + /// Endian used in the bite array for the image data. + enum { + ENDIAN_BIG=1, + ENDIAN_LITTLE=2 + }; + + /// Coordinate sysmtem. Either left-posterior-superior (LPS) or right-anterior-superior (RAS). + enum { + COORDINATE_RAS = 1, + COORDINATE_LPS = 2 + }; + + /// Pixel data type. + + /// Pixel data type either scalar or vector. + enum { + DTYPE_SCALAR = 1, + DTYPE_VECTOR = 3 + }; + + /// Pixel data type. + enum { + TYPE_INT8 = 2, + TYPE_UINT8 = 3, + TYPE_INT16 = 4, + TYPE_UINT16 = 5, + TYPE_INT32 = 6, + TYPE_UINT32 = 7, + }; + + +public: + + /// Gets the size of the specified scalar type. (e.g. 1 byte for 8-bit integer) + int GetScalarSize(int type) { return ScalarSizeTable[type]; }; + + /// Sets the Endianess of the image scalars. (default is ENDIAN_BIG) + void SetEndian(int e) { endian = e; }; + + /// Gets the Endianess of the image scalars. + int GetEndian() { return endian; }; + + /// Sets image dimensions by an array of the numbers of pixels in i, j and k directions. + /// SetDimensions() should be called prior to SetSubVolume(), since SetDimensions() + /// sets subvolume parameters automatically assuming that subvolume = entire volume. + void SetDimensions(int s[3]); + + /// Sets image dimensions by the numbers of pixels in i, j and k directions. + /// SetDimensions() should be called prior to SetSubVolume(), since SetDimensions() + /// sets subvolume parameters automatically assuming that subvolume = entire volume. + void SetDimensions(int i, int j, int k); + + /// Gets image dimensions as an array of the numbers of pixels in i, j and k directions. + void GetDimensions(int s[3]); + + /// Gets image dimensions as the numbers of pixels in i, j and k directions. + void GetDimensions(int &i, int &j, int &k); + + /// Sets the width of the image scalars. + void SetWidth(int w) { this->dimensions[0] = w; this->subDimensions[0] = w; }; + + /// Gets the width of the image scalars. + int GetWidth() { return this->dimensions[0]; }; + + /// Sets the width of the image scalars. + void SetHeight(int h) { this->dimensions[1] = h; this->subDimensions[1] = h; }; + + /// Gets the height of the image scalars. + int GetHeight() { return this->dimensions[1]; }; + + /// Sets the additionalZDimension of the image. + void SetAdditionalZDimension(int zDimension) { this->dimensions[2] = zDimension; this->subDimensions[2] = zDimension; }; + + /// Gets the additionalZDimension of the image. + int GetAdditionalZDimension() { return this->dimensions[2]; }; + + /// Sets sub-volume dimensions and offset by arrays of the dimensions and the offset. + /// SetSubVolume() should be called after calling SetDiemensions(), since SetDimensions() + /// reset the subvolume parameters automatically. Returns non-zero value if the subvolume + /// is successfully specified. Returns zero, if invalid subvolume is specified. + int SetSubVolume(int dim[3], int off[3]); + + /// Sets sub-volume dimensions and offset by the dimensions and the offset in i, j and k + /// directions. SetSubVolume() should be called after calling SetDiemensions(), + /// since SetDimensions() reset the subvolume parameters automatically. + /// Returns non-zero value if the subvolume is successfully specified. + /// Returns zero, if invalid subvolume is specified. + int SetSubVolume(int dimi, int dimj, int dimk, int offi, int offj, int offk); + + /// Gets sub-volume dimensions and offset using arrays of the dimensions and the offset. + void GetSubVolume(int dim[3], int off[3]); + + /// Gets sub-volume dimensions and offset by the dimensions and the offset in i, j and k + /// directions. + void GetSubVolume(int &dimi, int &dimj, int &dimk, int &offi, int &offj, int &offk); + + /// Sets the frame type of the encoded image + void SetFrameType(int e){videoFrameType = e;} + + /// Gets the frame type of the encoded image + int GetFrameType(){return videoFrameType;} + + /// Sets the codec type, e.g. H264, VP9, X265 + int SetCodecType(const char codecType[]); + + std::string GetCodecType() { return this->m_CodecType; }; + + /// Sets spacings by an array of spacing values in i, j and k directions. + void SetSpacing(float s[3]); + + /// Sets spacings by spacing values in i, j and k directions. + void SetSpacing(float si, float sj, float sk); + + /// Gets spacings using an array of spacing values in i, j and k directions. + void GetSpacing(float s[3]); + + /// Gets spacings using spacing values in i, j and k directions. + void GetSpacing(float &si, float &sj, float &sk); + + /// Sets the coordinates of the origin by an array of positions along the first (R or L), + /// second (A or P) and the third (S) axes. + void SetOrigin(float p[3]); + + /// Sets the coordinates of the origin by positions along the first (R or L), second (A or P) + /// and the third (S) axes. + void SetOrigin(float px, float py, float pz); + + /// Gets the coordinates of the origin using an array of positions along the first (R or L), + /// second (A or P) and the third (S) axes. + void GetOrigin(float p[3]); + + /// Gets the coordinates of the origin by positions along the first (R or L), second (A or P) + /// and the third (S) axes. + void GetOrigin(float &px, float &py, float &pz); + + /// Sets the orientation of the image by an array of the normal vectors for the i, j + /// and k indeces. + void SetNormals(float o[3][3]); + + /// Sets the orientation of the image by the normal vectors for the i, j and k indeces. + void SetNormals(float t[3], float s[3], float n[3]); + + /// Gets the orientation of the image using an array of the normal vectors for the i, j + /// and k indeces. + void GetNormals(float o[3][3]); + + /// Gets the orientation of the image using the normal vectors for the i, j and k indeces. + void GetNormals(float t[3], float s[3], float n[3]); + + /// Sets the origin/orientation matrix. + void SetMatrix(Matrix4x4& mat); + + /// Gets the origin/orientation matrix. + void GetMatrix(Matrix4x4& mat); + + /// This should only be called when the data is unpacked + int GetBitStreamSize(); + + // Get the packed bit stream size + int GetPackedBitStreamSize(); + + // For memory allocation in packing process + void SetBitStreamSize(int size); + + /// Allocates a memory area for the scalar data based on the dimensions of the subvolume, + /// the number of components, and the scalar type. + void AllocateScalars(); + + /// Gets a pointer to the scalar data (for fragmented pack support). + void* GetPackPointer(){return GetBufferPointer();}; + + /// Gets the number of fragments for the packed (serialized) data. Returns 3 + /// consisting of header, image header and image body. (for fragmented pack support) + int GetNumberOfPackFragments() { return 3; /* header, image header and image body */ } + + /// Gets a pointer to the specified fragment of the packed data. (for fragmented pack support) + unsigned char* GetPackFragmentPointer(int id); + + int GetPackFragmentSize(int id); + +protected: + VideoMessage(); + ~VideoMessage(); + +protected: + + /// Pack() serializes the header and body based on the member variables. + /// PackBody() must be implemented in the child class. (for fragmented pack support) + int PackContent() override; + int UnpackContent() override; + + igtlUint64 CalculateContentBufferSize() override; + +private: + + /// A variable for the Endian of the scalar values in the image. + int endian; + + /// A vector containing the numbers of voxels in i, j and k directions. + int dimensions[3]; + + /// The frame type of the encoded image + int videoFrameType; + + /// A variable for the allocate the message body + int bitStreamSize; + + /// A pointer to the serialized image header. + unsigned char* m_FrameHeader; + + /// A pointer to the serialized image data. + unsigned char* m_Frame; + + /// A table to look up the size of a given scalar type. + int ScalarSizeTable[12]; + + std::string m_CodecType; + + /// A vector containing the spacings of the voxels in i, j and k directions. + float spacing[3]; + + /// A variable for the scalar type of the voxels. + int coordinate; + + /// A vector containing the numbers of voxels of the subvolume in i, j and k directions. + int subDimensions[3]; + + /// A vector containing the offset (number of voxels) of the first voxel of + /// the subvolume from the first voxel of the original image. + int subOffset[3]; + + /// A matrix representing the origin and the orientation of the image. + /// The matrix is set to identity by default + Matrix4x4 matrix; +}; + + +} // namespace igtl + +#endif // _igtlVideoMessage_h diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVideoMetaMessage.cxx b/openigtlink/repo/Source/VideoStreaming/igtlVideoMetaMessage.cxx new file mode 100644 index 0000000..f4560cd --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVideoMetaMessage.cxx @@ -0,0 +1,443 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlVideoMetaMessage.h" + +#include "igtl_header.h" +#include "igtl_videometa.h" +#include "igtl_video.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include +#include + +namespace igtl { + + +//---------------------------------------------------------------------- +// igtl::VideoMetaElement class + +VideoMetaElement::VideoMetaElement() : Object() +{ + for (int i = 0; i < 3; i ++) + { + spacing[i] = 1.0; + } + for (int i = 0; i < 4; i ++) + { + for (int j = 0; j < 4; j ++) + { + matrix[i][j] = (i == j ? 1.0 : 0.0); + } + } + this->m_Size[0] = 0; + this->m_Size[1] = 0; + this->m_Size[2] = 0; + this->m_ZoomLevel = 1; + this->m_FocalLength = 100.0; + this->m_ScalarType = 0; +} + + +VideoMetaElement::~VideoMetaElement() +{ +} + + +int VideoMetaElement::SetName(const char* name) +{ + if (strlen(name) <= IGTL_VIDEOMETA_LEN_NAME) + { + this->m_Name = name; + return 1; + } + else + { + return 0; + } +} + + +int VideoMetaElement::SetDeviceName(const char* devname) +{ + if (strlen(devname) <= IGTL_VIDEOMETA_LEN_DEVICE_NAME) + { + this->m_DeviceName = devname; + return 1; + } + else + { + return 0; + } +} + +int VideoMetaElement::SetPatientName(const char* patname) +{ + if (strlen(patname) <= IGTL_VIDEOMETA_LEN_PATIENT_NAME) + { + this->m_PatientName = patname; + return 1; + } + else + { + return 0; + } +} + + +int VideoMetaElement::SetPatientID(const char* patid) +{ + if (strlen(patid) <= IGTL_VIDEOMETA_LEN_PATIENT_ID) + { + this->m_PatientID = patid; + return 1; + } + else + { + return 0; + } +} + + +void VideoMetaElement::SetSize(igtlUint16 si, igtlUint16 sj, igtlUint16 sk) +{ + this->m_Size[0] = si; + this->m_Size[1] = sj; + this->m_Size[2] = sk; +} + +void VideoMetaElement::GetSize(igtlUint16& si, igtlUint16& sj, igtlUint16& sk) +{ + si = this->m_Size[0]; + sj = this->m_Size[1]; + sk = this->m_Size[2]; +} + + +void VideoMetaElement::SetSpacing(float si, float sj, float sk) +{ + spacing[0] = si; + spacing[1] = sj; + spacing[2] = sk; +} + +void VideoMetaElement::GetSpacing(float &si, float &sj, float &sk) +{ + si = spacing[0]; + sj = spacing[1]; + sk = spacing[2]; +} + +void VideoMetaElement::SetOrigin(float px, float py, float pz) +{ + matrix[0][3] = px; + matrix[1][3] = py; + matrix[2][3] = pz; +} + +void VideoMetaElement::GetOrigin(float &px, float &py, float &pz) +{ + px = matrix[0][3]; + py = matrix[1][3]; + pz = matrix[2][3]; +} + +void VideoMetaElement::SetNormals(float t[3], float s[3], float n[3]) +{ + matrix[0][0] = t[0]; + matrix[1][0] = t[1]; + matrix[2][0] = t[2]; + matrix[0][1] = s[0]; + matrix[1][1] = s[1]; + matrix[2][1] = s[2]; + matrix[0][2] = n[0]; + matrix[1][2] = n[1]; + matrix[2][2] = n[2]; +} + +void VideoMetaElement::GetNormals(float t[3], float s[3], float n[3]) +{ + t[0] = matrix[0][0]; + t[1] = matrix[1][0]; + t[2] = matrix[2][0]; + s[0] = matrix[0][1]; + s[1] = matrix[1][1]; + s[2] = matrix[2][1]; + n[0] = matrix[0][2]; + n[1] = matrix[1][2]; + n[2] = matrix[2][2]; +} + +void VideoMetaElement::SetMatrix(Matrix4x4& mat) +{ + matrix[0][0] = mat[0][0]; + matrix[1][0] = mat[1][0]; + matrix[2][0] = mat[2][0]; + matrix[3][0] = mat[3][0]; + + matrix[0][1] = mat[0][1]; + matrix[1][1] = mat[1][1]; + matrix[2][1] = mat[2][1]; + matrix[3][1] = mat[3][1]; + + matrix[0][2] = mat[0][2]; + matrix[1][2] = mat[1][2]; + matrix[2][2] = mat[2][2]; + matrix[3][2] = mat[3][2]; + + matrix[0][3] = mat[0][3]; + matrix[1][3] = mat[1][3]; + matrix[2][3] = mat[2][3]; + matrix[3][3] = mat[3][3]; +} + +void VideoMetaElement::GetMatrix(Matrix4x4& mat) +{ + mat[0][0] = matrix[0][0]; + mat[1][0] = matrix[1][0]; + mat[2][0] = matrix[2][0]; + mat[3][0] = matrix[3][0]; + + mat[0][1] = matrix[0][1]; + mat[1][1] = matrix[1][1]; + mat[2][1] = matrix[2][1]; + mat[3][1] = matrix[3][1]; + + mat[0][2] = matrix[0][2]; + mat[1][2] = matrix[1][2]; + mat[2][2] = matrix[2][2]; + mat[3][2] = matrix[3][2]; + + mat[0][3] = matrix[0][3]; + mat[1][3] = matrix[1][3]; + mat[2][3] = matrix[2][3]; + mat[3][3] = matrix[3][3]; +} + +void VideoMetaElement::SetScalarType(igtlUint8 type) +{ + if (type == IGTL_VIDEO_STYPE_TYPE_INT8 || + type == IGTL_VIDEO_STYPE_TYPE_UINT8 || + type == IGTL_VIDEO_STYPE_TYPE_INT16 || + type == IGTL_VIDEO_STYPE_TYPE_UINT16 || + type == IGTL_VIDEO_STYPE_TYPE_INT32 || + type == IGTL_VIDEO_STYPE_TYPE_UINT32) + { + this->m_ScalarType = type; + } + else + { + this->m_ScalarType = 0; + } +} + + +igtlUint8 VideoMetaElement::GetScalarType() +{ + return this->m_ScalarType; +} + + + +//---------------------------------------------------------------------- +// igtl::VideoMetaMessage class + +VideoMetaMessage::VideoMetaMessage() +{ + this->m_SendMessageType = "VIDEOMETA"; + this->m_VideoMetaList.clear(); +} + + +VideoMetaMessage::~VideoMetaMessage() +{ +} + + +int VideoMetaMessage::AddVideoMetaElement(VideoMetaElement::Pointer& elem) +{ + this->m_VideoMetaList.push_back(elem); + return this->m_VideoMetaList.size(); +} + + +void VideoMetaMessage::ClearVideoMetaElement() +{ + this->m_VideoMetaList.clear(); +} + + +int VideoMetaMessage::GetNumberOfVideoMetaElement() +{ + return this->m_VideoMetaList.size(); +} + + +void VideoMetaMessage::GetVideoMetaElement(int index, VideoMetaElement::Pointer& elem) +{ + if (index >= 0 && index < (int) this->m_VideoMetaList.size()) + { + elem = this->m_VideoMetaList[index]; + } +} + + +igtlUint64 VideoMetaMessage::CalculateContentBufferSize() +{ + // The body size sum of the header size and status message size. + return IGTL_VIDEOMETA_ELEMENT_SIZE * this->m_VideoMetaList.size(); +} + + +int VideoMetaMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + igtl_videometa_element* element = (igtl_videometa_element*)this->m_Content; + + std::vector::iterator iter; + for (iter = this->m_VideoMetaList.begin(); iter != this->m_VideoMetaList.end(); iter ++) + { + strncpy((char*)element->name, (*iter)->GetName(), IGTL_VIDEOMETA_LEN_NAME); + strncpy((char*)element->device_name, (*iter)->GetDeviceName(), IGTL_VIDEOMETA_LEN_DEVICE_NAME); + strncpy((char*)element->patient_name, (*iter)->GetPatientName(), IGTL_VIDEOMETA_LEN_PATIENT_NAME); + strncpy((char*)element->patient_id, (*iter)->GetPatientID(), IGTL_VIDEOMETA_LEN_PATIENT_ID); + + element->zoom_level = (*iter)->GetZoomLevel(); + element->focal_length = (*iter)->GetFocalLength(); + + igtlUint16 size[3]; + (*iter)->GetSize(size[0], size[1], size[2]); + element->size[0] = size[0]; + element->size[1] = size[1]; + element->size[2] = size[2]; + + float origin[3]; + float norm_i[3]; + float norm_j[3]; + float norm_k[3]; + float spacing[3]; + Matrix4x4 mat; + (*iter)->GetMatrix(mat); + (*iter)->GetSpacing(spacing[0], spacing[1], spacing[2]); + for (int i = 0; i < 3; i ++) + { + norm_i[i] = mat[i][0]; + norm_j[i] = mat[i][1]; + norm_k[i] = mat[i][2]; + origin[i] = mat[i][3]; + } + + igtl_videometa_set_matrix(spacing, origin, + norm_i, norm_j, norm_k, + element); + + element->scalar_type = (*iter)->GetScalarType(); + element->reserved = 0; + element ++; + } + + igtl_videometa_convert_byte_order((igtl_videometa_element*)this->m_Content, this->m_VideoMetaList.size()); + + return 1; +} + + +int VideoMetaMessage::UnpackContent() +{ + + this->m_VideoMetaList.clear(); + + igtl_videometa_element* element = (igtl_videometa_element*) this->m_Content; + int elementsDataLength = this->m_BodySizeToRead; +#if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + elementsDataLength = this->m_BodySizeToRead-IGTL_EXTENDED_HEADER_SIZE-this->GetMetaDataHeaderSize()-this->GetMetaDataSize(); + } +#endif + int nElement = igtl_videometa_get_data_n(elementsDataLength); + + igtl_videometa_convert_byte_order(element, nElement); + + char strbuf[128]; + for (int i = 0; i < nElement; i ++) + { + VideoMetaElement::Pointer elemClass = VideoMetaElement::New(); + + // Add '\n' at the end of each string + // (necessary for a case, where a string reaches the maximum length.) + strbuf[IGTL_VIDEOMETA_LEN_NAME] = '\n'; + strncpy(strbuf, (char*)element->name, IGTL_VIDEOMETA_LEN_NAME); + elemClass->SetName((const char*)strbuf); + + strbuf[IGTL_VIDEOMETA_LEN_DEVICE_NAME] = '\n'; + strncpy(strbuf, (char*)element->device_name, IGTL_VIDEOMETA_LEN_DEVICE_NAME); + elemClass->SetDeviceName(strbuf); + + strbuf[IGTL_VIDEOMETA_LEN_PATIENT_NAME] = '\n'; + strncpy(strbuf, (char*)element->patient_name, IGTL_VIDEOMETA_LEN_PATIENT_NAME); + elemClass->SetPatientName(strbuf); + + strbuf[IGTL_VIDEOMETA_LEN_PATIENT_ID] = '\n'; + strncpy(strbuf, (char*)element->patient_id, IGTL_VIDEOMETA_LEN_PATIENT_ID); + elemClass->SetPatientID(strbuf); + + elemClass->SetZoomLevel(element->zoom_level); + elemClass->SetFocalLength(element->focal_length); + elemClass->SetSize(element->size[0],element->size[1],element->size[2]); + + // Set image orientation + float rspacing[3]; + float origin[3]; + float norm_i[3]; + float norm_j[3]; + float norm_k[3]; + + igtl_videometa_get_matrix(rspacing, origin, + norm_i, norm_j, norm_k, + element); + + elemClass->SetSpacing(rspacing[0], rspacing[1], rspacing[2]); + elemClass->SetNormals(norm_i, norm_j, norm_k); + elemClass->SetOrigin(origin[0], origin[1], origin[2]); + + Matrix4x4 tmpMatrix; + for (int i = 0; i < 3; i ++) + { + tmpMatrix[i][0] = norm_i[i]; + tmpMatrix[i][1] = norm_j[i]; + tmpMatrix[i][2] = norm_k[i]; + tmpMatrix[i][3] = origin[i]; + } + tmpMatrix[3][0] = 0.0; + tmpMatrix[3][1] = 0.0; + tmpMatrix[3][2] = 0.0; + tmpMatrix[3][3] = 1.0; + elemClass->SetMatrix(tmpMatrix); + + elemClass->SetScalarType(element->scalar_type); + + this->m_VideoMetaList.push_back(elemClass); + + element ++; + } + + return 1; +} + +} // namespace igtl \ No newline at end of file diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVideoMetaMessage.h b/openigtlink/repo/Source/VideoStreaming/igtlVideoMetaMessage.h new file mode 100644 index 0000000..dc555d8 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVideoMetaMessage.h @@ -0,0 +1,218 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlVideoMetaMessage_h +#define __igtlVideoMetaMessage_h + +#include +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +#include "igtlVideoMessage.h" + +namespace igtl +{ + +/// A class to manage meta data of images. +class IGTLCommon_EXPORT VideoMetaElement: public Object +{ +public: + igtlTypeMacro(igtl::VideoMetaElement, igtl::Object); + igtlNewMacro(igtl::VideoMetaElement); + +public: + + /// Sets the image name/description. The string 'name' must not exceed 64 characters. + int SetName(const char* name); + + /// Gets the image name/description. + const char* GetName() { return this->m_Name.c_str(); }; + + /// Sets the device name (message name). The string 'devname' must not exceed 20 + /// characters. + int SetDeviceName(const char* devname); + + /// Gets the device name (message name). + const char* GetDeviceName() { return this->m_DeviceName.c_str(); }; + + /// Sets the zoom level of the camera (e.g. +4, -4). + void SetZoomLevel(igtlInt16 level) {this->m_ZoomLevel = level;}; + + /// Gets the zoom level of the camera (e.g. +4, -4). + igtlInt16 GetZoomLevel() { return this->m_ZoomLevel; }; + + /// Sets the focal length of the camera (e.g. +50.0mm, +200.0mm). + void SetFocalLength(igtlFloat64 length) {this->m_FocalLength = length;}; + + /// Gets the focal length of the camera (e.g.+50.0mm, +200.0mm). + igtlFloat64 GetFocalLength() { return this->m_FocalLength; }; + + /// Sets the patient name. The string 'patname' must not exceed 64 characters. + int SetPatientName(const char* patname); + + /// Gets the patient name. + const char* GetPatientName() { return this->m_PatientName.c_str(); }; + + /// Sets the patient ID. The string 'patid' must not exceed 64 characters. + int SetPatientID(const char* patid); + + /// Gets the patient ID. + const char* GetPatientID() { return this->m_PatientID.c_str(); } + + /// Sets the size of the image by the numbers of voxels in i, j, and k directions. + void SetSize(igtlUint16 si, igtlUint16 sj, igtlUint16 sk); + + /// Gets the size of the image by the numbers of voxels in i, j, and k directions. + void GetSize(igtlUint16& si, igtlUint16& sj, igtlUint16& sk); + + /// Sets the origin/orientation matrix. + void SetMatrix(Matrix4x4& mat); + + /// Gets the origin/orientation matrix. + void GetMatrix(Matrix4x4& mat); + + /// Sets spacings by spacing values in i, j and k directions. + void SetSpacing(float si, float sj, float sk); + + /// Gets spacings using spacing values in i, j and k directions. + void GetSpacing(float &si, float &sj, float &sk); + + /// Sets the coordinates of the origin by positions along the first (R or L), second (A or P) + /// and the third (S) axes. + void SetOrigin(float px, float py, float pz); + + /// Gets the coordinates of the origin by positions along the first (R or L), second (A or P) + /// and the third (S) axes. + void GetOrigin(float &px, float &py, float &pz); + + /// Sets the orientation of the image by the normal vectors for the i, j and k indeces. + void SetNormals(float t[3], float s[3], float n[3]); + + /// Gets the orientation of the image using the normal vectors for the i, j and k indeces. + void GetNormals(float t[3], float s[3], float n[3]); + + /// Sets the scalar type of the image + void SetScalarType(igtlUint8 type); + + /// Gets the scalar type of the image. + igtlUint8 GetScalarType(); + +protected: + VideoMetaElement(); + ~VideoMetaElement(); + +protected: + + /// name / description (<= 64 bytes) + std::string m_Name; + + /// device name to query the IMAGE and COLORT + std::string m_DeviceName; + + /// patient name (<= 64 bytes) + std::string m_PatientName; + + /// patient ID (MRN etc.) (<= 64 bytes) + std::string m_PatientID; + + /// Zoom level of the camera + igtlInt16 m_ZoomLevel; + + /// Focal length of the camera + igtlFloat64 m_FocalLength; + + /// A vector containing the spacings of the voxels in i, j and k directions. + float spacing[3]; + + /// A matrix representing the origin and the orientation of the image, + /// if the camera is attached with tracking device. + /// The matrix is set to identity by default + Matrix4x4 matrix; + + /// entire image volume size, if the video is from ultrasound + igtlUint16 m_Size[3]; + + /// scalar type. see scalar_type in Video message + igtlUint8 m_ScalarType; + +}; + + +/// A class for the GET_IMGMETA message type. +class IGTLCommon_EXPORT GetVideoMetaMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::GetVideoMetaMessage, igtl::MessageBase); + igtlNewMacro(igtl::GetVideoMetaMessage); + +protected: + GetVideoMetaMessage() : MessageBase() { this->m_SendMessageType = "GET_VMETA"; }; + ~GetVideoMetaMessage() {}; +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; +}; + + +/// The IMGMETA message is used to transfer image meta information which are not +/// available in the IMAGE message type, such as patient name, medical record number, +/// modality etc. An IMGMETA message can contain meta data for multiple images. +/// This message type may be used to obtain a list of images available in +/// the remote system, such as image database or commercial image-guided surgery (IGS) system. +class IGTLCommon_EXPORT VideoMetaMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::VideoMetaMessage, igtl::MessageBase); + igtlNewMacro(igtl::VideoMetaMessage); + +public: + + /// Adds an video meta element to the list. Returns the number of elements after + /// adding the image meta element. + int AddVideoMetaElement(VideoMetaElement::Pointer& elem); + + /// Clears the all image meta elements in the list. + void ClearVideoMetaElement(); + + /// Gets the number of the image meta elements in the list. + int GetNumberOfVideoMetaElement(); + + /// Gets the image meta data specified by the index. + void GetVideoMetaElement(int index, VideoMetaElement::Pointer& elem); + + +protected: + VideoMetaMessage(); + ~VideoMetaMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// A list of pointers to image meta data. + std::vector m_VideoMetaList; + +}; + + +} // namespace igtl + +#endif // _igtlVideoMetaMessage_h diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkReceiver.cxx b/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkReceiver.cxx new file mode 100644 index 0000000..61ce3ee --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkReceiver.cxx @@ -0,0 +1,439 @@ +/*========================================================================= + + Program: VideoStreamIGTLinkReceiver + Modified based on the OpenH264/codec/console/dec/src/h264dec.cpp + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlVideoStreamIGTLinkReceiver.h" + +namespace igtl { + +struct ReadSocketAndPush +{ + igtl::MessageRTPWrapper::Pointer wrapper; + igtl::UDPClientSocket::Pointer clientSocket; + VideoStreamIGTLinkReceiver* receiver; +}; + +struct Wrapper +{ + igtl::MessageRTPWrapper::Pointer wrapper; + VideoStreamIGTLinkReceiver* receiver; +}; + + +void* ThreadFunctionUnWrap(void* ptr) +{ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + const char *deviceType = "VIDEO"; + Wrapper parentObj = *(static_cast(info->UserData)); + const char * videoDeviceName = parentObj.receiver->GetDeviceName().c_str(); + while(1) + { + parentObj.wrapper->UnWrapPacketWithTypeAndName(deviceType, videoDeviceName); + } +} + +void WriteTimeInfo(unsigned char * UDPPacket, int totMsgLen, VideoStreamIGTLinkReceiver* receiver) +{ + igtl_uint16 fragmentField; + igtl_uint32 messageID; + int extendedHeaderLength = IGTL_EXTENDED_HEADER_SIZE; + memcpy(&fragmentField, (void*)(UDPPacket + RTP_HEADER_LENGTH+IGTL_HEADER_SIZE+extendedHeaderLength-2),2); + memcpy(&messageID, (void*)(UDPPacket + RTP_HEADER_LENGTH+IGTL_HEADER_SIZE+extendedHeaderLength-6),4); + if(igtl_is_little_endian()) + { + fragmentField = BYTE_SWAP_INT16(fragmentField); + messageID = BYTE_SWAP_INT32(messageID); + } + +} + + +void* ThreadFunctionReadSocket(void* ptr) +{ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + ReadSocketAndPush parentObj = *(static_cast(info->UserData)); + unsigned char UDPPacket[RTP_PAYLOAD_LENGTH+RTP_HEADER_LENGTH]; + while(1) + { + int totMsgLen = parentObj.clientSocket->ReadSocket(UDPPacket, RTP_PAYLOAD_LENGTH+RTP_HEADER_LENGTH); + + WriteTimeInfo(UDPPacket, totMsgLen, parentObj.receiver); + if (totMsgLen>0) + { + parentObj.wrapper->PushDataIntoPacketBuffer(UDPPacket, totMsgLen); + } + } +} + +VideoStreamIGTLinkReceiver::VideoStreamIGTLinkReceiver(char *fileName) +{ + this->deviceName = ""; + this->configFile = fileName; + this->rtpWrapper = igtl::MessageRTPWrapper::New(); + strncpy(this->codecType, "H264",4); + + this->interval = 10; //10ms + this->kpOuputFileName = (char*)"decodedOutput.yuv"; + this->videoMessageBuffer=NULL; + this->decodedFrame=NULL; + socket = igtl::ClientSocket::New(); + UDPSocket = igtl::UDPClientSocket::New(); + this->Height = 0; + this->Width = 0; + this->decodeInstance = NULL; +} + +VideoStreamIGTLinkReceiver::~VideoStreamIGTLinkReceiver() +{} + +void VideoStreamIGTLinkReceiver::SetDecoder(GenericDecoder* decoder) +{ + this->decodeInstance = decoder; +} + + +int VideoStreamIGTLinkReceiver::RunOnTCPSocket() +{ + //------------------------------------------------------------ + // Establish Connection + int r = socket->ConnectToServer(TCPServerIPAddress, TCPServerPort); + + if (r != 0) + { + std::cerr << "Cannot connect to the server." << std::endl; + exit(0); + } + + //------------------------------------------------------------ + // Ask the server to start pushing tracking data + std::cerr << "Sending STT_VIDEO message....." << std::endl; + igtl::StartVideoMessage::Pointer startVideoMsg; + startVideoMsg = igtl::StartVideoMessage::New(); + startVideoMsg->AllocatePack(); + startVideoMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + startVideoMsg->SetDeviceName("MacCamera5"); + startVideoMsg->SetCodecType(codecType); + startVideoMsg->SetTimeInterval(interval); + startVideoMsg->Pack(); + socket->Send(startVideoMsg->GetPackPointer(), startVideoMsg->GetPackSize()); + while (1) + { + //------------------------------------------------------------ + // Wait for a reply + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + bool timeout(false); + int rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + socket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + std::cerr << rs <<"Message size information and actual data size don't match." <GetPackSize()<< std::endl; + continue; + } + + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceName(), this->deviceName.c_str()) == 0) + { + //------------------------------------------------------------ + // Allocate Video Message Class + + igtl::VideoMessage::Pointer videoMsg; + videoMsg = igtl::VideoMessage::New(); + videoMsg->SetMessageHeader(headerMsg); + videoMsg->AllocateScalars(); + bool timeout(false); + // Receive body from the socket + socket->Receive(videoMsg->GetPackBodyPointer(), videoMsg->GetPackBodySize(), timeout); + // Deserialize the transform data + // If you want to skip CRC check, call Unpack() without argument. + int c = videoMsg->Unpack(1); + + if (c==0) // if CRC check fails + { + // TODO: error handling + return 0; + } + this->SetWidth(videoMsg->GetWidth()); + this->SetHeight(videoMsg->GetHeight()); + int streamLength = videoMsg->GetBitStreamSize(); + if (!(this->videoMessageBuffer==NULL)) + { + delete[] this->videoMessageBuffer; + } + this->videoMessageBuffer = new igtl_uint8[streamLength]; + memcpy(this->videoMessageBuffer, videoMsg->GetPackFragmentPointer(2), streamLength); + static int frameNum = 0; + int status = this->ProcessVideoStream(this->videoMessageBuffer,streamLength); + + if (status == 0) + { + this->SendStopMessage(); + break; + } + else if(status == 2) + { + frameNum ++; + } + } + else + { + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + socket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + igtl::Sleep(20); + } + return 1; +} + + +void VideoStreamIGTLinkReceiver::SendStopMessage() +{ + //------------------------------------------------------------ + // Ask the server to stop pushing tracking data + std::cerr << "Sending STP_VIDEO message....." << std::endl; + igtl::StopVideoMessage::Pointer stopVideoMsg; + stopVideoMsg = igtl::StopVideoMessage::New(); + stopVideoMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + stopVideoMsg->SetDeviceName("VIDEO"); + stopVideoMsg->Pack(); + socket->Send(stopVideoMsg->GetPackPointer(), stopVideoMsg->GetPackSize()); +} + +int VideoStreamIGTLinkReceiver::RunOnUDPSocket() +{ + igtl::ConditionVariable::Pointer conditionVar = igtl::ConditionVariable::New(); + igtl::SimpleMutexLock* glock = igtl::SimpleMutexLock::New(); + UDPSocket->JoinNetwork("127.0.0.1", UDPClientPort); + ReadSocketAndPush info; + info.wrapper = rtpWrapper; + info.clientSocket = UDPSocket; + info.receiver = this; + + Wrapper infoWrapper; + infoWrapper.wrapper = rtpWrapper; + infoWrapper.receiver = this; + + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + threader->SpawnThread((igtl::ThreadFunctionType)&ThreadFunctionReadSocket, &info); + threader->SpawnThread((igtl::ThreadFunctionType)&ThreadFunctionUnWrap, &infoWrapper); + while(1) + { + glock->Lock(); + unsigned int messageNum = rtpWrapper->unWrappedMessages.size(); + glock->Unlock(); + if(messageNum)// to do: glock this session + { + igtl::VideoMessage::Pointer videoMultiPKTMSG = igtl::VideoMessage::New(); + glock->Lock(); + std::map::iterator it = rtpWrapper->unWrappedMessages.begin(); + igtlUint8 * message = new igtlUint8[it->second->messageDataLength]; + static int frameNum = 0; + int MSGLength = it->second->messageDataLength; + memcpy(message, it->second->messagePackPointer, it->second->messageDataLength); + delete it->second; + it->second = NULL; + rtpWrapper->unWrappedMessages.erase(it); + glock->Unlock(); + igtl::MessageHeader::Pointer header = igtl::MessageHeader::New(); + header->InitPack(); + memcpy(header->GetPackPointer(), message, IGTL_HEADER_SIZE); + header->Unpack(); + videoMultiPKTMSG->SetMessageHeader(header); + videoMultiPKTMSG->AllocateBuffer(); + if (MSGLength == videoMultiPKTMSG->GetPackSize()) + { + memcpy(videoMultiPKTMSG->GetPackPointer(), message, MSGLength); + videoMultiPKTMSG->Unpack(0); + int streamLength = videoMultiPKTMSG->GetBitStreamSize(); + this->SetWidth(videoMultiPKTMSG->GetWidth()); + this->SetHeight(videoMultiPKTMSG->GetHeight()); + if (!(this->videoMessageBuffer==NULL)) + { + delete[] this->videoMessageBuffer; + } + this->videoMessageBuffer = new igtl_uint8[streamLength]; + memcpy(this->videoMessageBuffer, videoMultiPKTMSG->GetPackFragmentPointer(2), streamLength); + + int status = this->ProcessVideoStream(this->videoMessageBuffer,streamLength); + + if (status == 0) + { + break; + } + else if(status == 2) + { + frameNum ++; + } + } + delete [] message; + } + } + return 0; +} + +bool VideoStreamIGTLinkReceiver::InitializeClient() +{ + // if configure file exit, reading configure file firstly + if(strcmp(this->configFile.c_str(),"")==0) + { + fprintf (stdout, "The udp/tcp selection is upto the application.\n"); + return true; + } + else + { + cRdCfg.OpenFile(this->configFile.c_str());// to do get the first configFile from this->configFile. + if (cRdCfg.ExistFile()) + { + cRdCfg.OpenFile (this->configFile.c_str());// reset the file read pointer to the beginning. + int iRet = ParseConfigForClient(); + if (iRet == -1) { + fprintf (stderr, "parse client parameter config file failed.\n"); + return false; + } + return true; + } + else + { + fprintf (stderr, "Specified file: %s not exist, maybe invalid path or parameter settting.\n", + cRdCfg.GetFileName().c_str()); + return false; + } + } +} + +int VideoStreamIGTLinkReceiver::ParseConfigForClient() +{ + std::string strTag[4]; + while (!cRdCfg.EndOfFile()) + { + strTag->clear(); + long iRd = cRdCfg.ReadLine (&strTag[0]); + if (iRd > 0) + { + if (strTag[0].empty()) + continue; + if (strTag[0].compare ("TCPServerPortNumber") == 0) { + this->TCPServerPort = atoi (strTag[1].c_str()); + if(this->TCPServerPort<0 || this->TCPServerPort>65535) + { + fprintf (stderr, "Invalid parameter for server port number should between 0 and 65525."); + return 1; + } + } + if (strTag[0].compare ("TCPServerIPAddress") == 0) { + this->TCPServerIPAddress = new char[IP4AddressStrLen]; + memcpy(this->TCPServerIPAddress, strTag[1].c_str(), IP4AddressStrLen); + if(!inet_addr(this->TCPServerIPAddress)) + { + fprintf (stderr, "Invalid parameter for IP address"); + return 1; + } + } + if (strTag[0].compare ("UDPClientPortNumber") == 0) { + this->UDPClientPort = atoi (strTag[1].c_str()); + if(this->UDPClientPort<0 || this->UDPClientPort>65535) + { + fprintf (stderr, "Invalid parameter for server port number should between 0 and 65525."); + return 1; + } + } + if (strTag[0].compare ("DeviceName") == 0) + { + this->deviceName =strTag[1].c_str(); + } + if (strTag[0].compare ("TransportMethod") == 0) + { + this->transportMethod = atoi(strTag[1].c_str()); + } + + if (strTag[0].compare ("DecodedFile") == 0) + { + this->kpOuputFileName = std::string(strTag[1].c_str()); + } + } + } + return 0; +} + +void VideoStreamIGTLinkReceiver::SetWidth(int iWidth) +{ + this->Width = iWidth; +} + +void VideoStreamIGTLinkReceiver::SetHeight(int iHeight) +{ + this->Height = iHeight; +} + +void VideoStreamIGTLinkReceiver::InitializeDecodedFrame() +{ + if (!(this->decodedFrame == NULL)) + { + delete[] this->decodedFrame; + } + this->decodedFrame = NULL; + this->decodedFrame = new unsigned char[this->Width*this->Height*3>>1]; +} + +int VideoStreamIGTLinkReceiver::ProcessVideoStream(igtl_uint8* bitStream, int streamLength) +{ + //std::cerr << "Receiving Video data type." << std::endl; + //this->videoMessageBuffer = new igtl_uint8[StreamLength]; + //memcpy(this->videoMessageBuffer, bitStream, StreamLength);// copy slow down the process, however, the videoMsg is a smart pointer, it gets deleted unpredictable. + if(!decodeInstance) + { + return 0; + } + + this->InitializeDecodedFrame(); + igtl_uint32 dimensions[2] = {static_cast(Width), static_cast(Height)}; + igtl_uint64 bitStreamLength = streamLength; + int status = decodeInstance->DecodeBitStreamIntoFrame(bitStream, this->decodedFrame, dimensions , bitStreamLength); + // return 2 for succefully decode one frame + FILE* pYuvFile = NULL; + // Lenght input mode support + if (kpOuputFileName.c_str()) + { + pYuvFile = fopen (kpOuputFileName.c_str(), "ab"); + if (pYuvFile == NULL) + { + fprintf (stderr, "Can not open yuv file to output result of decoding..\n"); + } + } + igtl_uint32 stride[2] = {static_cast(Width), static_cast(Width/2)}; + SourcePicture pic; + pic.data[0] = this->decodedFrame; + pic.data[1] = this->decodedFrame+Width*Height; + pic.data[2] = this->decodedFrame+Width*Height*5/4; + //pic.data[0] = + if(pYuvFile) + { + decodeInstance->Write2File (pYuvFile, pic.data, dimensions, stride); + fclose (pYuvFile); + } + return status; +} + +}// namespace igtl + diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkReceiver.h b/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkReceiver.h new file mode 100644 index 0000000..aa7c8eb --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkReceiver.h @@ -0,0 +1,129 @@ +/*========================================================================= + + Program: OpenIGTLink + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#ifndef __igtVideoStreamIGTLinkReceiver_h +#define __igtVideoStreamIGTLinkReceiver_h + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define WIN32_LEAN_AND_MEAN +#include +#include +// need link with Ws2_32.lib +#pragma comment(lib, "Ws2_32.lib") +#else +#include +#endif + +#include +#include +#include +#include +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlVideoMessage.h" +#include "igtlServerSocket.h" +#include "igtlMultiThreader.h" +#include "igtlUDPClientSocket.h" +#include "igtlMessageRTPWrapper.h" +#include "igtlConditionVariable.h" +#include "igtlTimeStamp.h" +#include "igtlCodecCommonClasses.h" + +namespace igtl { + +class IGTLCommon_EXPORT VideoStreamIGTLinkReceiver +{ +public: + VideoStreamIGTLinkReceiver(char * fileName); + + ~VideoStreamIGTLinkReceiver(); + + int ProcessVideoStream(igtl_uint8* bitStream, int streamLength); + + void SetDecoder(GenericDecoder* decoder); + + bool InitializeClient(); + + void SendStopMessage(); + + int ParseConfigForClient(); + + void SetWidth(int iWidth); + + void SetHeight(int iHeight); + + int GetWidth(){return Width;}; + + int GetHeight(){return Height;}; + + void InitializeDecodedFrame(); + + int RunOnTCPSocket(); + + int RunOnUDPSocket(); + + enum + { + RunOnTCP = 0, + RunOnUDP = 1 + }; + + int GetTransportMethod(){return transportMethod;} + + std::string GetDeviceName(){return deviceName;} + +private: + + GenericDecoder* decodeInstance; + + std::string deviceName; + + int transportMethod; + + unsigned char* decodedFrame; + + std::string kpOuputFileName; + + igtl::MutexLock::Pointer glock; + + igtl::ClientSocket::Pointer socket; + + igtl::UDPClientSocket::Pointer UDPSocket; + + igtl_uint8 * videoMessageBuffer; + + int interval; + + ReadConfigFile cRdCfg; + + int TCPServerPort; + + int UDPClientPort; + + char * TCPServerIPAddress; + + igtl::MessageRTPWrapper::Pointer rtpWrapper; + + char codecType[IGTL_VIDEO_CODEC_NAME_SIZE]; + + int Width; + + int Height; + + std::string configFile; + +}; + + +} // namespace igtl +#endif diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkServer.cxx b/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkServer.cxx new file mode 100644 index 0000000..50897a5 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkServer.cxx @@ -0,0 +1,751 @@ +/*========================================================================= + + Program: VideoStreamIGTLinkServer + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlVideoStreamIGTLinkServer.h" + +namespace igtl { + +static void* ThreadFunctionServer(void* ptr); + +VideoStreamIGTLinkServer::VideoStreamIGTLinkServer(char *argv) +{ + this->videoEncoder = NULL; + pSrcPic = new SourcePicture(); + pSrcPic->colorFormat = FormatI420; + pSrcPic->timeStamp = 0; + this->serverConnected = false; + this->waitSTTCommand = true; + this->serverIsSet = false; + this->serverPortNumber = -1; + this->deviceName = ""; + this->serverSocket = igtl::ServerSocket::New(); + this->serverUDPSocket = igtl::UDPServerSocket::New(); + this->socket = igtl::Socket::New();; + this->conditionVar = igtl::ConditionVariable::New(); + this->glock = igtl::SimpleMutexLock::New(); + this->glockInFrame = igtl::SimpleMutexLock::New(); + this->threader = igtl::MultiThreader::New(); + this->rtpWrapper = igtl::MessageRTPWrapper::New(); + this->ServerTimer = igtl::TimeStamp::New(); + this->incommingFrames.clear(); + this->encodedFrames.clear(); + this->netWorkBandWidth = 10000; // in Kbps + this->interval = 30; //in ms + this->transportMethod = UseTCP; + this->totalCompressedDataSize = 0; + this->iTotalFrameToEncode = -1; + this->sendPacketThreadID = -1; + this->readFrameThreadID = -1; + this->serverThreadID = -1; + this->augments = std::string(argv); + if(this->augments.c_str()) + { + SetupServer(); + } +} + +int VideoStreamIGTLinkServer::SetEncoder(GenericEncoder* encoder) +{ + this->videoEncoder = encoder; + videoEncoder->SetPicWidthAndHeight(pSrcPic->picWidth,pSrcPic->picHeight); + return 0; +} + +int VideoStreamIGTLinkServer::StartTCPServer () +{ + if (this->serverIsSet) + { + + if(this->transportMethod==VideoStreamIGTLinkServer::UseTCP) + { + serverThreadID = threader->SpawnThread((igtl::ThreadFunctionType)&ThreadFunctionServer, this); + this->glock->Lock(); + while(!this->serverConnected) + { + this->conditionVar->Wait(this->glock); + igtl::Sleep(10); + } + this->glock->Unlock(); + return true; + } + } + else + { + return false; + } + return false; +} + +int VideoStreamIGTLinkServer::StartUDPServer () +{ + if (this->serverIsSet) + { + + if (this->transportMethod == VideoStreamIGTLinkServer::UseUDP) + { + int r = -1; + if (this->serverUDPSocket.IsNotNull()) + { + this->serverUDPSocket->CloseSocket(); + } + r = this->serverUDPSocket->CreateUDPServer(); + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + return true; + } + } + else + { + return false; + } + return false; +} + +int VideoStreamIGTLinkServer::ParseConfigForServer() +{ + std::string strTag[4]; + while (!cRdCfg.EndOfFile()) { + strTag->clear(); + long iRd = cRdCfg.ReadLine (&strTag[0]); + if (iRd > 0) { + if (strTag[0].empty()) + continue; + if (strTag[0].compare ("ServerPortNumber") == 0) { + this->serverPortNumber = atoi (strTag[1].c_str()); + if(this->serverPortNumber<0 || this->serverPortNumber>65535) + { + fprintf (stderr, "Invalid parameter for server port number should between 0 and 65525."); + return 1; + } + } + if (strTag[0].compare ("ClientIPAddress") == 0) { + this->clientIPAddress = new char[IP4AddressStrLen]; + memcpy(this->clientIPAddress, strTag[1].c_str(), IP4AddressStrLen); + if(!inet_addr(this->clientIPAddress)) + { + fprintf (stderr, "Invalid parameter for IP address"); + return 1; + } + } + if (strTag[0].compare ("ClientPortNumber") == 0) { + this->clientPortNumber = atoi (strTag[1].c_str()); + if(this->clientPortNumber<0 || this->clientPortNumber>65535) + { + fprintf (stderr, "Invalid parameter for server port number should between 0 and 65525."); + return 1; + } + } + if (strTag[0].compare ("InputFile") == 0) + { + this->strSeqFile =strTag[1].c_str(); + } + if (strTag[0].compare ("SourceWidth") == 0) + { + this->pSrcPic->picWidth = atoi(strTag[1].c_str()); + pSrcPic->stride[0] = this->pSrcPic->picWidth; + pSrcPic->stride[1] = pSrcPic->stride[2] = pSrcPic->stride[0] >> 1; + } + if (strTag[0].compare ("SourceHeight") == 0) + { + this->pSrcPic->picHeight = atoi(strTag[1].c_str()); + } + if (strTag[0].compare ("TotalFrameToEncode") == 0) + { + this->iTotalFrameToEncode = atoi(strTag[1].c_str()); + } + if (strTag[0].compare ("OutputBitStreamFile") == 0) + { + this->strOutputFile =strTag[1].c_str(); + } + if (strTag[0].compare ("CodecConfigurationFile") == 0) + { + this->encoderConfigFile = strTag[1]; + } + if (strTag[0].compare ("DeviceName") == 0) + { + this->deviceName =strTag[1].c_str(); + } + if (strTag[0].compare ("TransportMethod") == 0) + { + this->transportMethod = atoi(strTag[1].c_str()); + } + if (strTag[0].compare ("NetWorkBandWidth") == 0) + { + this->netWorkBandWidth = atoi(strTag[1].c_str()); + int netWorkBandWidthInBPS = netWorkBandWidth * 1000; //networkBandwidth is in kbps + int time = floor(8*RTP_PAYLOAD_LENGTH*1e9/netWorkBandWidthInBPS+ 1.0); // the needed time in nanosecond to send a RTP payload. + this->rtpWrapper->packetIntervalTime = time; // in nanoSecond + } + } + } + pSrcPic->data[0] = new unsigned char[pSrcPic->picHeight*pSrcPic->picWidth*3/2]; + pSrcPic->data[1] = pSrcPic->data[0]+pSrcPic->picHeight*pSrcPic->picWidth; + pSrcPic->data[2] = pSrcPic->data[1]+pSrcPic->picHeight*pSrcPic->picWidth/4; + if (this->transportMethod == 1 ) + { + if (this->clientIPAddress && this->clientPortNumber) + { + this->serverUDPSocket->AddClient(this->clientIPAddress, this->clientPortNumber, 0); + } + else + { + return 1; + } + } + return 0; +} + +int VideoStreamIGTLinkServer::InitializeEncoder() +{ + int iRet = 1; + if( this->videoEncoder && (pSrcPic->picWidth*pSrcPic->picHeight>0) && this->encoderConfigFile.c_str()) + { + this->videoEncoder->SetConfigurationFile(encoderConfigFile); + this->videoEncoder->SetPicWidthAndHeight(pSrcPic->picWidth,pSrcPic->picHeight); + iRet = this->videoEncoder->InitializeEncoder(); + } + return iRet; +} + +static void* ThreadFunctionServer(void* ptr) +{ + //------------------------------------------------------------ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + VideoStreamIGTLinkServer* parentObj = static_cast(info->UserData); + int r = -1; + if (parentObj->serverSocket.IsNotNull()) + { + parentObj->serverSocket->CloseSocket(); + } + r = parentObj->serverSocket->CreateServer(parentObj->serverPortNumber); + if (r < 0) + { + std::cerr << "Cannot create a server socket." << std::endl; + exit(0); + } + parentObj->socket = igtl::Socket::New(); + + while (1) + { + //------------------------------------------------------------ + // Waiting for Connection + parentObj->serverConnected = false; + parentObj->socket = parentObj->serverSocket->WaitForConnection(1000); + + if (parentObj->socket.IsNotNull()) // if client connected + { + std::cerr << "A client is connected." << std::endl; + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + if (!parentObj->waitSTTCommand) + { + // Create a message buffer to receive header + strncpy(parentObj->codecName, "H264", IGTL_VIDEO_CODEC_NAME_SIZE); + parentObj->serverIsSet = false; + parentObj->serverConnected = true; + parentObj->conditionVar->Signal(); + while (parentObj->serverConnected) + { + headerMsg->InitPack(); + bool timeout(false); + int rs = parentObj->socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Disconnecting the client." << std::endl; + break; + } + else + { + igtl::Sleep(10); + } + } + } + else if (parentObj->waitSTTCommand) + { + //------------------------------------------------------------ + // loop + for (;;) + { + // Initialize receive buffer + headerMsg->InitPack(); + bool timeout(false); + // Receive generic header from the socket + int rs = parentObj->socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout); + if (rs == 0) + { + std::cerr << "Disconnecting the client." << std::endl; + break; + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + + // Check data type and receive data body + if (strcmp(headerMsg->GetDeviceType(), "STP_VIDEO") == 0) + { + parentObj->glock->Lock(); + parentObj->socket->Skip(headerMsg->GetBodySizeToRead(), 0); + std::cerr << "Received a STP_VIDEO message." << std::endl; + std::cerr << "Disconnecting the client." << std::endl; + parentObj->serverIsSet = false; + parentObj->serverConnected = false; + if (parentObj->socket.IsNotNull()) + { + parentObj->socket->CloseSocket(); + } + parentObj->glock->Unlock(); + parentObj->socket = NULL; // VERY IMPORTANT. Completely remove the instance. + break; + } + else if (strcmp(headerMsg->GetDeviceType(), "STT_VIDEO") == 0) + { + std::cerr << "Received a STT_VIDEO message." << std::endl; + + igtl::StartVideoMessage::Pointer startVideoMsg; + startVideoMsg = igtl::StartVideoMessage::New(); + startVideoMsg->SetMessageHeader(headerMsg); + startVideoMsg->AllocatePack(); + parentObj->glock->Lock(); + bool timeout(false); + parentObj->socket->Receive(startVideoMsg->GetPackBodyPointer(), startVideoMsg->GetPackBodySize(), timeout); + parentObj->glock->Unlock(); + int c = startVideoMsg->Unpack(1); + if (c & igtl::MessageHeader::UNPACK_BODY && strcmp(startVideoMsg->GetCodecType().c_str(), "H264")) // if CRC check is OK + { + parentObj->interval = startVideoMsg->GetTimeInterval(); + strncpy(parentObj->codecName, startVideoMsg->GetCodecType().c_str(), IGTL_VIDEO_CODEC_NAME_SIZE); + parentObj->serverConnected = true; + parentObj->conditionVar->Signal(); + } + } + else + { + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + parentObj->glock->Lock(); + parentObj->socket->Skip(headerMsg->GetBodySizeToRead(), 0); + parentObj->glock->Unlock(); + } + igtl::Sleep(100); + } + } + } + } + + //------------------------------------------------------------ + // Close connection (The example code never reaches to this section ...) + parentObj->serverSocket->CloseSocket(); + parentObj->glock->Lock(); + if (parentObj->socket.IsNotNull()) + { + parentObj->socket->CloseSocket(); + } + parentObj->glock->Unlock(); + parentObj->socket = NULL; // VERY IMPORTANT. Completely remove the instance. + parentObj->serverSocket = NULL; +} + +void VideoStreamIGTLinkServer::SetSrcPicWidth(int width) +{ + pSrcPic->picWidth = width; +} + +void VideoStreamIGTLinkServer::SetSrcPicHeight(int height) +{ + pSrcPic->picHeight = height; +} + +int VideoStreamIGTLinkServer::SetupServer() +{ + //------------------------------------------------------------ + int iRet = 0; + if (this->videoEncoder == NULL) + iRet = 1; + + this->iTotalFrameToEncode = 0; + + // Preparing encoding process + + // Inactive with sink with output file handler + FILE* pFpBs = NULL; + if (pSrcPic == NULL) { + iRet = 1; + goto INSIDE_MEM_FREE; + } + //fill default pSrcPic + pSrcPic->colorFormat = FormatI420;//videoFormatI420; + pSrcPic->timeStamp = 0; + + // if configure file exit, reading configure file firstly + cRdCfg.OpenFile(this->augments.c_str());// to do get the first augments from this->augments. + if (cRdCfg.ExistFile()) + { + cRdCfg.OpenFile(this->augments.c_str());// reset the file read pointer to the beginning. + iRet = ParseConfigForServer(); + if (iRet) { + fprintf (stderr, "parse server parameter config file failed.\n"); + iRet = 1; + goto INSIDE_MEM_FREE; + } + } + else + { + fprintf (stderr, "Specified file: %s not exist, maybe invalid path or parameter settting.\n", + cRdCfg.GetFileName().c_str()); + iRet = 1; + goto INSIDE_MEM_FREE; + } + + //finish reading the configurations + igtl_uint32 iSourceWidth, iSourceHeight, kiPicResSize; + iSourceWidth = pSrcPic->picWidth; + iSourceHeight = pSrcPic->picHeight; + kiPicResSize = iSourceWidth * iSourceHeight * 3 >> 1; + + //update pSrcPic + pSrcPic->stride[0] = iSourceWidth; + pSrcPic->stride[1] = pSrcPic->stride[2] = pSrcPic->stride[0] >> 1; + pSrcPic->stride[3] = 0; + + this->serverIsSet = true; + return true; +INSIDE_MEM_FREE: + if (pFpBs) { + fclose (pFpBs); + pFpBs = NULL; + } + if (pSrcPic) { + delete pSrcPic; + pSrcPic = NULL; + } + this->serverConnected = false; + this->serverIsSet = false; + return iRet; +} + +struct serverPointer +{ + VideoStreamIGTLinkServer* server; +}; + +static void* ThreadFunctionReadFrameFromFile(void* ptr) +{ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + serverPointer parentObj = *(static_cast(info->UserData)); + int kiPicResSize = parentObj.server->pSrcPic->picWidth*parentObj.server->pSrcPic->picHeight*3>>1; + igtl_int32 iFrameNumInFile = -1; + FILE* pFileYUV = NULL; + pFileYUV = fopen (parentObj.server->strSeqFile.c_str(), "rb"); + if (pFileYUV != NULL) { +#if defined(_WIN32) || defined(_WIN64) +#if _MSC_VER >= 1400 + if (!_fseeki64 (pFileYUV, 0, SEEK_END)) { + igtl_int64 i_size = _ftelli64 (pFileYUV); + _fseeki64 (pFileYUV, 0, SEEK_SET); + iFrameNumInFile = max ((igtl_int32) (i_size / kiPicResSize), iFrameNumInFile); + } +#else + if (!fseek (pFileYUV, 0, SEEK_END)) { + igtl_int64 i_size = ftell (pFileYUV); + fseek (pFileYUV, 0, SEEK_SET); + iFrameNumInFile = max ((igtl_int32) (i_size / kiPicResSize), iFrameNumInFile); + } +#endif +#else + if (!fseeko (pFileYUV, 0, SEEK_END)) { + igtl_int64 i_size = ftello (pFileYUV); + fseeko (pFileYUV, 0, SEEK_SET); + iFrameNumInFile = std::max((igtl_int32) (i_size / kiPicResSize), iFrameNumInFile); + } +#endif + igtl_int32 iFrameIdx = 0; + while((igtl_int32)parentObj.server->iTotalFrameToEncode > 0) + { + iFrameIdx = 0; +#if defined(_WIN32) || defined(_WIN64) +#if _MSC_VER >= 1400 + _fseeki64(pFileYUV, 0, SEEK_SET); +#else + fseek(pFileYUV, 0, SEEK_SET); +#endif +#else + fseeko(pFileYUV, 0, SEEK_SET); +#endif + while (iFrameIdx < iFrameNumInFile && iFrameIdx < parentObj.server->iTotalFrameToEncode) { + bool bCanBeRead = false; + igtl_uint8* pYUV = new igtl_uint8[kiPicResSize]; + bCanBeRead = (fread (pYUV, 1, kiPicResSize, pFileYUV) == kiPicResSize); + parentObj.server->glockInFrame->Lock(); + if (parentObj.server->incommingFrames.size()>3) + { + std::map::iterator it = parentObj.server->incommingFrames.begin(); + delete it->second; + it->second = NULL; + parentObj.server->incommingFrames.erase(it); + } + parentObj.server->incommingFrames.insert(std::pair(0, pYUV)); + parentObj.server->glockInFrame->Unlock(); + parentObj.server->iTotalFrameToEncode = parentObj.server->iTotalFrameToEncode - 1; // excluding skipped frame time + igtl::Sleep(parentObj.server->interval); + if (!bCanBeRead) + break; + } + } + if (pFileYUV) + { + fclose(pFileYUV); + pFileYUV = NULL; + } + } else { + fprintf (stderr, "Unable to open source sequence file (%s), check corresponding path!\n", + parentObj.server->strSeqFile.c_str()); + } + + return NULL; +} + + +static void* ThreadFunctionSendPacket(void* ptr) +{ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + serverPointer parentObj = *(static_cast(info->UserData)); + while(1) + { + parentObj.server->glock->Lock(); + unsigned int frameNum = parentObj.server->encodedFrames.size(); + parentObj.server->glock->Unlock(); + if(frameNum) + { + parentObj.server->glock->Lock(); + VideoStreamIGTLinkServer::encodedFrame* frameCopy = new VideoStreamIGTLinkServer::encodedFrame(); + std::map::iterator it = parentObj.server->encodedFrames.begin(); + frameCopy->messageDataLength = it->second->messageDataLength; + memcpy(frameCopy->messagePackPointer,it->second->messagePackPointer,it->second->messageDataLength); + delete it->second; + it->second = NULL; + parentObj.server->encodedFrames.erase(it); + if (parentObj.server->transportMethod == VideoStreamIGTLinkServer::UseUDP) + { + parentObj.server->rtpWrapper->WrapMessageAndSend(parentObj.server->serverUDPSocket, frameCopy->messagePackPointer, frameCopy->messageDataLength); + } + else if(parentObj.server->transportMethod == VideoStreamIGTLinkServer::UseTCP) + { + if(parentObj.server->socket) + { + parentObj.server->socket->Send(frameCopy->messagePackPointer, frameCopy->messageDataLength); + } + } + parentObj.server->glock->Unlock(); + delete frameCopy; + } + igtl::Sleep(1); + } +} + +int VideoStreamIGTLinkServer::StartReadFrameThread(int frameRate) +{ + this->interval = 1000/frameRate; + serverPointer ptr; + ptr.server = this; + readFrameThreadID = threader->SpawnThread((igtl::ThreadFunctionType)&ThreadFunctionReadFrameFromFile, &ptr); + igtl::Sleep(10); + return readFrameThreadID; +} + +int VideoStreamIGTLinkServer::StartSendPacketThread() +{ + serverPointer ptr; + ptr.server = this; + sendPacketThreadID = threader->SpawnThread((igtl::ThreadFunctionType)&ThreadFunctionSendPacket, &ptr); + igtl::Sleep(10); + return sendPacketThreadID; +} + +void VideoStreamIGTLinkServer::CheckEncodedFrameMap() +{ + if(this->encodedFrames.size()>5) + { + std::map::iterator it = this->encodedFrames.begin(); + delete it->second; + it->second = NULL; + this->encodedFrames.erase(it); + } +} + +void VideoStreamIGTLinkServer::SendOriginalData() +{ + int kiPicResSize = pSrcPic->picWidth*pSrcPic->picHeight*3>>1; + igtl_uint8* pYUV = new igtl_uint8[kiPicResSize]; + static int messageID = -1; + while(this->iTotalFrameToEncode) + { + this->glockInFrame->Lock(); + int frameNum = this->incommingFrames.size(); + this->glockInFrame->Unlock(); + while(frameNum) + { + this->glockInFrame->Lock(); + std::map::iterator it = this->incommingFrames.begin(); + memcpy(pYUV,it->second,kiPicResSize); + delete it->second; + it->second = NULL; + this->incommingFrames.erase(it); + frameNum = this->incommingFrames.size(); + this->glockInFrame->Unlock(); + messageID ++; + igtl::VideoMessage::Pointer videoMsg; + videoMsg = igtl::VideoMessage::New(); + videoMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + videoMsg->SetDeviceName(this->deviceName.c_str()); + videoMsg->SetBitStreamSize(kiPicResSize); + videoMsg->AllocateScalars(); + int endian = (igtl_is_little_endian() == 1 ? IGTL_VIDEO_ENDIAN_LITTLE : IGTL_VIDEO_ENDIAN_BIG); + videoMsg->SetEndian(endian); //little endian is 2 big endian is 1 + videoMsg->SetWidth(pSrcPic->picWidth); + videoMsg->SetHeight(pSrcPic->picHeight); + memcpy(videoMsg->GetPackFragmentPointer(2), pYUV, kiPicResSize); + ServerTimer->GetTime(); + videoMsg->SetTimeStamp(ServerTimer); + videoMsg->Pack(); + encodedFrame* frame = new encodedFrame(); + memcpy(frame->messagePackPointer, videoMsg->GetPackPointer(), videoMsg->GetBufferSize()); + frame->messageDataLength = videoMsg->GetBufferSize(); + this->glock->Lock(); + this->CheckEncodedFrameMap(); + this->encodedFrames.insert(std::pair(messageID, frame)); + this->glock->Unlock(); + } + } + delete[] pYUV; + pYUV = NULL; +} + +int VideoStreamIGTLinkServer::EncodeFile(void) +{ + if(!this->videoEncoder) + { + return -1; + } + if(!this->serverIsSet) + { + this->SetupServer(); + } + igtl_int64 iStart = 0, iTotal = 0; + + int picSize = pSrcPic->picWidth*pSrcPic->picHeight; + + igtl_int32 iFrameIdx = 0; + this->totalCompressedDataSize = 0; + int iActualFrameEncodedCount = 0; + while(this->iTotalFrameToEncode) + { + this->glockInFrame->Lock(); + int frameNum = this->incommingFrames.size(); + this->glockInFrame->Unlock(); + while(frameNum) + { + // To encoder this frame + this->glockInFrame->Lock(); + std::map::iterator it = this->incommingFrames.begin(); + memcpy(this->pSrcPic->data[0],it->second,picSize*3/2); + delete it->second; + it->second = NULL; + this->incommingFrames.erase(it); + frameNum = this->incommingFrames.size(); + this->glockInFrame->Unlock(); + this->ServerTimer->GetTime(); + this->encodeStartTime = this->ServerTimer->GetTimeStampInNanoseconds(); + iStart = this->encodeStartTime; + igtl::VideoMessage::Pointer videoMsg = igtl::VideoMessage::New(); + videoMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + videoMsg->SetDeviceName(this->deviceName.c_str()); + int iEncFrames = this->videoEncoder->EncodeSingleFrameIntoVideoMSG(this->pSrcPic, videoMsg, false); + this->ServerTimer->GetTime(); + this->encodeEndTime = this->ServerTimer->GetTimeStampInNanoseconds(); + iTotal += this->encodeEndTime - iStart; + ++ iFrameIdx; + if (this->videoEncoder->GetVideoFrameType() == FrameTypeSkip) { + continue; + } + + if (iEncFrames == ResultSuccess ) { + static int messageID = -1; + messageID++; + this->totalCompressedDataSize += videoMsg->GetPackedBitStreamSize(); + encodedFrame* frame = new encodedFrame(); + memcpy(frame->messagePackPointer, videoMsg->GetPackPointer(), videoMsg->GetBufferSize()); + frame->messageDataLength = videoMsg->GetBufferSize(); + this->glock->Lock(); + this->CheckEncodedFrameMap(); + this->encodedFrames.insert(std::pair(messageID, frame)); + this->glock->Unlock(); + igtl::Sleep(5); + iActualFrameEncodedCount ++; + } else { + fprintf (stderr, "EncodeFrame(), ret: %d, frame index: %d.\n", iEncFrames, iFrameIdx); + } + if (iActualFrameEncodedCount%10 == 0) { + double dElapsed = iTotal / 1e9; + float totalFrameSize = iActualFrameEncodedCount*3/2.0*this->pSrcPic->picWidth*this->pSrcPic->picHeight; + printf ("Width:\t\t%d\nHeight:\t\t%d\nFrames:\t\t%d\nencode time:\t%f sec\nFPS:\t\t%f fps\nCompressionRate:\t\t%f\n", + this->pSrcPic->picWidth, this->pSrcPic->picHeight, + iActualFrameEncodedCount, dElapsed, (iActualFrameEncodedCount * 1.0) / dElapsed, totalCompressedDataSize/totalFrameSize); + } + } + } + return 0; +} + +void VideoStreamIGTLinkServer::Stop() +{ + if(serverThreadID>=0) + threader->TerminateThread(serverThreadID); + if(readFrameThreadID>=0) + threader->TerminateThread(readFrameThreadID); + if(sendPacketThreadID>=0) + threader->TerminateThread(sendPacketThreadID); + this->serverSocket->CloseSocket(); +} + +int VideoStreamIGTLinkServer::EncodeSingleFrame(igtl_uint8* picPointer, bool isGrayImage) +{ + int encodeRet = -1; + if (this->serverIsSet == true && this->videoEncoder) + { + int iSourceWidth = pSrcPic->picWidth; + int iSourceHeight = pSrcPic->picHeight; + pSrcPic->data[0] = picPointer; + pSrcPic->data[1] = pSrcPic->data[0] + (iSourceWidth * iSourceHeight); + pSrcPic->data[2] = pSrcPic->data[1] + (iSourceWidth * iSourceHeight >> 2); + igtl::VideoMessage::Pointer videoMsg = igtl::VideoMessage::New(); + encodeRet = this->videoEncoder->EncodeSingleFrameIntoVideoMSG(this->pSrcPic, videoMsg, isGrayImage); + this->videoFrameType = videoEncoder->GetVideoFrameType(); + } + return encodeRet; +} + +}//namespace igtl + diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkServer.h b/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkServer.h new file mode 100644 index 0000000..df1f841 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVideoStreamIGTLinkServer.h @@ -0,0 +1,237 @@ +/*========================================================================= + + Program: OpenIGTLink + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtVideoStreamIGTLinkServer_h +#define __igtVideoStreamIGTLinkServer_h + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define WIN32_LEAN_AND_MEAN +#include +#include +// need link with Ws2_32.lib +#pragma comment(lib, "Ws2_32.lib") +#else +#include +#endif + +#include +#include +#include +#include +#include +#include "igtl_header.h" +#include "igtl_video.h" +#include "igtlOSUtil.h" +#include "igtlMessageHeader.h" +#include "igtlVideoMessage.h" +#include "igtlServerSocket.h" +#include "igtlUDPServerSocket.h" +#include "igtlMultiThreader.h" +#include "igtlConditionVariable.h" +#include "igtlMessageRTPWrapper.h" +#include "igtlTimeStamp.h" +#include "igtlCodecCommonClasses.h" + +namespace igtl { + +class IGTLCommon_EXPORT VideoStreamIGTLinkServer +{ +public: + VideoStreamIGTLinkServer(char *argv); + ~VideoStreamIGTLinkServer(){}; + + /** + Start the server, this function will be holding the main program for a client connection. + */ + int StartTCPServer(); + + /** + Start the server, this function will be holding the main program for a client connection. + */ + int StartUDPServer(); + + /** + Parse the configuration file to initialize the encoder and server. + */ + int SetupServer(); + + int SetEncoder(GenericEncoder* encoder); + /** + intialize the encoder + */ + int InitializeEncoder(); + + /** + Set the picture width + */ + void SetSrcPicWidth(int width); + + /** + Set the picture height + */ + void SetSrcPicHeight(int height); + + /** + Encode a frame, for performance issue, before encode the frame, make sure the frame pointer is updated with a new frame. + Otherwize, the old frame will be encoded. + */ + int EncodeSingleFrame(igtl_uint8* picPointer, bool isGrayImage = false); + + /** + Pack the encoded frame into a OpenIGTLink message and send the message to a client. + */ + void SendCompressedData(); + + /** + Pack the original frame into a OpenIGTLink message and send the message to a client. + */ + void SendOriginalData(); + + /** + Set the server to wait for STT command or just send the bitstream when connection is setup. + */ + void SetWaitSTTCommand(bool needSTTCommand){ waitSTTCommand = needSTTCommand;}; + + /** + Get the encoder and server initialization status. + */ + bool GetServerSetStatus(){return serverIsSet;}; + + /** + Get Server connection status, true for connected, false for not connected + */ + bool GetServerConnectStatus(){return serverConnected == 1;} + + /** + Encode the video stream from a source file + */ + int EncodeFile(void); + + /** + Get the type of encoded frame + */ + int GetVideoFrameType(){return videoFrameType;}; + + int ParseConfigForServer(); + + enum TransportMethod + { + UseTCP, + UseUDP + }; + + void Stop(); + + igtl::MultiThreader::Pointer threader; + + igtl::SimpleMutexLock* glockInFrame; + + igtl::SimpleMutexLock* glock; + + igtl::Socket::Pointer socket; + + igtl::ServerSocket::Pointer serverSocket; + + igtl::UDPServerSocket::Pointer serverUDPSocket; + + igtl::MessageRTPWrapper::Pointer rtpWrapper; + + GenericEncoder* videoEncoder; + + // for server configuration file + + ReadConfigFile cRdCfg; + + std::string strSeqFile; + + std::string strOutputFile; + + SourcePicture* pSrcPic; + + igtlUint64 encodeStartTime; + + igtlUint64 encodeEndTime; + + igtl::ConditionVariable::Pointer conditionVar; + + int videoFrameType; + + int interval; + + int netWorkBandWidth; // in kbps + + char codecName[IGTL_VIDEO_CODEC_NAME_SIZE]; + + int serverConnected; + + int serverPortNumber; + + char* clientIPAddress; + + int clientPortNumber; + + int argc; + + std::string augments; + + bool waitSTTCommand; + + std::string deviceName; + + int transportMethod; + + bool serverIsSet; + + igtl::TimeStamp::Pointer ServerTimer; + + class encodedFrame + { + public: + encodedFrame(){messageDataLength = 0;}; + encodedFrame(encodedFrame const &anotherFrame){}; + ~encodedFrame(){}; + unsigned char messagePackPointer[RTP_PAYLOAD_LENGTH*(16384-2)]; // we use 14 bits for fragment number, 2^14 = 16384. maximum + igtl_uint32 messageDataLength; + }; + + std::map incommingFrames; + + std::map encodedFrames; + + int iTotalFrameToEncode; + + int StartSendPacketThread(); + + int StartReadFrameThread(int frameRate); + +private: + + void CheckEncodedFrameMap(); + + void ReadInFileWithFrameRate(int rate); + + unsigned long totalCompressedDataSize; + + std::string encoderConfigFile; + + int serverThreadID; + + int sendPacketThreadID; + + int readFrameThreadID; + +}; + +} //Namespace igtl + +#endif diff --git a/openigtlink/repo/Source/VideoStreaming/igtlVideoStreaming.cmake b/openigtlink/repo/Source/VideoStreaming/igtlVideoStreaming.cmake new file mode 100644 index 0000000..3258281 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtlVideoStreaming.cmake @@ -0,0 +1,166 @@ +LIST(APPEND OpenIGTLink_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/Source/VideoStreaming) +LIST(APPEND OpenIGTLink_SOURCES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtl_video.c + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtl_videometa.c + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVideoMessage.cxx + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVideoStreamIGTLinkServer.cxx + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVideoStreamIGTLinkReceiver.cxx + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlCodecCommonClasses.cxx + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVideoMetaMessage.cxx + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlI420Decoder.cxx + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlI420Encoder.cxx + ) +LIST(APPEND OpenIGTLink_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming + ) +LIST(APPEND OpenIGTLink_INCLUDE_FILES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtl_video.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtl_videometa.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVideoMessage.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVideoStreamIGTLinkServer.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVideoStreamIGTLinkReceiver.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlCodecCommonClasses.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVideoMetaMessage.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlI420Decoder.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlI420Encoder.h + ) +IF(OpenIGTLink_USE_H264) + INCLUDE(${OpenIGTLink_SOURCE_DIR}/SuperBuild/External_openh264.cmake) + IF(EXISTS ${OpenH264_LIBRARY_DIR}) + LIST(APPEND OpenIGTLink_SOURCES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlH264Decoder.cxx + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlH264Encoder.cxx + ) + LIST(APPEND OpenIGTLink_INCLUDE_FILES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlH264Decoder.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlH264Encoder.h + ) + LIST(APPEND OpenIGTLink_INCLUDE_DIRS + ${OpenH264_INCLUDE_DIR} + ) + ELSE() + MESSAGE("H264_LIBRARY no found. You could specify OpenH264_INCLUDE_DIR or OpenH264_LIBRARY_DIR") + ENDIF() +ENDIF() +IF(OpenIGTLink_USE_VP9) + INCLUDE(${OpenIGTLink_SOURCE_DIR}/SuperBuild/External_VP9.cmake) + IF((NOT "${VP9_LIBRARY_DIR}" STREQUAL "") AND (NOT "${VP9_INCLUDE_DIR}" STREQUAL "")) + LIST(APPEND OpenIGTLink_INCLUDE_DIRS + ${VP9_INCLUDE_DIR} + ) + LIST(APPEND OpenIGTLink_SOURCES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVP9Decoder.cxx + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVP9Encoder.cxx + ) + LIST(APPEND OpenIGTLink_INCLUDE_FILES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVP9Decoder.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlVP9Encoder.h + ) + LINK_DIRECTORIES("${VP9_LIBRARY_DIR}") + ELSE() + MESSAGE("VP9_INCLUDE_DIR or VP9_LIBRARY_DIR no found") + ENDIF() +ENDIF() + +IF(OpenIGTLink_USE_X265) + INCLUDE(${OpenIGTLink_SOURCE_DIR}/SuperBuild/External_X265.cmake) + LIST(APPEND OpenIGTLink_INCLUDE_DIRS + ${X265_INCLUDE_DIR} + ${X265_LIBRARY_DIR} + ) + LIST(APPEND OpenIGTLink_SOURCES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlH265Encoder.cxx + ) + LIST(APPEND OpenIGTLink_INCLUDE_FILES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlH265Encoder.h + ) +ENDIF() + +IF(OpenIGTLink_USE_OpenHEVC) + INCLUDE(${OpenIGTLink_SOURCE_DIR}/SuperBuild/External_openHEVC.cmake) + LIST(APPEND OpenIGTLink_INCLUDE_DIRS + ${OpenHEVC_INCLUDE_DIR} + ) + LIST(APPEND OpenIGTLink_SOURCES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlH265Decoder.cxx + ) + LIST(APPEND OpenIGTLink_INCLUDE_FILES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlH265Decoder.h + ) +ENDIF() + +IF(OpenIGTLink_USE_AV1) + INCLUDE(${OpenIGTLink_SOURCE_DIR}/SuperBuild/External_AV1.cmake) + LIST(APPEND OpenIGTLink_INCLUDE_DIRS + ${AV1_INCLUDE_DIR} + ${AV1_LIBRARY_DIR} + ) + LIST(APPEND OpenIGTLink_SOURCES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlAV1Decoder.cxx + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlAV1Encoder.cxx + ) + LIST(APPEND OpenIGTLink_INCLUDE_FILES + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlAV1Decoder.h + ${PROJECT_SOURCE_DIR}/Source/VideoStreaming/igtlAV1Encoder.h + ) +ENDIF() + +IF(WIN32) # for Windows + IF(OpenIGTLink_USE_H264) + LIST(APPEND LINK_LIBS + ${OpenH264_LIBRARY_DIR}/openh264.lib + ) + ENDIF() + IF(OpenIGTLink_USE_VP9) + #To do, library name depends on the compiler setting, could be vpxmt.lib and vpxmtd also. Make sure the setting matches. + #SET(VP9_lib optimized ${VP9_LIBRARY_DIR}\\Release\\vpxmd.lib debug ${VP9_LIBRARY_DIR}\\Debug\\vpxmdd.lib) + SET(VP9_lib ${VP9_LIBRARY_DIR}\\libvpx.lib) + LIST(APPEND LINK_LIBS + ${VP9_lib} + ) + ENDIF() + IF(OpenIGTLink_USE_X265) + #To do, library name depends on the compiler setting, could be vpxmt.lib and vpxmtd also. Make sure the setting matches. + SET(LINK_X265_LIBRARY optimized ${X265_LIBRARY_DIR}\\Release\\x265-static.lib debug ${X265_LIBRARY_DIR}\\Debug\\x265-static.lib) + LIST(APPEND LINK_LIBS + ${LINK_X265_LIBRARY} + ) + ENDIF() + IF(OpenIGTLink_USE_OpenHEVC) + LIST(APPEND LINK_LIBS + ${OpenHEVC_LIBRARY} + ) + ENDIF() + + IF(OpenIGTLink_USE_AV1) + LIST(APPEND LINK_LIBS + ${AV1_LIBRARY} + ) + ENDIF() +ELSE() # for POSIX-compatible OSs + IF(OpenIGTLink_USE_H264) + LIST(APPEND LINK_LIBS + ${OpenH264_LIBRARY_DIR}/libopenh264.a + ) + ENDIF() + IF(OpenIGTLink_USE_VP9) + LIST(APPEND LINK_LIBS + ${VP9_LIBRARY_DIR}/libvpx.a + ) + ENDIF() + IF(OpenIGTLink_USE_X265) + LIST(APPEND LINK_LIBS + ${X265_LIBRARY_DIR}/libx265.a + ) + ENDIF() + IF(OpenIGTLink_USE_OpenHEVC) + LIST(APPEND LINK_LIBS + ${OpenHEVC_LIBRARY} + ) + ENDIF() + IF(OpenIGTLink_USE_AV1) + LIST(APPEND LINK_LIBS + ${AV1_LIBRARY} + ) + ENDIF() +ENDIF() diff --git a/openigtlink/repo/Source/VideoStreaming/igtl_video.c b/openigtlink/repo/Source/VideoStreaming/igtl_video.c new file mode 100755 index 0000000..db07b0a --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtl_video.c @@ -0,0 +1,181 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_video.h" +#include "igtl_util.h" + +void igtl_export igtl_stt_video_convert_byte_order(igtl_stt_video* stt_video) +{ + igtl_int32* tmp; + + if (igtl_is_little_endian()) + { + tmp = (igtl_int32*)&(stt_video->time_interval); + *tmp = BYTE_SWAP_INT32(*tmp); + } +} + + +igtl_uint64 igtl_export igtl_stt_video_get_crc(igtl_stt_video* stt_video) +{ + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) stt_video, IGTL_STT_VIDEO_SIZE, crc); + return crc; +} + +void igtl_export igtl_frame_convert_byte_order(igtl_frame_header * header) +{ + int i; + igtl_uint32 tmp[12]; + + if (igtl_is_little_endian()) + { + header->header_version = BYTE_SWAP_INT16(header->header_version); + header->frameType = BYTE_SWAP_INT16(header->frameType); + + for (i = 0; i < 3; i++) + { + header->size[i] = BYTE_SWAP_INT16(header->size[i]); + header->subvol_size[i] = BYTE_SWAP_INT16(header->subvol_size[i]); + header->subvol_offset[i] = BYTE_SWAP_INT16(header->subvol_offset[i]); + } + + memcpy(tmp, header->matrix, sizeof(igtl_uint32) * 12); + for (i = 0; i < 12; i++) + { + tmp[i] = BYTE_SWAP_INT32(tmp[i]); + } + memcpy(header->matrix, tmp, sizeof(igtl_uint32) * 12); + } +} + +void igtl_export igtl_frame_set_matrix(float spacing[3], float origin[3], + float norm_i[3], float norm_j[3], float norm_k[3], + igtl_frame_header * header) +{ + header->matrix[0] = (igtl_float32)(norm_i[0] * spacing[0]); + header->matrix[1] = (igtl_float32)(norm_i[1] * spacing[0]); + header->matrix[2] = (igtl_float32)(norm_i[2] * spacing[0]); + header->matrix[3] = (igtl_float32)(norm_j[0] * spacing[1]); + header->matrix[4] = (igtl_float32)(norm_j[1] * spacing[1]); + header->matrix[5] = (igtl_float32)(norm_j[2] * spacing[1]); + header->matrix[6] = (igtl_float32)(norm_k[0] * spacing[2]); + header->matrix[7] = (igtl_float32)(norm_k[1] * spacing[2]); + header->matrix[8] = (igtl_float32)(norm_k[2] * spacing[2]); + header->matrix[9] = (igtl_float32)(origin[0]); + header->matrix[10] = (igtl_float32)(origin[1]); + header->matrix[11] = (igtl_float32)(origin[2]); +} + +void igtl_export igtl_frame_set_matrix_4x4(float _matrix[4][4], igtl_frame_header * header) +{ + header->matrix[0] = _matrix[0][0]; + header->matrix[1] = _matrix[0][1]; + header->matrix[2] = _matrix[0][2]; + header->matrix[3] = _matrix[1][0]; + header->matrix[4] = _matrix[1][1]; + header->matrix[5] = _matrix[1][2]; + header->matrix[6] = _matrix[2][0]; + header->matrix[7] = _matrix[2][1]; + header->matrix[8] = _matrix[2][2]; + header->matrix[9] = _matrix[0][3]; + header->matrix[10] = _matrix[1][3]; + header->matrix[11] = _matrix[2][3]; +} + +void igtl_export igtl_frame_get_matrix(float spacing[3], float origin[3], + float norm_i[3], float norm_j[3], float norm_k[3], + igtl_frame_header * header) +{ + float tx; + float ty; + float tz; + float sx; + float sy; + float sz; + float nx; + float ny; + float nz; + float px; + float py; + float pz; + + tx = (float)header->matrix[0]; + ty = (float)header->matrix[1]; + tz = (float)header->matrix[2]; + sx = (float)header->matrix[3]; + sy = (float)header->matrix[4]; + sz = (float)header->matrix[5]; + nx = (float)header->matrix[6]; + ny = (float)header->matrix[7]; + nz = (float)header->matrix[8]; + px = (float)header->matrix[9]; + py = (float)header->matrix[10]; + pz = (float)header->matrix[11]; + + spacing[0] = sqrtf(tx*tx + ty*ty + tz*tz); + spacing[1] = sqrtf(sx*sx + sy*sy + sz*sz); + spacing[2] = sqrtf(nx*nx + ny*ny + nz*nz); + + if (spacing[0] != 0) + { + norm_i[0] = header->matrix[0] / spacing[0]; + norm_i[1] = header->matrix[1] / spacing[0]; + norm_i[2] = header->matrix[2] / spacing[0]; + } + if (spacing[1] != 0) + { + norm_j[0] = header->matrix[3] / spacing[1]; + norm_j[1] = header->matrix[4] / spacing[1]; + norm_j[2] = header->matrix[5] / spacing[1]; + } + if (spacing[2] != 0) + { + norm_k[0] = header->matrix[6] / spacing[2]; + norm_k[1] = header->matrix[7] / spacing[2]; + norm_k[2] = header->matrix[8] / spacing[2]; + } + + origin[0] = header->matrix[9]; + origin[1] = header->matrix[10]; + origin[2] = header->matrix[11]; + +} + +void igtl_export igtl_frame_get_matrix_4x4(float _matrix[4][4], igtl_frame_header * header) +{ + _matrix[0][0] = header->matrix[0]; + _matrix[0][1] = header->matrix[1]; + _matrix[0][2] = header->matrix[2]; + _matrix[1][0] = header->matrix[3]; + _matrix[1][1] = header->matrix[4]; + _matrix[1][2] = header->matrix[5]; + _matrix[2][0] = header->matrix[6]; + _matrix[2][1] = header->matrix[7]; + _matrix[2][2] = header->matrix[8]; + + _matrix[0][3] = header->matrix[9]; + _matrix[1][3] = header->matrix[10]; + _matrix[2][3] = header->matrix[11]; + + _matrix[3][0] = 0; + _matrix[3][1] = 0; + _matrix[3][2] = 0; + _matrix[3][3] = 1; +} diff --git a/openigtlink/repo/Source/VideoStreaming/igtl_video.h b/openigtlink/repo/Source/VideoStreaming/igtl_video.h new file mode 100755 index 0000000..37ed685 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtl_video.h @@ -0,0 +1,123 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_VIDEO_H +#define __IGTL_VIDEO_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" + +#define IGTL_STT_VIDEO_SIZE 9 +#define IGTL_VIDEO_CODEC_NAME_SIZE 4 +#define IGTL_VIDEO_HEADER_VERSION 1 +#define IGTL_VIDEO_HEADER_SIZE 76 + + +/* Data type */ +#define IGTL_VIDEO_DTYPE_SCALAR 1 +#define IGTL_VIDEO_DTYPE_VECTOR 3 + +/* Scalar type */ +#define IGTL_VIDEO_STYPE_TYPE_INT8 2 +#define IGTL_VIDEO_STYPE_TYPE_UINT8 3 +#define IGTL_VIDEO_STYPE_TYPE_INT16 4 +#define IGTL_VIDEO_STYPE_TYPE_UINT16 5 +#define IGTL_VIDEO_STYPE_TYPE_INT32 6 +#define IGTL_VIDEO_STYPE_TYPE_UINT32 7 + +/* Endian */ +#define IGTL_VIDEO_ENDIAN_BIG 1 +#define IGTL_VIDEO_ENDIAN_LITTLE 2 + +#define IGTL_VIDEO_CODEC_NAME_I420 "I420" +#define IGTL_VIDEO_CODEC_NAME_H264 "H264" +#define IGTL_VIDEO_CODEC_NAME_VP9 "VP90" +#define IGTL_VIDEO_CODEC_NAME_X265 "X265" +#define IGTL_VIDEO_CODEC_NAME_OPENHEVC "O265" +#define IGTL_VIDEO_CODEC_NAME_AV1 "AV10" + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memory */ + +typedef struct { + char codec[IGTL_VIDEO_CODEC_NAME_SIZE]; /* codec protocol */ + igtl_uint32 time_interval; /* Minimum time between two frames. Use 0 for as fast as possible. */ + /* If e.g. 50 ms is specified, the maximum update rate will be 20 Hz. */ +} igtl_stt_video; + +#pragma pack() + + +#pragma pack(1) /* For 1-byte boundary in memory */ + + /** Image data consists of frame data header, which is defined in this + * structure, folowed by array of image pixel data. + */ + typedef struct { + igtl_uint16 header_version; /* data format version number(1) */ + igtl_uint8 endian; /* endian type of image data */ + /* (1:big, 2:little) */ + + char encoding[IGTL_VIDEO_CODEC_NAME_SIZE]; /* fourcc representing data encoding */ + igtl_uint16 frameType; + + igtl_uint8 coord; /* coordinate system (1:RAS 2:LPS) */ + + igtl_uint16 size[3]; /* entire image volume size */ + + igtl_float32 matrix[12]; /* orientation / origin of image */ + /* - matrix[0-2]: norm_i * pix_i */ + /* - matrix[3-5]: norm_j * pix_j */ + /* - matrix[6-8]: norm_k * pix_k */ + /* - matrix[9-11]:origin */ + /* where norm_* are normal vectors */ + /* along each index, and pix_* are */ + /* pixel size in each direction */ + + igtl_uint16 subvol_offset[3]; /* sub volume offset */ + igtl_uint16 subvol_size[3]; /* sub volume size */ + + } igtl_frame_header; + +#pragma pack() + + +/** Converts endianness of each element in an array of + * or vice versa.*/ +void igtl_export igtl_stt_video_convert_byte_order(igtl_stt_video* stt_video); + +/** Calculates, STT_VIDEO messages.*/ +igtl_uint64 igtl_export igtl_stt_video_get_crc(igtl_stt_video* stt_video); + +void igtl_export igtl_frame_convert_byte_order(igtl_frame_header * header); + +void igtl_export igtl_frame_set_matrix(float spacing[3], float origin[3], float norm_i[3], float norm_j[3], float norm_k[3], igtl_frame_header * header); + +void igtl_export igtl_frame_set_matrix_4x4(float _matrix[4][4], igtl_frame_header * header); + +void igtl_export igtl_frame_get_matrix(float spacing[3], float origin[3], float norm_i[3], float norm_j[3], float norm_k[3], igtl_frame_header * header); + +void igtl_export igtl_frame_get_matrix_4x4(float _matrix[4][4], igtl_frame_header * header); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_VIDEO_H */ + + diff --git a/openigtlink/repo/Source/VideoStreaming/igtl_videometa.c b/openigtlink/repo/Source/VideoStreaming/igtl_videometa.c new file mode 100644 index 0000000..a27a5f9 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtl_videometa.c @@ -0,0 +1,193 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_videometa.h" +#include "igtl_util.h" + +void igtl_export igtl_videometa_set_matrix(float spacing[3], float origin[3], + float norm_i[3], float norm_j[3], float norm_k[3], + igtl_videometa_element * element) +{ + element->matrix[0] = (igtl_float32) (norm_i[0] * spacing[0]); + element->matrix[1] = (igtl_float32) (norm_i[1] * spacing[0]); + element->matrix[2] = (igtl_float32) (norm_i[2] * spacing[0]); + element->matrix[3] = (igtl_float32) (norm_j[0] * spacing[1]); + element->matrix[4] = (igtl_float32) (norm_j[1] * spacing[1]); + element->matrix[5] = (igtl_float32) (norm_j[2] * spacing[1]); + element->matrix[6] = (igtl_float32) (norm_k[0] * spacing[2]); + element->matrix[7] = (igtl_float32) (norm_k[1] * spacing[2]); + element->matrix[8] = (igtl_float32) (norm_k[2] * spacing[2]); + element->matrix[9] = (igtl_float32) (origin[0]); + element->matrix[10] = (igtl_float32) (origin[1]); + element->matrix[11] = (igtl_float32) (origin[2]); +} + +void igtl_export igtl_videometa_set_matrix_4x4(float _matrix [4][4], igtl_videometa_element * element) +{ + element->matrix[0] = _matrix[0][0]; + element->matrix[1] = _matrix[0][1]; + element->matrix[2] = _matrix[0][2]; + element->matrix[3] = _matrix[1][0]; + element->matrix[4] = _matrix[1][1]; + element->matrix[5] = _matrix[1][2]; + element->matrix[6] = _matrix[2][0]; + element->matrix[7] = _matrix[2][1]; + element->matrix[8] = _matrix[2][2]; + element->matrix[9] = _matrix[0][3]; + element->matrix[10] = _matrix[1][3]; + element->matrix[11] = _matrix[2][3]; +} + +void igtl_export igtl_videometa_get_matrix(float spacing[3], float origin[3], + float norm_i[3], float norm_j[3], float norm_k[3], + igtl_videometa_element * element) +{ + float tx; + float ty; + float tz; + float sx; + float sy; + float sz; + float nx; + float ny; + float nz; + float px; + float py; + float pz; + + tx = (float) element->matrix[0]; + ty = (float) element->matrix[1]; + tz = (float) element->matrix[2]; + sx = (float) element->matrix[3]; + sy = (float) element->matrix[4]; + sz = (float) element->matrix[5]; + nx = (float) element->matrix[6]; + ny = (float) element->matrix[7]; + nz = (float) element->matrix[8]; + px = (float) element->matrix[9]; + py = (float) element->matrix[10]; + pz = (float) element->matrix[11]; + + spacing[0] = sqrtf(tx*tx + ty*ty + tz*tz); + spacing[1] = sqrtf(sx*sx + sy*sy + sz*sz); + spacing[2] = sqrtf(nx*nx + ny*ny + nz*nz); + + if (spacing[0] != 0) + { + norm_i[0] = element->matrix[0] / spacing[0]; + norm_i[1] = element->matrix[1] / spacing[0]; + norm_i[2] = element->matrix[2] / spacing[0]; + } + if (spacing[1] != 0) + { + norm_j[0] = element->matrix[3] / spacing[1]; + norm_j[1] = element->matrix[4] / spacing[1]; + norm_j[2] = element->matrix[5] / spacing[1]; + } + if (spacing[2] != 0) + { + norm_k[0] = element->matrix[6] / spacing[2]; + norm_k[1] = element->matrix[7] / spacing[2]; + norm_k[2] = element->matrix[8] / spacing[2]; + } + + origin[0] = element->matrix[9]; + origin[1] = element->matrix[10]; + origin[2] = element->matrix[11]; + +} + + +void igtl_export igtl_videometa_get_matrix_4x4(float _matrix[4][4], igtl_videometa_element * element) +{ + _matrix[0][0] = element->matrix[0]; + _matrix[0][1] = element->matrix[1]; + _matrix[0][2] = element->matrix[2]; + _matrix[1][0] = element->matrix[3]; + _matrix[1][1] = element->matrix[4]; + _matrix[1][2] = element->matrix[5]; + _matrix[2][0] = element->matrix[6]; + _matrix[2][1] = element->matrix[7]; + _matrix[2][2] = element->matrix[8]; + + _matrix[0][3] = element->matrix[9]; + _matrix[1][3] = element->matrix[10]; + _matrix[2][3] = element->matrix[11]; + + _matrix[3][0] = 0; + _matrix[3][1] = 0; + _matrix[3][2] = 0; + _matrix[3][3] = 1; +} + + +void igtl_export igtl_videometa_convert_byte_order(igtl_videometa_element * metalist, int nitem) +{ + igtl_videometa_element* elem; + int item; + int i; + igtl_uint32 tmp[12]; + igtl_uint64 tmp_focal; + for (item = 0; item < nitem; item ++) + { + elem = &(metalist[item]); + + if (igtl_is_little_endian()) + { + elem->zoom_level = BYTE_SWAP_INT16(elem->zoom_level); + memcpy(&tmp_focal, &elem->focal_length, sizeof(igtl_float64)); + tmp_focal = BYTE_SWAP_INT64(tmp_focal); + memcpy(&elem->focal_length, &tmp_focal, sizeof(igtl_float64)); + + for (i = 0; i < 3; i ++) + { + elem->size[i] = BYTE_SWAP_INT16(elem->size[i]); + } + + memcpy(tmp, elem->matrix, sizeof(igtl_uint32)*12); + + /* + * TODO: The following loop may cause segmentation fault, when it is compiled + * with '-ftree-vectorize' optimization option on 64-bit Linux. + * ('-ftree-vectorize' becomes active, when '-O3' optimization is specified.) + * -- code has been updated on June 24 -- needs test + */ + for (i = 0; i < 12; i ++) + { + tmp[i] = BYTE_SWAP_INT32(tmp[i]); + } + memcpy(elem->matrix, tmp, sizeof(igtl_uint32)*12); + + } + } +} + +igtl_uint64 igtl_export igtl_videometa_get_crc(igtl_videometa_element* metalist, int nitem) +{ + igtl_videometa_element* elem; + int i; + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + for (i = 0; i < nitem; i ++) + { + elem = &(metalist[i]); + crc = crc64((unsigned char*) elem, IGTL_VIDEOMETA_ELEMENT_SIZE, crc); + } + + return crc; +} diff --git a/openigtlink/repo/Source/VideoStreaming/igtl_videometa.h b/openigtlink/repo/Source/VideoStreaming/igtl_videometa.h new file mode 100644 index 0000000..2310792 --- /dev/null +++ b/openigtlink/repo/Source/VideoStreaming/igtl_videometa.h @@ -0,0 +1,101 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_VIDEOMETA_H +#define __IGTL_VIDEOMETA_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_video.h" + +#define IGTL_VIDEOMETA_ELEMENT_SIZE 322 + +#define IGTL_VIDEOMETA_LEN_NAME 64 +#define IGTL_VIDEOMETA_LEN_DEVICE_NAME 64 +#define IGTL_VIDEOMETA_LEN_PATIENT_NAME 64 +#define IGTL_VIDEOMETA_LEN_PATIENT_ID 64 + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** VIDEOMETA is a message type to transfer a list of video source available in a server. + * A VIDEOMETA message may contain information of multiple video source. + * The client determins the number of video source meta by the size of the body included + * in the message header (see igtl_videometa_getdata_n() macro). */ +typedef struct { + char name[IGTL_VIDEOMETA_LEN_NAME]; /* name / description */ + char device_name[IGTL_VIDEOMETA_LEN_DEVICE_NAME]; /* device name to query the video and COLORT */ + char patient_name[IGTL_VIDEOMETA_LEN_PATIENT_NAME]; /* patient name */ + char patient_id[IGTL_VIDEOMETA_LEN_PATIENT_ID]; /* patient ID (MRN etc.) */ + + igtl_int16 zoom_level; /* camera zoom level. */ + + igtl_float64 focal_length; /* camera focal length. */ + + igtl_uint16 size[3]; /* entire image volume size */ + + igtl_float32 matrix[12]; /* orientation / origin of image */ + /* - matrix[0-2]: norm_i * pix_i */ + /* - matrix[3-5]: norm_j * pix_j */ + /* - matrix[6-8]: norm_k * pix_k */ + /* - matrix[9-11]:origin */ + /* where norm_* are normal vectors */ + /* along each index, and pix_* are */ + /* pixel size in each direction */ + + igtl_uint8 scalar_type; /* scalar type. see scalar_type in IMAGE message */ + igtl_uint8 reserved; +} igtl_videometa_element; + +#pragma pack() + +/** igtl_videometa_get_data_size(n) macro calculates the size of body based on the number + * of images.The size of body is used in the message header. + * igtl_videometa_get_data_n(size) calculates the number of images in the body, based on + * the body size. This function may be used when a client program parses VIDEOMETA message. */ +#define igtl_videometa_get_data_size(n) ((n) * IGTL_VIDEOMETA_ELEMENT_SIZE) +#define igtl_videometa_get_data_n(size) ((size) / IGTL_VIDEOMETA_ELEMENT_SIZE) + + +/** Generates image orientation/origin matrix from spacing, origin and normal vectors. */ +void igtl_export igtl_videometa_set_matrix(float spacing[3], float origin[3], + float norm_i[3], float norm_j[3], float norm_k[3], + igtl_videometa_element * element); + +void igtl_export igtl_videometa_get_matrix(float spacing[3], float origin[3], + float norm_i[3], float norm_j[3], float norm_k[3], + igtl_videometa_element * element); + +/** Sets the image orientation/origin matrix in 4x4 format */ +void igtl_export igtl_videometa_set_matrix_4x4(float _matrix[4][4], igtl_videometa_element * element); + +/** Gets the image orientation/origin matrix in 4x4 format */ +void igtl_export igtl_videometa_get_matrix_4x4(float _matrix[4][4],igtl_videometa_element * element); + +/** Converts endianness of each member variable in igtl_videometa_element from host + * byte order to network byte order, or vice versa. */ +void igtl_export igtl_videometa_convert_byte_order(igtl_videometa_element* metalist, int nitem); + +/** Clculates CRC of video meta data body. */ +igtl_uint64 igtl_export igtl_videometa_get_crc(igtl_videometa_element* metalist, int nitem); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_VIDEOMETA_H */ diff --git a/openigtlink/repo/Source/WebSocket/UseWebSocket.cmake b/openigtlink/repo/Source/WebSocket/UseWebSocket.cmake new file mode 100644 index 0000000..22366fe --- /dev/null +++ b/openigtlink/repo/Source/WebSocket/UseWebSocket.cmake @@ -0,0 +1,142 @@ +set (WEBSOCKETPP_PLATFORM_LIBS "") +set (WEBSOCKETPP_PLATFORM_TLS_LIBS "") +set (WEBSOCKETPP_BOOST_LIBS "") + +# VC9 and C++11 reasoning +if (ENABLE_CPP11 AND MSVC AND MSVC90) +message("* Detected Visual Studio 9 2008, disabling C++11 support.") + set (ENABLE_CPP11 FALSE) +endif () + +# Detect clang. Not officially reported by cmake. +execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "-v" ERROR_VARIABLE CXX_VER_STDERR) +if ("${CXX_VER_STDERR}" MATCHES ".*clang.*") + set (CMAKE_COMPILER_IS_CLANGXX 1) +endif () + +# C++11 defines +if (ENABLE_CPP11) +if (MSVC) + add_definitions (-D_WEBSOCKETPP_CPP11_FUNCTIONAL_) + add_definitions (-D_WEBSOCKETPP_CPP11_SYSTEM_ERROR_) + add_definitions (-D_WEBSOCKETPP_CPP11_RANDOM_DEVICE_) + add_definitions (-D_WEBSOCKETPP_CPP11_MEMORY_) +else() + add_definitions (-D_WEBSOCKETPP_CPP11_STL_) +endif() +endif () + +# Visual studio +if (MSVC) + set (WEBSOCKETPP_BOOST_LIBS system thread) + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL /Gy /GF /Ox /Ob2 /Ot /Oi /MP /arch:SSE2 /fp:fast") + set (CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /INCREMENTAL:NO /OPT:REF /OPT:ICF") + add_definitions (/W3 /wd4996 /wd4995 /wd4355) + add_definitions (-DUNICODE -D_UNICODE) + add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) + add_definitions (-DNOMINMAX) +endif () + +# g++ +if (CMAKE_COMPILER_IS_GNUCXX) + set (WEBSOCKETPP_PLATFORM_LIBS pthread rt) + set (WEBSOCKETPP_PLATFORM_TLS_LIBS ssl crypto) + set (WEBSOCKETPP_BOOST_LIBS system thread) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") +if (NOT APPLE) +add_definitions (-DNDEBUG -Wall -Wcast-align) # todo: should we use CMAKE_C_FLAGS for these? +endif () + +# Try to detect version. Note: Not tested! +execute_process (COMMAND ${CMAKE_CXX_COMPILER} "-dumpversion" OUTPUT_VARIABLE GCC_VERSION) +if ("${GCC_VERSION}" STRGREATER "4.4.0") + message("* C++11 support partially enabled due to GCC version ${GCC_VERSION}") + set (WEBSOCKETPP_BOOST_LIBS system thread) +endif () +endif () + +# clang +if (CMAKE_COMPILER_IS_CLANGXX) +if (NOT APPLE) + set (WEBSOCKETPP_PLATFORM_LIBS pthread rt) +else() + set (WEBSOCKETPP_PLATFORM_LIBS pthread) +endif() + set (WEBSOCKETPP_PLATFORM_TLS_LIBS ssl crypto) + set (WEBSOCKETPP_BOOST_LIBS system thread) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++") # todo: is libc++ really needed here? +if (NOT APPLE) + add_definitions (-DNDEBUG -Wall -Wno-padded) # todo: should we use CMAKE_C_FLAGS for these? +endif () +endif () + +# OSX, can override above. +if (APPLE) + add_definitions (-DNDEBUG -Wall) +endif () + +# Set BOOST_ROOT env variable or pass with cmake -DBOOST_ROOT=path. +# BOOST_ROOT can also be defined by a previous run from cmake cache. +if (NOT "$ENV{BOOST_ROOT_CPP11}" STREQUAL "") +# Scons documentation for BOOST_ROOT_CPP11: +# "look for optional second boostroot compiled with clang's libc++ STL library +# this prevents warnings/errors when linking code built with two different +# incompatible STL libraries." +file (TO_CMAKE_PATH "$ENV{BOOST_ROOT_CPP11}" BOOST_ROOT) + set (BOOST_ROOT ${BOOST_ROOT} CACHE PATH "BOOST_ROOT dependency path" FORCE) +endif () +if ("${BOOST_ROOT}" STREQUAL "") + file (TO_CMAKE_PATH "$ENV{BOOST_ROOT}" BOOST_ROOT) +# Cache BOOST_ROOT for runs that do not define $ENV{BOOST_ROOT}. + set (BOOST_ROOT ${BOOST_ROOT} CACHE PATH "BOOST_ROOT dependency path" FORCE) +endif () + +if (MSVC) + set (Boost_USE_MULTITHREADED TRUE) + set (Boost_USE_STATIC_LIBS TRUE) +else () + set (Boost_USE_MULTITHREADED FALSE) + set (Boost_USE_STATIC_LIBS FALSE) +endif () + +if (BOOST_STATIC) + set (Boost_USE_STATIC_LIBS TRUE) +endif () + +if (NOT Boost_USE_STATIC_LIBS) + add_definitions (/DBOOST_TEST_DYN_LINK) +endif () + +set (Boost_FIND_REQUIRED TRUE) +set (Boost_FIND_QUIETLY TRUE) +set (Boost_DEBUG FALSE) +set (Boost_USE_MULTITHREADED TRUE) +set (Boost_ADDITIONAL_VERSIONS "1.39.0" "1.40.0" "1.41.0" "1.42.0" "1.43.0" "1.44.0" "1.46.1") # todo: someone who knows better spesify these! + +find_package (Boost 1.39.0 COMPONENTS "${WEBSOCKETPP_BOOST_LIBS}") + +if (Boost_FOUND) +# Boost is a project wide global dependency. +include_directories (${Boost_INCLUDE_DIRS}) +link_directories (${Boost_LIBRARY_DIRS}) + +# Pretty print status +message (STATUS "-- Include Directories") +foreach (include_dir ${Boost_INCLUDE_DIRS}) +message (STATUS " " ${include_dir}) +endforeach () +message (STATUS "-- Library Directories") +foreach (library_dir ${Boost_LIBRARY_DIRS}) +message (STATUS " " ${library_dir}) +endforeach () +message (STATUS "-- Libraries") +foreach (boost_lib ${Boost_LIBRARIES}) +message (STATUS " " ${boost_lib}) +endforeach () +message ("") +else () +message (FATAL_ERROR "Failed to find required dependency: boost") +endif () + +find_package(OpenSSL) +find_package(ZLIB) \ No newline at end of file diff --git a/openigtlink/repo/Source/WebSocket/igtlWebClientSocket.cxx b/openigtlink/repo/Source/WebSocket/igtlWebClientSocket.cxx new file mode 100644 index 0000000..0c5af5f --- /dev/null +++ b/openigtlink/repo/Source/WebSocket/igtlWebClientSocket.cxx @@ -0,0 +1,143 @@ +// +// igtlWebClientSocket.cpp +// OpenIGTLink +// +// Created by Longquan Chen on 1/20/17. +// +// + +#include "igtlWebClientSocket.h" + +webSocketClient::webSocketClient() : m_open(false),m_done(false) { + // set up access channels to only log interesting things + m_client.clear_access_channels(websocketpp::log::alevel::all); + m_client.set_access_channels(websocketpp::log::alevel::connect); + m_client.set_access_channels(websocketpp::log::alevel::disconnect); + m_client.set_access_channels(websocketpp::log::alevel::app); + + // Initialize the Asio transport policy + m_client.init_asio(); + + // Bind the handlers we are using + using websocketpp::lib::placeholders::_1; + using websocketpp::lib::placeholders::_2; + using websocketpp::lib::bind; + m_client.set_open_handler(bind(&webSocketClient::on_open,this,_1)); + m_client.set_close_handler(bind(&webSocketClient::on_close,this,_1)); + m_client.set_fail_handler(bind(&webSocketClient::on_fail,this,_1)); + m_client.set_message_handler(bind(&webSocketClient::on_message,this, _1, _2)); +} + +int webSocketClient::ConnectToServer(const char* hostName, int port) +{ + websocketpp::lib::error_code ec; + std::string uri; + uri.append("http://"); + uri.append(hostName); + uri.append(":"); + uri.append(std::to_string(port)); + client::connection_ptr con = m_client.get_connection(uri, ec); + if (ec) + { + m_client.get_alog().write(websocketpp::log::alevel::app, + "Get Connection Error: "+ec.message()); + return -1; + } + + // Grab a handle for this connection so we can talk to it in a thread + // safe manor after the event loop starts. + m_hdl = con->get_handle(); + + // Queue the connection. No DNS queries or network connections will be + // made until the io_service event loop is run. + m_client.connect(con); + + m_client.run(); + + return 0; +} + +// The open handler will signal that we are ready to start sending telemetry +void webSocketClient::on_open(websocketpp::connection_hdl) { + m_client.get_alog().write(websocketpp::log::alevel::app, + "Connection opened, starting telemetry!"); + + scoped_lock guard(m_lock); + m_open = true; +} + +// The close handler will signal that we should stop sending telemetry +void webSocketClient::on_close(websocketpp::connection_hdl) { + m_client.get_alog().write(websocketpp::log::alevel::app, + "Connection closed, stopping telemetry!"); + + scoped_lock guard(m_lock); + m_done = true; +} + +// The fail handler will signal that we should stop sending telemetry +void webSocketClient::on_fail(websocketpp::connection_hdl) { + m_client.get_alog().write(websocketpp::log::alevel::app, + "Connection failed, stopping telemetry!"); + + scoped_lock guard(m_lock); + m_done = true; +} + +void webSocketClient::on_message(websocketpp::connection_hdl hdl, message_ptr msg) { + { + unique_lock lock(m_action_lock); + std::string str(msg->get_raw_payload()); + m_messages.push(str); + } + m_action_cond.notify_one(); +} + + +int webSocketClient::Receive(void* data, int& length) +{ + unique_lock lock(m_action_lock); + + while(m_messages.empty()) + { + m_action_cond.wait(lock); + } + std::string a = m_messages.front(); + int messageLen = a.length(); + if(length && messageLen>=length) + { + memcpy(data, a.c_str(), length); + } + if (messageLen == length) + { + m_messages.pop(); + } + else + { + a.erase(a.begin(), a.begin()+length); + messageLen = a.length(); + m_messages.front()= a; + } + lock.unlock(); + return length; +} + +int webSocketClient::Send(const void* data, int length) +{ + std::stringstream val; + websocketpp::lib::error_code ec; + m_client.send(m_hdl,val.str(),websocketpp::frame::opcode::binary,ec); + + // The most likely error that we will get is that the connection is + // not in the right state. Usually this means we tried to send a + // message to a connection that was closed or in the process of + // closing. While many errors here can be easily recovered from, + // in this simple example, we'll stop the telemetry loop. + if (ec) + { + m_client.get_alog().write(websocketpp::log::alevel::app, + "Send Error: "+ec.message()); + return 0; + } + return 1; +} \ No newline at end of file diff --git a/openigtlink/repo/Source/WebSocket/igtlWebClientSocket.h b/openigtlink/repo/Source/WebSocket/igtlWebClientSocket.h new file mode 100644 index 0000000..309bd2f --- /dev/null +++ b/openigtlink/repo/Source/WebSocket/igtlWebClientSocket.h @@ -0,0 +1,76 @@ +// +// igtlWebSocket.hpp +// OpenIGTLink +// +// Created by Longquan Chen on 1/20/17. +// +// + +#ifndef igtlWebClientSocket_h +#define igtlWebClientSocket_h + + +#include "websocketpp/config/asio_no_tls.hpp" +#include + +#include "websocketpp/client.hpp" + +#include "igtlOSUtil.h" +#include +typedef websocketpp::config::asio_client::message_type::ptr message_ptr; +using websocketpp::lib::placeholders::_1; +using websocketpp::lib::placeholders::_2; +using websocketpp::connection_hdl; +using websocketpp::lib::bind; +using websocketpp::lib::mutex; +using websocketpp::lib::lock_guard; +using websocketpp::lib::unique_lock; +using websocketpp::lib::condition_variable; + +#include +#include +#include +#include +#include + +class webSocketClient { +public: + typedef websocketpp::client client; + typedef websocketpp::lib::lock_guard scoped_lock; + + webSocketClient() ; + + // The open handler will signal that we are ready to start sending data + void on_open(websocketpp::connection_hdl); + + + // The close handler will signal that we should stop sending data + void on_close(websocketpp::connection_hdl) ; + + // The fail handler will signal that we should stop sending data + void on_fail(websocketpp::connection_hdl) ; + + int ConnectToServer(const char* hostName, int port); + + int Send(const void* data, int length); + + int Receive(void* data, int& length); + + void on_message(websocketpp::connection_hdl hdl, message_ptr msg); + +private: + client m_client; + websocketpp::connection_hdl m_hdl; + websocketpp::lib::mutex m_lock; + bool m_open; + bool m_done; + std::queue m_messages; + + mutex m_action_lock; + mutex m_connection_lock; + condition_variable m_action_cond; +}; + + + +#endif /* igtlWebClientSocket_h */ diff --git a/openigtlink/repo/Source/WebSocket/igtlWebServerSocket.cxx b/openigtlink/repo/Source/WebSocket/igtlWebServerSocket.cxx new file mode 100644 index 0000000..47ac765 --- /dev/null +++ b/openigtlink/repo/Source/WebSocket/igtlWebServerSocket.cxx @@ -0,0 +1,188 @@ +// +// igtlWebServerSocket.cpp +// OpenIGTLink +// +// Created by Longquan Chen on 1/20/17. +// +// + +#include "igtlWebServerSocket.h" + +webSocketServer::webSocketServer() : m_count(0) { + // set up access channels to only log interesting things + m_endpoint.clear_access_channels(websocketpp::log::alevel::all); + m_endpoint.set_access_channels(websocketpp::log::alevel::access_core); + m_endpoint.set_access_channels(websocketpp::log::alevel::app); + + // Initialize the Asio transport policy + m_endpoint.init_asio(); + + // Bind the handlers we are using + using websocketpp::lib::placeholders::_1; + m_endpoint.set_open_handler(bind(&webSocketServer::on_open,this,_1)); + m_endpoint.set_close_handler(bind(&webSocketServer::on_close,this,_1)); + m_endpoint.set_http_handler(bind(&webSocketServer::on_http,this,_1)); + m_timeInterval = 1; +} + +void webSocketServer::SetTimeInterval(unsigned int time) +{ + this->m_timeInterval = time; +} + +int webSocketServer::CreateServer(uint16_t port) +{ + return this->run("",port); +} + +int webSocketServer::CreateHTTPServer(std::string docroot, uint16_t port) +{ + m_docroot = docroot; + this->port = port; + return this->run(docroot,port); +} + +webSocketServer* webSocketServer::WaitForConnection(unsigned long msec ) +{ + if(m_connections.size()) + { + return this; + } + else + { + igtl::Sleep(msec); + return NULL; + } +} + +int webSocketServer::run(std::string docroot, uint16_t port) { + m_docroot = docroot; + serverCreated = false; + //------------------------------------------------------------ + // Get thread information + //igtl::MultiThreader::ThreadInfo* info = + //static_cast(ptr); + std::stringstream ss; + ss << "Running server on port "<< this->port <<" using docroot=" << this->m_docroot; + this->m_endpoint.get_alog().write(websocketpp::log::alevel::app,ss.str()); + + + // listen on specified port + this->m_endpoint.listen(this->port); + + // Start the server accept loop + this->m_endpoint.start_accept(); + + set_timer(); + // Start the ASIO io_service run loop + try + { + this->m_endpoint.run(); + } + catch (websocketpp::exception const & e) + { + std::cout << e.what() << std::endl; + this->status = -1; + } + this->status = 0; + return status; +} + +void webSocketServer::Send(void * inputMessage, size_t len) +{ + { + unique_lock lock(m_action_lock); + char * str = new char[len]; + memcpy(str, inputMessage, len); + std::string msg(str, len); + m_actions.push(action(MESSAGE,msg)); + delete [] str; + } + m_action_cond.notify_one(); + m_count++; +} + +void webSocketServer::set_timer() { + m_timer = m_endpoint.set_timer(this->m_timeInterval, + websocketpp::lib::bind( &webSocketServer::on_timer, this) + ); +} + +void webSocketServer::on_timer() { + // Broadcast count to all connections + unique_lock lock(m_action_lock); + + while(m_actions.empty()) { + m_action_cond.wait(lock); + } + action a = m_actions.front(); + m_actions.pop(); + lock.unlock(); + + con_list::iterator it; + for (it = m_connections.begin(); it != m_connections.end(); ++it) { + if (a.msg.length()) + { + m_endpoint.send(*it,a.msg,websocketpp::frame::opcode::binary); + } + } + // set timer for next telemetry check + set_timer(); +} + +void webSocketServer::on_http(connection_hdl hdl) { + // Upgrade our connection handle to a full connection_ptr + server::connection_ptr con = m_endpoint.get_con_from_hdl(hdl); + + std::ifstream file; + std::string filename = con->get_resource(); + std::string response; + + //m_endpoint.get_alog().write(websocketpp::log::alevel::app, "http request1: "+filename); + + if (filename == "/") + { + filename = m_docroot+"index.html"; + } + else + { + filename = m_docroot+filename.substr(1); + } + + //m_endpoint.get_alog().write(websocketpp::log::alevel::app, "http request2: "+filename); + + file.open(filename.c_str(), std::ios::in); + if (!file) + { + // 404 error + std::stringstream ss; + + ss << "" + << "Error 404 (Resource not found)" + << "

Error 404

" + << "

The requested URL " << filename << " was not found on this server.

" + << ""; + + con->set_body(ss.str()); + con->set_status(websocketpp::http::status_code::not_found); + return; + } + + file.seekg(0, std::ios::end); + response.reserve(file.tellg()); + file.seekg(0, std::ios::beg); + + response.assign((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + + con->set_body(response); + con->set_status(websocketpp::http::status_code::ok); +} + +void webSocketServer::on_open(connection_hdl hdl) { + m_connections.insert(hdl); +} + +void webSocketServer::on_close(connection_hdl hdl) { + m_connections.erase(hdl); +} diff --git a/openigtlink/repo/Source/WebSocket/igtlWebServerSocket.h b/openigtlink/repo/Source/WebSocket/igtlWebServerSocket.h new file mode 100644 index 0000000..588c9ca --- /dev/null +++ b/openigtlink/repo/Source/WebSocket/igtlWebServerSocket.h @@ -0,0 +1,103 @@ +// +// igtlWebServerSocket.hpp +// OpenIGTLink +// +// Created by Longquan Chen on 1/20/17. +// +// + +#ifndef igtlWebServerSocket_h +#define igtlWebServerSocket_h + + +#include "websocketpp/config/asio_no_tls.hpp" + +#include "websocketpp/server.hpp" + +#include "igtlOSUtil.h" +#include +#include +typedef websocketpp::server server; + +using websocketpp::connection_hdl; +using websocketpp::lib::placeholders::_1; +using websocketpp::lib::placeholders::_2; +using websocketpp::lib::bind; + +using websocketpp::lib::thread; +using websocketpp::lib::mutex; +using websocketpp::lib::lock_guard; +using websocketpp::lib::unique_lock; +using websocketpp::lib::condition_variable; + +#include +#include +#include +#include +#include + + +enum action_type { + SUBSCRIBE, + UNSUBSCRIBE, + MESSAGE, + SEVERCREATED +}; + +struct action { + action(action_type t, connection_hdl h) : type(t), hdl(h) {} + action(action_type t, connection_hdl h, std::string m) + : type(t), hdl(h), msg(m) {} + + action(action_type t):type(t){}; + action(action_type t, std::string m):type(t), msg(m){}; + action_type type; + websocketpp::connection_hdl hdl; + std::string msg; +}; + +/** + */ + +class webSocketServer{ + public: + typedef websocketpp::connection_hdl connection_hdl; + typedef websocketpp::server server; + webSocketServer(); + int CreateServer(uint16_t port); + int CreateHTTPServer(std::string docroot, uint16_t port); + + void Send(void * inputMessage, size_t len); + void on_http(connection_hdl hdl); + void on_open(connection_hdl hdl); + void on_close(connection_hdl hdl); + webSocketServer* WaitForConnection(unsigned long msec); + void SetTimeInterval(unsigned int time); + void on_timer(); + void set_timer(); + server m_endpoint; + std::string m_docroot; + bool serverCreated; + uint16_t port; + private: + typedef std::set > con_list; + int run(std::string docroot, uint16_t port); + + con_list m_connections; + server::timer_ptr m_timer; + + + int status; + + unsigned int m_timeInterval; + // data count + uint64_t m_count; + std::queue m_actions; + + mutex m_action_lock; + mutex m_connection_lock; + condition_variable m_action_cond; +}; + + +#endif /* igtlWebServerSocket_h */ diff --git a/openigtlink/repo/Source/igtlBindMessage.cxx b/openigtlink/repo/Source/igtlBindMessage.cxx new file mode 100644 index 0000000..6c73c9b --- /dev/null +++ b/openigtlink/repo/Source/igtlBindMessage.cxx @@ -0,0 +1,542 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlBindMessage.h" + +#include "igtl_header.h" +#include "igtl_bind.h" + +#include + +namespace igtl { + + + +BindMessageBase::BindMessageBase(): + MessageBase() +{ + Init(); +} + + +BindMessageBase::~BindMessageBase() +{ +} + +void BindMessageBase::Init() +{ + this->m_ChildMessages.clear(); +} + + +int BindMessageBase::SetNumberOfChildMessages(unsigned int n) +{ + m_IsBodyPacked = false; + this->m_ChildMessages.resize(n); + return this->m_ChildMessages.size(); +} + + +int BindMessageBase::GetNumberOfChildMessages() +{ + return this->m_ChildMessages.size(); +} + + +int BindMessageBase::AppendChildMessage(igtl::MessageBase * child) +{ + if (this->m_ChildMessages.size() < 0xFFFF) + { + m_IsBodyPacked = false; + ChildMessageInfo info; +#if OpenIGTLink_HEADER_VERSION >= 2 + info.type = child->GetMessageType(); +#else + info.type = child->GetDeviceType(); +#endif + info.name = child->GetDeviceName(); + + // If the class instance is BindMessage. + if (strncmp(this->m_SendMessageType.c_str(), "BIND", 4) == 0) + { + info.size = child->GetBufferBodySize(); + info.ptr = child->GetBufferBodyPointer(); + } + this->m_ChildMessages.push_back(info); + } + return this->m_ChildMessages.size(); +} + + +int BindMessageBase::SetChildMessage(unsigned int i, igtl::MessageBase * child) +{ + if (i < this->m_ChildMessages.size()) + { + m_IsBodyPacked = false; +#if OpenIGTLink_HEADER_VERSION >= 2 + this->m_ChildMessages[i].type = child->GetMessageType(); +#else + this->m_ChildMessages[i].type = child->GetDeviceType(); +#endif + this->m_ChildMessages[i].name = child->GetDeviceName(); + // If the class instance is BindMessage. + if (strncmp(this->m_SendMessageType.c_str(), "BIND", 4) == 0) + { + this->m_ChildMessages[i].size = child->GetBufferBodySize(); + this->m_ChildMessages[i].ptr = child->GetBufferBodyPointer(); + } + return 1; + } + else + { + return 0; + } +} + + +const char* BindMessageBase::GetChildMessageType(unsigned int i) +{ + if (i < this->m_ChildMessages.size()) + { + return this->m_ChildMessages[i].type.c_str(); + } + else + { + return NULL; + } +} + + + +BindMessage::BindMessage(): + BindMessageBase() +{ + this->m_SendMessageType = "BIND"; +} + + +BindMessage::~BindMessage() +{ +} + + +int BindMessage::GetChildMessage(unsigned int i, igtl::MessageBase * child) +{ + if (i < this->m_ChildMessages.size()) + { + child->InitBuffer(); + igtl_header * header = (igtl_header *) child->GetBufferPointer(); + header->header_version = 1; + strncpy( header->name, this->m_ChildMessages[i].type.c_str(), IGTL_HEADER_TYPE_SIZE); + strncpy( header->device_name, this->m_ChildMessages[i].name.c_str(), IGTL_HEADER_NAME_SIZE); + + // Time stamp -- same as the bind message + igtl_uint64 ts = m_TimeStampSec & 0xFFFFFFFF; + ts = (ts << 32) | (m_TimeStampSecFraction & 0xFFFFFFFF); + header->timestamp = ts; + header->body_size = this->m_ChildMessages[i].size; + header->crc = 0; + + // Convert to network byte order + igtl_header_convert_byte_order(header); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), header, IGTL_HEADER_SIZE); + headerMsg->Unpack(); + child->SetMessageHeader(headerMsg); + child->AllocateBuffer(); + // TODO: Is there any way to avoid this memory copy? + memcpy(child->GetBufferBodyPointer(), + this->m_ChildMessages[i].ptr, this->m_ChildMessages[i].size); + + child->Unpack(); + return 1; + } + else + { + return 0; + } +} + + +igtlUint64 BindMessage::CalculateContentBufferSize() +{ + igtlUint64 size; + igtlUint64 nameTableSectionSize = 0; // Size of name table section + igtlUint64 dataSectionSize = 0; // Size of data section + + size = sizeof(igtlUint16) // Number of child messages section + + (IGTL_HEADER_TYPE_SIZE + sizeof(igtlUint64)) * this->m_ChildMessages.size() // BIND header + + sizeof (igtlUint16); // Size of name table section + + std::vector::iterator iter; + for (iter = this->m_ChildMessages.begin(); iter != this->m_ChildMessages.end(); iter ++) + { + nameTableSectionSize += (*iter).name.length(); + nameTableSectionSize += 1; // NULL separator + dataSectionSize += (*iter).size + ((*iter).size%2); // child message body + padding (if applicable) + } + + // Add padding for the whole name table section + if (nameTableSectionSize % 2 > 0) + { + nameTableSectionSize++; + } + size += nameTableSectionSize; + size += dataSectionSize; + + return size; +} + + +int BindMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + igtl_bind_info bind_info; + igtl_bind_init_info(&bind_info); + + if (igtl_bind_alloc_info(&bind_info, this->m_ChildMessages.size())) + { + // TODO: using c library causes additional data copy (C++ member variable to c-structure, + // then to pack byte array). Probably, it's good idea to implement PackBody() without + // using c APIs. + int i = 0; + std::vector::iterator iter; + for (iter = this->m_ChildMessages.begin(); iter != this->m_ChildMessages.end(); iter ++) + { + strncpy(bind_info.child_info_array[i].type, (*iter).type.c_str(), IGTL_HEADER_TYPE_SIZE); + strncpy(bind_info.child_info_array[i].name, (*iter).name.c_str(), IGTL_HEADER_NAME_SIZE); + bind_info.child_info_array[i].size = (*iter).size; + bind_info.child_info_array[i].ptr = (*iter).ptr; + + i ++; + } + + igtl_bind_pack(&bind_info, this->m_Content, IGTL_TYPE_PREFIX_NONE); + int nc = this->m_ChildMessages.size(); + size_t bind_size = (size_t) igtl_bind_get_size(&bind_info, IGTL_TYPE_PREFIX_NONE); + char * ptr = (char *)this->m_Content; + ptr = ptr + bind_size; + for (int i = 0; i < nc; i ++) + { + memcpy((void*)ptr, bind_info.child_info_array[i].ptr, bind_info.child_info_array[i].size); + ptr += bind_info.child_info_array[i].size; + /* Note: a padding byte is added, if the size of the child message body + is odd. */ + if (bind_info.child_info_array[i].size % 2) + { + *ptr = '\0'; + ptr ++; + } + } + + igtl_bind_free_info(&bind_info); // TODO: calling igtl_bind_free_info() after igtl_bind_pack() causes + // this causes segmentation fault on Linux... why? + return 1; + } + else + { + return 0; + } +} + + +int BindMessage::UnpackContent() +{ + + igtl_bind_info bind_info; + + if (igtl_bind_unpack(IGTL_TYPE_PREFIX_NONE, (void*)this->m_Content, &bind_info, this->GetBufferBodySize()) == 0) + { + return 0; + } + + int n = bind_info.ncmessages; + + Init(); + + for (int i = 0; i < n; i ++) + { + ChildMessageInfo info; + + info.type = bind_info.child_info_array[i].type; + info.name = bind_info.child_info_array[i].name; + info.size = bind_info.child_info_array[i].size; + info.ptr = bind_info.child_info_array[i].ptr; + + this->m_ChildMessages.push_back(info); + + } + + return 1; +} + + + +GetBindMessage::GetBindMessage(): + BindMessageBase() +{ + this->m_SendMessageType = "GET_BIND"; +} + + +GetBindMessage::~GetBindMessage() +{ +} + + +int GetBindMessage::AppendChildMessage(const char * type, const char * name) +{ + if (strlen(type) < IGTL_HEADER_TYPE_SIZE && + strlen(name) < IGTL_HEADER_NAME_SIZE) + { + m_IsBodyPacked = false; + BindMessageBase::ChildMessageInfo info; + info.type = type; + info.name = name; + this->m_ChildMessages.push_back(info); + } + return this->m_ChildMessages.size(); +} + + +igtlUint64 GetBindMessage::CalculateContentBufferSize() +{ + igtlUint64 size; + + size = sizeof(igtlUint16) // Number of child messages section + + IGTL_HEADER_TYPE_SIZE * this->m_ChildMessages.size() // BIND header + + sizeof (igtlUint16); // Size of name table section + + std::vector::iterator iter; + for (iter = this->m_ChildMessages.begin(); iter != this->m_ChildMessages.end(); iter ++) + { + size += (*iter).name.length(); + size += 1; // NULL separator + } + + return size; +} + + +int GetBindMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + igtl_bind_info bind_info; + igtl_bind_init_info(&bind_info); + + if (igtl_bind_alloc_info(&bind_info, this->m_ChildMessages.size())) + { + // TODO: using c library causes additional data copy (C++ member variable to c-structure, + // then to pack byte array). Probably, it's good idea to implement PackBody() without + // using c APIs. + int i = 0; + std::vector::iterator iter; + for (iter = this->m_ChildMessages.begin(); iter != this->m_ChildMessages.end(); iter ++) + { + strncpy(bind_info.child_info_array[i].type, (*iter).type.c_str(), IGTL_HEADER_TYPE_SIZE); + strncpy(bind_info.child_info_array[i].name, (*iter).name.c_str(), IGTL_HEADER_NAME_SIZE); + bind_info.child_info_array[i].size = 0; + bind_info.child_info_array[i].ptr = NULL; + i ++; + } + + igtl_bind_pack(&bind_info, this->m_Content, IGTL_TYPE_PREFIX_GET); + igtl_bind_free_info(&bind_info); + + return 1; + } + else + { + return 0; + } +} + + +int GetBindMessage::UnpackContent() +{ + + igtl_bind_info bind_info; + + if (igtl_bind_unpack(IGTL_TYPE_PREFIX_NONE, (void*)this->m_Content, &bind_info, this->GetBufferBodySize()) == 0) + { + return 0; + } + + int n = bind_info.ncmessages; + + Init(); + + for (int i = 0; i < n; i ++) + { + ChildMessageInfo info; + + info.type = bind_info.child_info_array[i].type; + info.name = bind_info.child_info_array[i].name; + info.size = 0; + info.ptr = NULL; + + this->m_ChildMessages.push_back(info); + + } + + return 1; +} + + +StartBindMessage::StartBindMessage(): + GetBindMessage() +{ + this->m_SendMessageType = "STT_BIND"; +} + + +StartBindMessage::~StartBindMessage() +{ +} + + +void StartBindMessage::SetResolution(igtlUint64 res) +{ + m_IsBodyPacked = false; + this->m_Resolution = res; +} + + +igtlUint64 StartBindMessage::GetResolution() +{ + return this->m_Resolution; +} + + +igtlUint64 StartBindMessage::CalculateContentBufferSize() +{ + if (this->m_ChildMessages.size() == 0) + { + // Only a time stamp field is in the message + return sizeof(igtlUint64); + } + + return Superclass::CalculateContentBufferSize() + sizeof(igtlUint64); +} + + +int StartBindMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + igtl_bind_info bind_info; + igtl_bind_init_info(&bind_info); + + // If there is no child message information in the class instance, + // the message request any available messages + if (this->m_ChildMessages.size() == 0) + { + bind_info.request_all = 1; + } + + if (igtl_bind_alloc_info(&bind_info, this->m_ChildMessages.size())) + { + // TODO: using c library causes additional data copy (C++ member variable to c-structure, + // then to pack byte array). Probably, it's good idea to implement PackBody() without + // using c APIs. + int i = 0; + std::vector::iterator iter; + for (iter = this->m_ChildMessages.begin(); iter != this->m_ChildMessages.end(); iter ++) + { + strncpy(bind_info.child_info_array[i].type, (*iter).type.c_str(), IGTL_HEADER_TYPE_SIZE); + strncpy(bind_info.child_info_array[i].name, (*iter).name.c_str(), IGTL_HEADER_NAME_SIZE); + bind_info.child_info_array[i].size = 0; + bind_info.child_info_array[i].ptr = NULL; + i ++; + } + + bind_info.resol = this->m_Resolution; + + igtl_bind_pack(&bind_info, this->m_Content, IGTL_TYPE_PREFIX_STT); + igtl_bind_free_info(&bind_info); + + return 1; + } + else + { + return 0; + } +} + + +int StartBindMessage::UnpackContent() +{ + + igtl_bind_info bind_info; + + if (igtl_bind_unpack(IGTL_TYPE_PREFIX_NONE, (void*)this->m_Content, &bind_info, this->GetBufferBodySize()) == 0) + { + return 0; + } + + int n = bind_info.ncmessages; + + this->m_Resolution = bind_info.resol; + + Init(); + + for (int i = 0; i < n; i ++) + { + ChildMessageInfo info; + + info.type = bind_info.child_info_array[i].type; + info.name = bind_info.child_info_array[i].name; + info.size = 0; + info.ptr = NULL; + + this->m_ChildMessages.push_back(info); + + } + + return 1; +} + + +igtlUint64 RTSBindMessage::CalculateContentBufferSize() +{ + return sizeof (igtlUint8); +} + +int RTSBindMessage::PackContent() +{ + AllocateBuffer(); + + * (igtlUint8 * )this->m_Content = this->m_Status; + + return 1; +} + + +int RTSBindMessage::UnpackContent() +{ + this->m_Status = * (igtlUint8 * )this->m_Content; + + return 1; +} + + + + + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlBindMessage.h b/openigtlink/repo/Source/igtlBindMessage.h new file mode 100644 index 0000000..14ab000 --- /dev/null +++ b/openigtlink/repo/Source/igtlBindMessage.h @@ -0,0 +1,229 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlBindMessage_h +#define __igtlBindMessage_h + +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +namespace igtl +{ +/// The BindMessageBase class is a base class for the BindMessage, GetBindMessage and +/// StartBindMessage classes. The class is used to manage a list of child messages that +/// will be bundled into a BIND message. +class IGTLCommon_EXPORT BindMessageBase: public MessageBase +{ +public: + igtlTypeMacro(igtl::BindMessageBase, igtl::MessageBase); + igtlNewMacro(igtl::BindMessageBase); + +public: + + /// Initializes the BindMessageBase class. + void Init(); + + /// Sets the number of child messages bundled in the message and returns the total number of + /// child messages. The returned value should be same as 'n', if the number is updated successfully. + int SetNumberOfChildMessages(unsigned int n); + + /// Gets the number of child messages bundled in the message. + int GetNumberOfChildMessages(); + + /// Appends a new child message to the end of the list of child messages. + /// The AppendChildMessage() function will increment the number of child messages. + /// Returns the number of child messages after appending the specified child message. + int AppendChildMessage(igtl::MessageBase * child); + + /// Sets or replaces a child message specified by the index 'i'. The SetChildMessage() does not + /// increment the number of child messages. Returns non-zero value, if success. + int SetChildMessage(unsigned int i, igtl::MessageBase * child); + + /// Gets the name of a child message specified by the index 'i'. + const char* GetChildMessageType(unsigned int i); + +protected: + + BindMessageBase(); + ~BindMessageBase(); + +protected: + + /// A structure to manage properties of a child message, including message type, message name, + /// size and pointer to the class instance of the child message. A ChildMessageInfo structure is + /// allocated per child message and managed by a vector m_ChildMessages. + typedef struct _ChildMessageInfo { + std::string type; + std::string name; + igtlUint64 size; + void * ptr; + } ChildMessageInfo; + + /// A vector to manage a list of ChildMessageInfo structures. + std::vector m_ChildMessages; + +}; + + +/// A class for the BIND message type +class IGTLCommon_EXPORT BindMessage: public BindMessageBase +{ +public: + igtlTypeMacro(igtl::BindMessage, igtl::BindMessageBase); + igtlNewMacro(igtl::BindMessage); + +public: + /// Gets a child message specified by the index 'i'. A pointer to the instance of + /// the specified child message is substituted to the message base specified by 'child'. + /// Returns non-zero value if success. + int GetChildMessage(unsigned int i, igtl::MessageBase * child); + +protected: + BindMessage(); + ~BindMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + +}; + + +/// A class for the GET_BIND message type. The GET_BIND message contains a list of child messages +/// to request for specific messages. If no child message is specified, the receiver must return +/// the all available messages. +class IGTLCommon_EXPORT GetBindMessage: public BindMessageBase +{ +public: + igtlTypeMacro(igtl::GetBindMessage, igtl::BindMessageBase); + igtlNewMacro(igtl::GetBindMessage); + +public: + /// Appends the type and name of a new child message to the end of the list of child messages. + /// The AppendChildMessage() function will increment the number of child messages. + /// Returns the number of child messages. + int AppendChildMessage(const char * type, const char * name); + +protected: + GetBindMessage(); + ~GetBindMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + +}; + + +/// A class for the STT_BIND message type. Like the GET_BIND message type, it contains a list of +/// child messages to request for specific messages. If no child message is specified, +/// the receiver must return the all available messages. +class IGTLCommon_EXPORT StartBindMessage: public GetBindMessage +{ +public: + igtlTypeMacro(igtl::StartBindMessage, igtl::GetBindMessage); + igtlNewMacro(igtl::StartBindMessage); + +public: + + /// Sets time resolution. The time resolution is specified + /// as a 64-bit fixed-point used in OpenIGTLink time stamp. + void SetResolution(igtlUint64 res); + + /// Gets time resolution. The time resolution is specified + /// as a 64-bit fixed-point used in OpenIGTLink time stamp. + igtlUint64 GetResolution(); + +protected: + StartBindMessage(); + ~StartBindMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + igtlUint64 m_Resolution; + +}; + + +/// A class for the STP_BIND message type. The STP_BIND message is sent to the sender +/// of BIND message stream to stop it. +class IGTLCommon_EXPORT StopBindMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::StopBindMessage, igtl::MessageBase); + igtlNewMacro(igtl::StopBindMessage); + +protected: + StopBindMessage() : MessageBase() { this->m_SendMessageType = "STP_BIND"; }; + ~StopBindMessage() {}; + +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; + +}; + + +/// A class for the RTS_BIND message type. The RTS_BIND message has to be returned +/// to acknowledge STT_BIND and STP_BIND. +class IGTLCommon_EXPORT RTSBindMessage: public MessageBase +{ +public: + // Status type + enum { + STATUS_SUCCESS = 0, + STATUS_ERROR = 1 + }; + + igtlTypeMacro(igtl::RTSBindMessage, igtl::MessageBase); + igtlNewMacro(igtl::RTSBindMessage); + + /// Sets the status for the start/stop request. 'status' must be either RTSBindMessage::STATUS_SUCCESS or RTSBindMessage::STATUS_ERROR. + void SetStatus(igtlUint8 status){ this->m_Status = status; } + + /// Gets the status for the start/stop request. 'status' must be either RTSBindMessage::STATUS_SUCCESS or RTSBindMessage::STATUS_ERROR. + igtlUint8 GetStatus() { return this->m_Status; }; + +protected: + RTSBindMessage() : MessageBase(), m_Status(0) { this->m_SendMessageType = "RTS_BIND"; }; + ~RTSBindMessage() {}; + + /// Stores the status for the start/stop request. + igtlUint8 m_Status; + +protected: + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + +}; + + + +} // namespace igtl + +#endif // _igtlBindMessage_h diff --git a/openigtlink/repo/Source/igtlCapabilityMessage.cxx b/openigtlink/repo/Source/igtlCapabilityMessage.cxx new file mode 100755 index 0000000..dc90293 --- /dev/null +++ b/openigtlink/repo/Source/igtlCapabilityMessage.cxx @@ -0,0 +1,158 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Module: + Language: C++ + Date: + Version: + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlCapabilityMessage.h" + +#include + +#include +#include +#include + +#include +#include + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include + +namespace igtl { + +CapabilityMessage::CapabilityMessage(): + MessageBase() +{ + this->m_SendMessageType = "CAPABILITY"; + this->m_TypeNames.clear(); +/// CapabilityMessage stay the same as previous versions, set m_Version = 1 +/// to make the pack and unpack procedures the same as OpenIGTLink_PROTOCOL_VERSION 1 +#if OpenIGTLink_HEADER_VERSION >= 2 + m_HeaderVersion = IGTL_HEADER_VERSION_1; +#endif +} + + +CapabilityMessage::~CapabilityMessage() +{ + this->m_TypeNames.clear(); +} + +void CapabilityMessage::SetTypes(std::vector types) +{ + m_IsBodyPacked = false; + this->m_TypeNames.clear(); + this->m_TypeNames = types; +} + + +int CapabilityMessage::SetType(int id, const char* type) +{ + if (id < (int)this->m_TypeNames.size() && strlen(type) < IGTL_HEADER_TYPE_SIZE) + { + m_IsBodyPacked = false; + this->m_TypeNames[id] = type; + return 1; + } + else + { + return 0; + } +} + + +const char* CapabilityMessage::GetType(int id) +{ + if (id < (int)this->m_TypeNames.size()) + { + return this->m_TypeNames[id].c_str(); + } + else + { + return ""; + } +} + + +igtlUint64 CapabilityMessage::CalculateContentBufferSize() +{ + return (sizeof(char) * IGTL_HEADER_TYPE_SIZE * this->m_TypeNames.size()); +} + + +int CapabilityMessage::PackContent() +{ + AllocateBuffer(); + + if (this->m_TypeNames.size() == 0) + { + return 0; + } + + igtl_capability_info info; + int nTypes = this->m_TypeNames.size(); + + igtl_capability_init_info(&info); + info.ntypes = nTypes; + igtl_capability_alloc_info(&info, nTypes); + + for(int i = 0; i < nTypes; i++ ) + { + memcpy(info.typenames[i], this->m_TypeNames[i].c_str(), IGTL_HEADER_TYPE_SIZE); + } + + igtl_capability_pack(&info, this->m_Content); + + return 1; +} + + +int CapabilityMessage::UnpackContent() +{ + + igtl_capability_info info; + + igtl_capability_init_info(&info); + bool isUnpacked(true); + igtl_capability_unpack(this->m_Content, &info, this->CalculateReceiveContentSize(isUnpacked)); + + int ntypes = info.ntypes; + + if(ntypes == 0) + { + return 0; + } + + this->m_TypeNames.clear(); + for(int i = 0; i < ntypes; i++) + { + std::string buf; + if (igtl::Strnlen((const char*)info.typenames[i], IGTL_HEADER_TYPE_SIZE) < IGTL_HEADER_TYPE_SIZE) + { + buf.append((const char*)info.typenames[i]); + } + else + { + buf.append((const char*)info.typenames[i], IGTL_HEADER_TYPE_SIZE); + } + this->m_TypeNames.push_back(buf); + } + + + return 1; +} + + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlCapabilityMessage.h b/openigtlink/repo/Source/igtlCapabilityMessage.h new file mode 100755 index 0000000..e2c0e9f --- /dev/null +++ b/openigtlink/repo/Source/igtlCapabilityMessage.h @@ -0,0 +1,61 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlCapabilityMessage_h +#define __igtlCapabilityMessage_h + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +#include +#include + +namespace igtl +{ + +class IGTLCommon_EXPORT CapabilityMessage: public MessageBase +{ + +public: + igtlTypeMacro(igtl::CapabilityMessage, igtl::MessageBase); + igtlNewMacro(igtl::CapabilityMessage); + +public: + void SetTypes(std::vector types); + int SetType(int id, const char* name); + const char* GetType(int id); + + void SetNumberOfTypes(int n) { m_TypeNames.resize(n); } + int GetNumberOfTypes() { return m_TypeNames.size(); } + std::vector GetTypes() { return m_TypeNames; } + +protected: + CapabilityMessage(); + ~CapabilityMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + std::vector m_TypeNames; + +}; + + +} // namespace igtl + +#endif // __igtlCapabilityMessage_h diff --git a/openigtlink/repo/Source/igtlClientSocket.cxx b/openigtlink/repo/Source/igtlClientSocket.cxx new file mode 100644 index 0000000..4bea50a --- /dev/null +++ b/openigtlink/repo/Source/igtlClientSocket.cxx @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkClientSocket.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "igtlClientSocket.h" + +namespace igtl +{ + +//----------------------------------------------------------------------------- +ClientSocket::ClientSocket() +{ +} + +//----------------------------------------------------------------------------- +ClientSocket::~ClientSocket() +{ +} + +//----------------------------------------------------------------------------- +int ClientSocket::ConnectToServer(const char* hostName, int port, bool logErrorIfServerConnectionFailed /*= true*/) +{ + if (this->m_SocketDescriptor != -1) + { + igtlWarningMacro("Client connection already exists. Closing it."); + this->CloseSocket(this->m_SocketDescriptor); + this->m_SocketDescriptor = -1; + } + + this->m_SocketDescriptor = this->CreateSocket(); + if (!this->m_SocketDescriptor) + { + igtlErrorMacro("Failed to create socket."); + return -1; + } + + if (this->Connect(this->m_SocketDescriptor, hostName, port) == -1) + { + this->CloseSocket(this->m_SocketDescriptor); + this->m_SocketDescriptor = -1; + + if( logErrorIfServerConnectionFailed ) + { + igtlErrorMacro("Failed to connect to server " << hostName << ":" << port); + } + return -1; + } + return 0; +} + +//----------------------------------------------------------------------------- +void ClientSocket::PrintSelf(std::ostream& os) const +{ + this->Superclass::PrintSelf(os); +} + +} // end of igtl namespace + diff --git a/openigtlink/repo/Source/igtlClientSocket.h b/openigtlink/repo/Source/igtlClientSocket.h new file mode 100644 index 0000000..6b86f57 --- /dev/null +++ b/openigtlink/repo/Source/igtlClientSocket.h @@ -0,0 +1,66 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkClientSocket.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME igtlClientSocket - Encapsulates a client socket. + +#ifndef __igtlClientSocket_h +#define __igtlClientSocket_h + +#include "igtlSocket.h" +#include "igtlWin32Header.h" + +namespace igtl +{ + +class ServerSocket; + +class IGTLCommon_EXPORT ClientSocket : public Socket +{ +public: + igtlTypeMacro(igtl::ClientSocket, igtl::Socket) + igtlNewMacro(igtl::ClientSocket); + + /// Connects to host. Returns 0 on success, -1 on error. + int ConnectToServer(const char* hostname, int port, bool logErrorIfServerConnectionFailed = true); + +protected: + ClientSocket(); + ~ClientSocket(); + + void PrintSelf(std::ostream& os) const override; + + friend class ServerSocket; + +private: + ClientSocket(const ClientSocket&); // Not implemented. + void operator=(const ClientSocket&); // Not implemented. +}; + +} + +#endif + diff --git a/openigtlink/repo/Source/igtlColorTableMessage.cxx b/openigtlink/repo/Source/igtlColorTableMessage.cxx new file mode 100644 index 0000000..6d814af --- /dev/null +++ b/openigtlink/repo/Source/igtlColorTableMessage.cxx @@ -0,0 +1,105 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlColorTableMessage.h" + +#include "igtl_header.h" +#include "igtl_colortable.h" + +namespace igtl { + + +ColorTableMessage::ColorTableMessage(): + MessageBase() +{ + + indexType = INDEX_UINT8; + mapType = MAP_UINT8; + m_ColorTableHeader = NULL; + m_ColorTable = NULL; + m_SendMessageType = "COLORT"; +/// ColorTableMessage stay the same as previous versions, set m_Version = 1 +/// to make the pack and unpack procedures the same as OpenIGTLink_PROTOCOL_VERSION 1 +#if OpenIGTLink_HEADER_VERSION >= 2 + m_HeaderVersion = IGTL_HEADER_VERSION_1; +#endif + +} + +ColorTableMessage::~ColorTableMessage() +{ +} + +void ColorTableMessage::AllocateTable() +{ + // Memory area to store image scalar is allocated with + // message and image header, by using AllocatePack() implemented + // in the parent class. + AllocateBuffer(); + m_ColorTableHeader = m_Content; + m_ColorTable = &m_ColorTableHeader[IGTL_COLORTABLE_HEADER_SIZE]; +} + +void* ColorTableMessage::GetTablePointer() +{ + return (void*)m_ColorTable; +} + +int ColorTableMessage::GetColorTableSize() +{ + igtl_colortable_header header; + + header.indexType = this->indexType; + header.mapType = this->mapType; + + return (int) igtl_colortable_get_table_size(&header); + +} + +igtlUint64 ColorTableMessage::CalculateContentBufferSize() +{ + return GetColorTableSize() + IGTL_COLORTABLE_HEADER_SIZE; +} + +int ColorTableMessage::PackContent() +{ + igtl_colortable_header* colortable_header = (igtl_colortable_header*)m_ColorTableHeader; + + colortable_header->indexType = this->indexType; + colortable_header->mapType = this->mapType; + + igtl_colortable_convert_byte_order(colortable_header, (void*)m_ColorTable); + + return 1; + +} + + +int ColorTableMessage::UnpackContent() +{ + + this->m_ColorTableHeader = this->m_Content; + this->m_ColorTable = &(this->m_Content[IGTL_COLORTABLE_HEADER_SIZE]); + + igtl_colortable_header* colortable_header = (igtl_colortable_header*)this->m_ColorTableHeader; + igtl_colortable_convert_byte_order(colortable_header, (void*)this->m_ColorTable); + + this->indexType = colortable_header->indexType; + this->mapType = colortable_header->mapType; + + return 1; +} + + +} // namespace igtl \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlColorTableMessage.h b/openigtlink/repo/Source/igtlColorTableMessage.h new file mode 100644 index 0000000..8d67be6 --- /dev/null +++ b/openigtlink/repo/Source/igtlColorTableMessage.h @@ -0,0 +1,124 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlColorTableMessage_h +#define __igtlColorTableMessage_h + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" + +namespace igtl +{ + +/// A class for the GET_COLORT message type. +class IGTLCommon_EXPORT GetColorTableMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::GetColorTableMessage, igtl::MessageBase); + igtlNewMacro(igtl::GetColorTableMessage); + +protected: + GetColorTableMessage() : MessageBase() { this->m_SendMessageType = "GET_COLORT"; }; + ~GetColorTableMessage() {}; + +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; +}; + + +/// A class for the COLORT message type. +class IGTLCommon_EXPORT ColorTableMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::ColorTableMessage, igtl::MessageBase) + igtlNewMacro(igtl::ColorTableMessage); + +public: + + /// Index value types (UINT8 or UINT16) and map types (UINT8, UINT16 and RGB(UINT8x3)) + enum { + INDEX_UINT8 = 3, + INDEX_UINT16 = 5, + MAP_UINT8 = 3, + MAP_UINT16 = 5, + MAP_RGB = 19, + }; + +public: + + /// Sets the index type for the color type + void SetIndexType(int t) { indexType = t; }; + + /// Sets the index type for the color type to 8-bit unsigned integer. + void SetIndexTypeToUint8() { indexType = INDEX_UINT8; }; + + /// Sets the index type for the color type to 16-bit unsigned integer. + void SetIndexTypeToUint16() { indexType = INDEX_UINT16; }; + + /// Gets the index type. Returns either INDEX_UINT8 or INDEX_UINT16. + int GetIndexType() { return indexType; }; + + /// Sets the scalar type of the map. + void SetMapType(int t) { mapType = t; }; + + /// Sets the scalar type of the map to 8-bit unsigned integer. + void SetMapTypeToUint8() { mapType = MAP_UINT8; }; + + /// Sets the scalar type of the map to 16-bit unsigned integer. + void SetMapTypeToUint16() { mapType = MAP_UINT16; }; + + /// Gets the type of the map. + int GetMapType() { return mapType; }; + + /// Gets the size of the color table. + int GetColorTableSize(); + + /// Allocates a memory area for the color table. + void AllocateTable(); + + /// Returns a pointer to the color table. + void* GetTablePointer(); + +protected: + ColorTableMessage(); + ~ColorTableMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// A variable to store the index type. Either INDEX_UINT8 or INDEX_UINT16. + int indexType; + + /// A variable to store the type of the map. Either MAP_UINT8, MAP_UINT16 or MAP_RGB. + int mapType; + + /// A pointer to the header for the color table. + unsigned char* m_ColorTableHeader; + + /// A pointer to the color table data. + unsigned char* m_ColorTable; + +}; + + +} // namespace igtl + +#endif // _igtlColorTableMessage_h diff --git a/openigtlink/repo/Source/igtlCommandMessage.cxx b/openigtlink/repo/Source/igtlCommandMessage.cxx new file mode 100644 index 0000000..8ccae82 --- /dev/null +++ b/openigtlink/repo/Source/igtlCommandMessage.cxx @@ -0,0 +1,262 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlCommandMessage.h" + +#include "igtl_header.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include + +#define NUM_ENCODINGS 257 + +namespace +{ + +bool isEncodingValid(int encoding) +{ + for( int i = 0; i < NUM_ENCODINGS-1; ++i ) + { + if( encoding == igtl::CommandMessage::validEncodings[i] ) + { + return true; + } + } + return false; +} + +} + + +namespace igtl { + +const int CommandMessage::validEncodings[NUM_ENCODINGS] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,109,110,111,112,113,114,115,116,117,118,119,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2011,2044,2045,2010,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260}; + +CommandMessage::CommandMessage() + : MessageBase() + , m_CommandId(0) + , m_Encoding(3) +{ + memset(m_CommandName, 0, IGTL_COMMAND_NAME_SIZE); + this->m_HeaderVersion = IGTL_HEADER_VERSION_2; + this->m_SendMessageType = "COMMAND"; + this->m_Command.clear(); +} + + +CommandMessage::~CommandMessage() +{ +} + + +int CommandMessage::SetCommandId(igtlUint32 aId) +{ + m_IsBodyPacked = false; + this->m_CommandId = aId; + return 1; +} + + +int CommandMessage::SetCommandName(const char* aCommandName) +{ + if (strlen(aCommandName) > IGTL_COMMAND_NAME_SIZE) /* If the length is beyond the range specified by the spec */ + { + return 0; + } + m_IsBodyPacked = false; + strcpy((char*)m_CommandName, aCommandName); + return 1; +} + + +int CommandMessage::SetCommandName(const std::string& aCommandName) +{ + return this->SetCommandName(aCommandName.c_str()); +} + + +int CommandMessage::SetCommandContent(const char* string) +{ + if (strlen(string) > 0xFFFF) /* If the length is beyond the range of unsigned short */ + { + return 0; + } + m_IsBodyPacked = false; + this->m_Command = string; + return (int) this->m_Command.length(); +} + + +int CommandMessage::SetCommandContent(const std::string & string) +{ + if (string.length() > 0xFFFF) /* If the length is beyond the range of unsigned short */ + { + return 0; + } + m_IsBodyPacked = false; + this->m_Command = string; + return (int) this->m_Command.length(); +} + + +int CommandMessage::SetContentEncoding(igtlUint16 enc) +{ + if( !isEncodingValid(enc) ) + { + return 0; + } + m_IsBodyPacked = false; + this->m_Encoding = enc; + return 1; +} + + +igtlUint32 CommandMessage::GetCommandId() const +{ + return this->m_CommandId; +} + + +std::string CommandMessage::GetCommandName() const +{ + return std::string((char*)this->m_CommandName); +} + + +std::string CommandMessage::GetCommandContent() const +{ + return this->m_Command; +} + + +igtlUint32 CommandMessage::GetCommandContentLength() const +{ + return this->m_Command.length(); +} + + +igtlUint16 CommandMessage::GetContentEncoding() const +{ + return this->m_Encoding; +} + + +igtlUint64 CommandMessage::CalculateContentBufferSize() +{ + // Body pack size is the sum of ENCODING, LENGTH and STRING fields + return sizeof(igtl_command_header) + this->m_Command.length(); +} + + +int CommandMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + igtl_command_header * command_header; + char * command; + + // Set pointers +#if OpenIGTLink_HEADER_VERSION >= 2 + command_header = (igtl_command_header*) this->m_Content; + command = (char *) this->m_Content + sizeof(igtl_command_header); +#else + command_header = (igtl_command_header*) this->m_Body; + command = (char *) this->m_Body + sizeof(igtl_command_header); +#endif + + // Copy data + command_header->encoding = static_cast(this->m_Encoding); + command_header->length = static_cast(this->m_Command.length()); + command_header->commandId = this->m_CommandId; + memcpy(command_header->commandName, this->m_CommandName, IGTL_COMMAND_NAME_SIZE); + strncpy(command, this->m_Command.c_str(), command_header->length); + + // Convert byte order from host to network + igtl_command_convert_byte_order(command_header); + + return 1; +} + +int CommandMessage::UnpackContent() +{ + igtl_command_header * command_header; + char * command; + +#if OpenIGTLink_HEADER_VERSION >= 2 + command_header = (igtl_command_header*) this->m_Content; + command = (char *) this->m_Content + sizeof(igtl_command_header); +#else + command_header = (igtl_command_header*) this->m_Body; + command = (char *) this->m_Body + sizeof(igtl_command_header); +#endif + + // Convert byte order from network to host + igtl_command_convert_byte_order(command_header); + + // Copy data + this->m_CommandId = command_header->commandId; + memcpy(m_CommandName, command_header->commandName, IGTL_COMMAND_NAME_SIZE); + this->m_Encoding = command_header->encoding; + this->m_Command.clear(); + this->m_Command.append(command, command_header->length); + + return 1; +} + + +int RTSCommandMessage::SetCommandErrorString(const char* anErrorString) +{ + if (strlen(anErrorString) > IGTL_COMMAND_NAME_SIZE) /* If the length is beyond the range specified by the spec */ + { + return 0; + } + m_IsBodyPacked = false; + strcpy((char*)m_CommandName, anErrorString); + return 1; +} + + +int RTSCommandMessage::SetCommandErrorString(const std::string& anErrorString) +{ + if( anErrorString.length() > IGTL_COMMAND_NAME_SIZE ) + { + return 0; + } + m_IsBodyPacked = false; + strcpy((char*)m_CommandName, anErrorString.c_str()); + return 1; +} + + +std::string RTSCommandMessage::GetCommandErrorString() const +{ + return std::string((char*)this->m_CommandName); +} + + +RTSCommandMessage::RTSCommandMessage() + : CommandMessage() +{ + this->m_SendMessageType = std::string("RTS_COMMAND"); +} + + +RTSCommandMessage::~RTSCommandMessage() +{ + +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlCommandMessage.h b/openigtlink/repo/Source/igtlCommandMessage.h new file mode 100644 index 0000000..221a2d2 --- /dev/null +++ b/openigtlink/repo/Source/igtlCommandMessage.h @@ -0,0 +1,121 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlCommandMessage_h +#define __igtlCommandMessage_h + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtl_command.h" + +namespace igtl +{ + +class IGTLCommon_EXPORT CommandMessage : public MessageBase +{ +public: + static const int validEncodings[257]; + +public: + igtlTypeMacro(igtl::CommandMessage, igtl::MessageBase) + igtlNewMacro(igtl::CommandMessage); + +public: + + /// Sets the command ID + int SetCommandId(igtlUint32 aId); + + /// Sets the command name + int SetCommandName(const char* aCommandName); + + /// Sets the command name by std::string + int SetCommandName(const std::string& aCommandName); + + /// Sets the string by character array. + int SetCommandContent(const char* string); + + /// Sets the string by std::string. + int SetCommandContent(const std::string & string); + + /// Sets the encoding of the string. For character encoding, please refer IANA Character Sets + /// (http://www.iana.org/assignments/character-sets). + /// US-ASCII (ANSI-X3.4-1968; MIBenum = 3) is strongly recommended. + int SetContentEncoding(igtlUint16 enc); + + /// Gets the command ID + igtlUint32 GetCommandId() const; + + /// Get the command name + std::string GetCommandName() const; + + /// Gets the string. + std::string GetCommandContent() const; + + /// Gets the length of the command content + igtlUint32 GetCommandContentLength() const; + + /// Gets the encoding of the string. The returned value is defined in + /// IANA Character Sets (http://www.iana.org/assignments/character-sets). + igtlUint16 GetContentEncoding() const; + +protected: + CommandMessage(); + ~CommandMessage(); + +protected: + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// The unique ID of the command + igtlUint32 m_CommandId; + + /// The name of the command + igtlUint8 m_CommandName[IGTL_COMMAND_NAME_SIZE]; + + /// The encoding of the command string. + /// The value is defined in IANA Character Sets (http://www.iana.org/assignments/character-sets). + igtlUint16 m_Encoding; + + /// The command stored as an XML encoded string. + std::string m_Command; +}; + +class IGTLCommon_EXPORT RTSCommandMessage : public CommandMessage +{ +public: + igtlTypeMacro(igtl::RTSCommandMessage, igtl::CommandMessage) + igtlNewMacro(igtl::RTSCommandMessage); + +public: + + /// Sets the error string + int SetCommandErrorString(const char* aCommandName); + + /// Sets the error string by std::string + int SetCommandErrorString(const std::string& aCommandName); + + /// Get the error string + std::string GetCommandErrorString() const; + +protected: + RTSCommandMessage(); + ~RTSCommandMessage(); +}; + +} // namespace igtl + +#endif // _igtlCommandMessage_h diff --git a/openigtlink/repo/Source/igtlCommon.h b/openigtlink/repo/Source/igtlCommon.h new file mode 100644 index 0000000..50bf974 --- /dev/null +++ b/openigtlink/repo/Source/igtlCommon.h @@ -0,0 +1,59 @@ +/*========================================================================= + +Program: The OpenIGTLink Library +Language: C++ +Web page: http://openigtlink.org/ + +Copyright (c) Insight Software Consortium. All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + +Program: Open Image Guided Therapy Link Network Layer +Module: $RCSfile: igtlCommon.h,v $ +Language: C++ +Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ +Version: $Revision: 3460 $ + +Copyright (c) Insight Software Consortium. All rights reserved. +See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlCommon_h +#define __igtlCommon_h + +#include +#include + +namespace igtl +{ + /// This function contains the extrinsic knowledge of the protocol version history + /// so that programmers don't need to know which protocol version uses which header version + static int IGTLProtocolToHeaderLookup(int igtlProtocolVersion) + { + if( igtlProtocolVersion == OpenIGTLink_PROTOCOL_VERSION_1 || igtlProtocolVersion == OpenIGTLink_PROTOCOL_VERSION_2 ) + { + return IGTL_HEADER_VERSION_1; + } + else if( igtlProtocolVersion == OpenIGTLink_PROTOCOL_VERSION_3) + { + return IGTL_HEADER_VERSION_2; + } + else + { + // TODO : which error mechanism to use for error reporting + return IGTL_HEADER_VERSION_1; + } + } +} + +#endif diff --git a/openigtlink/repo/Source/igtlConditionVariable.cxx b/openigtlink/repo/Source/igtlConditionVariable.cxx new file mode 100644 index 0000000..85ae78d --- /dev/null +++ b/openigtlink/repo/Source/igtlConditionVariable.cxx @@ -0,0 +1,244 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkConditionVariable.cxx,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "igtlConditionVariable.h" +#if defined(WIN32) || defined(_WIN32) + #include +#else + #include +#endif // defined(WIN32) || defined(_WIN32) + + +namespace igtl { + +ConditionVariable::ConditionVariable() +{ +#ifdef OpenIGTLink_USE_PTHREADS + pthread_mutex_init(&m_Mutex, NULL); + pthread_cond_init(&m_ConditionVariable, NULL); +#else +#ifdef WIN32 + m_NumberOfWaiters = 0; + m_WasBroadcast = 0; + m_Semaphore = CreateSemaphore(NULL, // no security + 0, // initial value + 0x7fffffff, // max count + NULL); // unnamed + InitializeCriticalSection( &m_NumberOfWaitersLock ); + m_WaitersAreDone = CreateEvent( NULL, // no security + FALSE, // auto-reset + FALSE, // non-signaled initially + NULL ); // unnamed +#endif +#endif +} + +ConditionVariable::~ConditionVariable() +{ +#ifdef OpenIGTLink_USE_PTHREADS + pthread_mutex_destroy(&m_Mutex); + pthread_cond_destroy(&m_ConditionVariable); +#else +#ifdef WIN32 + CloseHandle( m_Semaphore ); + CloseHandle( m_WaitersAreDone ); + DeleteCriticalSection( &m_NumberOfWaitersLock ); +#endif +#endif + +} + +void ConditionVariable::Signal() +{ +#ifdef OpenIGTLink_USE_PTHREADS + pthread_cond_signal(&m_ConditionVariable); +#else +#ifdef WIN32 + EnterCriticalSection( &m_NumberOfWaitersLock ); + int haveWaiters = m_NumberOfWaiters > 0; + LeaveCriticalSection( &m_NumberOfWaitersLock ); + + // if there were not any waiters, then this is a no-op + if (haveWaiters) + { + ReleaseSemaphore(m_Semaphore, 1, 0); + } +#endif +#endif +} + +void ConditionVariable::Broadcast() +{ +#ifdef OpenIGTLink_USE_PTHREADS + pthread_cond_broadcast(&m_ConditionVariable); +#else +#ifdef WIN32 + // This is needed to ensure that m_NumberOfWaiters and m_WasBroadcast are + // consistent + EnterCriticalSection( &m_NumberOfWaitersLock ); + int haveWaiters = 0; + + if (m_NumberOfWaiters > 0) + { + // We are broadcasting, even if there is just one waiter... + // Record that we are broadcasting, which helps optimize Wait() + // for the non-broadcast case + m_WasBroadcast = 1; + haveWaiters = 1; + } + + if (haveWaiters) + { + // Wake up all waiters atomically + ReleaseSemaphore(m_Semaphore, m_NumberOfWaiters, 0); + + LeaveCriticalSection( &m_NumberOfWaitersLock ); + + // Wait for all the awakened threads to acquire the counting + // semaphore + WaitForSingleObject( m_WaitersAreDone, INFINITE ); + // This assignment is ok, even without the m_NumberOfWaitersLock held + // because no other waiter threads can wake up to access it. + m_WasBroadcast = 0; + } + else + { + LeaveCriticalSection( &m_NumberOfWaitersLock ); + } +#endif +#endif +} + +void ConditionVariable::Wait(SimpleMutexLock *mutex) +{ +#ifdef OpenIGTLink_USE_PTHREADS + pthread_cond_wait(&m_ConditionVariable, &mutex->GetMutexLock() ); +#else +#ifdef WIN32 + // Avoid race conditions + EnterCriticalSection( &m_NumberOfWaitersLock ); + m_NumberOfWaiters++; + LeaveCriticalSection( &m_NumberOfWaitersLock ); + + // This call atomically releases the mutex and waits on the + // semaphore until signaled + SignalObjectAndWait( mutex->GetMutexLock(), m_Semaphore, INFINITE, FALSE ); + + // Reacquire lock to avoid race conditions + EnterCriticalSection( &m_NumberOfWaitersLock ); + + // We're no longer waiting.... + m_NumberOfWaiters--; + + // Check to see if we're the last waiter after the broadcast + int lastWaiter = m_WasBroadcast && m_NumberOfWaiters == 0; + + LeaveCriticalSection( &m_NumberOfWaitersLock ); + + // If we're the last waiter thread during this particular broadcast + // then let the other threads proceed + if (lastWaiter) + { + // This call atomically signals the m_WaitersAreDone event and waits + // until it can acquire the external mutex. This is required to + // ensure fairness + SignalObjectAndWait( m_WaitersAreDone, mutex->GetMutexLock(), + INFINITE, FALSE); + } + else + { + // Always regain the external mutex since that's the guarentee we + // give to our callers + WaitForSingleObject( mutex->GetMutexLock(), INFINITE ); + } +#endif +#endif +} + + +bool ConditionVariable::Wait(SimpleMutexLock *mutex, igtl_uint32 waitTime) +{ +#ifdef OpenIGTLink_USE_PTHREADS + bool returnCode = false; + struct timeval tval; + ::gettimeofday( &tval, 0 ); + struct timespec targetTime; + int seconds = waitTime/1000; + int millisecond = waitTime%1000; + targetTime.tv_sec = tval.tv_sec + seconds; + targetTime.tv_nsec = tval.tv_usec*1000 + (millisecond * 1000000); + int rv = pthread_cond_timedwait(&m_ConditionVariable, &mutex->GetMutexLock(), &targetTime); + if (rv == 0) returnCode = true; + return returnCode; +#else +#ifdef WIN32 + bool returnCode = false; + // Avoid race conditions + EnterCriticalSection( &m_NumberOfWaitersLock ); + m_NumberOfWaiters++; + LeaveCriticalSection( &m_NumberOfWaitersLock ); + + // This call atomically releases the mutex and waits on the + // semaphore until signaled + DWORD dwRet = SignalObjectAndWait( mutex->GetMutexLock(), m_Semaphore, waitTime, FALSE ); + + // Reacquire lock to avoid race conditions + EnterCriticalSection( &m_NumberOfWaitersLock ); + + // We're no longer waiting.... + m_NumberOfWaiters--; + + // Check to see if we're the last waiter after the broadcast + int lastWaiter = m_WasBroadcast && m_NumberOfWaiters == 0; + + LeaveCriticalSection( &m_NumberOfWaitersLock ); + + // If we're the last waiter thread during this particular broadcast + // then let the other threads proceed + if (lastWaiter) + { + // This call atomically signals the m_WaitersAreDone event and waits + // until it can acquire the external mutex. This is required to + // ensure fairness + SignalObjectAndWait( m_WaitersAreDone, mutex->GetMutexLock(), + INFINITE, FALSE); + } + else + { + // Always regain the external mutex since that's the guarentee we + // give to our callers + WaitForSingleObject( mutex->GetMutexLock(), INFINITE ); + } + if (WAIT_OBJECT_0 == dwRet) returnCode = true; + return returnCode; +#endif +#endif +} + +}//end of namespace igtl diff --git a/openigtlink/repo/Source/igtlConditionVariable.h b/openigtlink/repo/Source/igtlConditionVariable.h new file mode 100644 index 0000000..66fe625 --- /dev/null +++ b/openigtlink/repo/Source/igtlConditionVariable.h @@ -0,0 +1,142 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkConditionVariable.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlConditionVariable_h +#define __igtlConditionVariable_h + +#include "igtlConfigure.h" + +// This implementation uses a routine called SignalObjectAndWait() +// which is only defined on WinNT 4.0 or greater systems. We need to +// define this symbol in order to get the prototype for the +// routine. This needs to be done before we load any system headers. +#ifdef OpenIGTLink_USE_WIN32_THREADS +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#include "igtlWindows.h" +#endif + + +#include "igtlMutexLock.h" +#include "igtlLightObject.h" +#include "igtl_types.h" + +namespace igtl { + +/** \class ConditionVariable + * \brief A thread synchronization object used to suspend execution until some + * condition on shared data is met. + * + * A thread calls Wait() to suspend its execution until the condition is + * met. Each call to Signal() from an executing thread will then cause a single + * waiting thread to be released. A call to Signal() means, "signal + * that the condition is true." Broadcast() releases all threads waiting on + * the condition variable. + * + * The IGTL ConditionVariable implementation is consistent with the standard + * definition and use of condition variables in pthreads and other common + * thread libraries. + * + * IMPORTANT: A condition variable always requires an associated SimpleMutexLock + * object. The mutex object is used to avoid a dangerous race condition when + * Wait() and Signal() are called simultaneously from two different + * threads. + * + * On systems using pthreads, this implementation abstract the + * standard calls to the pthread condition variable. On Win32 + * systems, there is no system provided condition variable. This + * class implements a condition variable using a critical section, a + * semphore, an event and a number of counters. The implementation is + * almost an extract translation of the implementation presented by + * Douglas C Schmidt and Irfan Pyarali in "Strategies for Implementing + * POSIX Condition Variables on Win32". This article can be found at + * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html + * + */ +class IGTLCommon_EXPORT ConditionVariable : public LightObject +{ +public: + /** Run-time type information (and related methods). */ + igtlTypeMacro(ConditionVariable, LightObject); + + /** Method for creation through the object factory. */ + igtlNewMacro(Self); + + /** Suspend execution of this thread until the condition is signaled. The + * argument is a SimpleMutex object that must be locked prior to calling + * this method. */ + void Wait(SimpleMutexLock * mutex); + + /** Suspend execution of this thread until the condition is signaled or specified time in millisecond elapsed. + * return true if the signal recevied, false if the timeout expired or other error conditions happened. + * See the following links for more infomation about other scenarios: + * https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-signalobjectandwait + * https://www.ibm.com/support/knowledgecenter/en/ssw_i5_54/apis/users_77.htm + * The argument is a SimpleMutex object that must be locked prior to calling + * this method. */ + bool Wait(SimpleMutexLock * mutex, igtl_uint32 waitTime); + + /** Signal that the condition is true and release one waiting thread */ + void Signal(); + + /** Signal that the condition is true and release all waiting threads */ + void Broadcast(); + +protected: + ConditionVariable(); + ~ConditionVariable(); + +private: + ConditionVariable(const Self & other); + const Self & operator=( const Self & ); +#ifdef OpenIGTLink_USE_PTHREADS + pthread_cond_t m_ConditionVariable; + MutexType m_Mutex; +#else + int m_NumberOfWaiters; // number of waiting threads +#ifdef WIN32 + CRITICAL_SECTION m_NumberOfWaitersLock; // Serialize access to + // m_NumberOfWaiters + + HANDLE m_Semaphore; // Semaphore to queue threads + HANDLE m_WaitersAreDone; // Auto-reset event used by the + // broadcast/signal thread to + // wait for all the waiting + // threads to wake up and + // release the semaphore + + size_t m_WasBroadcast; // Keeps track of whether we + // were broadcasting or signaling +#endif +#endif +}; + +} // end namespace igtl + +#endif diff --git a/openigtlink/repo/Source/igtlCreateObjectFunction.h b/openigtlink/repo/Source/igtlCreateObjectFunction.h new file mode 100644 index 0000000..426bf21 --- /dev/null +++ b/openigtlink/repo/Source/igtlCreateObjectFunction.h @@ -0,0 +1,89 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkCreateObjectFunction.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlCreateObjectFunction_h +#define __igtlCreateObjectFunction_h + +#include "igtlObject.h" + +namespace igtl +{ + +/** \class CreateObjectFunctionBase + * \brief Define API for object creation callback functions. + * + * \ingroup IGTLSystemObjects + */ +class CreateObjectFunctionBase: public Object +{ +public: + igtlTypeMacro(CreateObjectFunctionBase, Object); + /** Create an object and return a pointer to it as an + * igtl::LightObject. */ + virtual SmartPointer CreateObject() = 0; + +protected: + CreateObjectFunctionBase() {} + ~CreateObjectFunctionBase() {} + +private: + CreateObjectFunctionBase(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + + +/** \class CreateObjectFunction + * \brief CreateObjectFunction is used to create callback functions that + * create IGTL Objects for use with the igtl::ObjectFactory. + * + * \ingroup IGTLSystemObjects + */ +template +class CreateObjectFunction : public CreateObjectFunctionBase +{ +public: + + igtlTypeMacro(CreateObjectFunction, CreateObjectFunctionBase); + + /** Methods from igtl:LightObject. */ + igtlFactorylessNewMacro(Self); + LightObject::Pointer CreateObject() { return T::New().GetPointer(); } + +protected: + CreateObjectFunction() {} + ~CreateObjectFunction() {} + +private: + CreateObjectFunction(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + +} // end namespace igtl + +#endif diff --git a/openigtlink/repo/Source/igtlFastMutexLock.cxx b/openigtlink/repo/Source/igtlFastMutexLock.cxx new file mode 100644 index 0000000..b54e49a --- /dev/null +++ b/openigtlink/repo/Source/igtlFastMutexLock.cxx @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkFastMutexLock.cxx,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "igtlFastMutexLock.h" + +namespace igtl +{ + +void FastMutexLock::PrintSelf(std::ostream& os) const +{ + Superclass::PrintSelf(os); +} + +}//end namespace igtl diff --git a/openigtlink/repo/Source/igtlFastMutexLock.h b/openigtlink/repo/Source/igtlFastMutexLock.h new file mode 100644 index 0000000..c489add --- /dev/null +++ b/openigtlink/repo/Source/igtlFastMutexLock.h @@ -0,0 +1,105 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkFastMutexLock.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlFastMutexLock_h +#define __igtlFastMutexLock_h + +#include "igtlObject.h" +#include "igtlSimpleFastMutexLock.h" +#include "igtlObjectFactory.h" + +namespace igtl +{ + +/** \class FastMutexLock + * \brief Critical section locking class. + * + * FastMutexLock allows the locking of variables which are accessed + * through different threads. This header file also defines + * SimpleFastMutexLock which is not a subclass of Object. + * The API is identical to that of MutexLock, and the behavior is + * identical as well, except on Windows 9x/NT platforms. The only difference + * on these platforms is that MutexLock is more flexible, in that + * it works across processes as well as across threads, but also costs + * more, in that it evokes a 600-cycle x86 ring transition. The + * FastMutexLock provides a higher-performance equivalent (on + * Windows) but won't work across processes. Since it is unclear how, + * in igtl, an object at the igtl level can be shared across processes + * in the first place, one should use FastMutexLock unless one has + * a very good reason to use MutexLock. If higher-performance equivalents + * for non-Windows platforms (Irix, SunOS, etc) are discovered, they + * should replace the implementations in this class + * + * \ingroup OSSystemObjects + */ +class IGTLCommon_EXPORT FastMutexLock : public Object +{ +public: + /** Run-time type information. */ + igtlTypeMacro(FastMutexLock,Object); + + /** Method for creation. */ + igtlNewMacro(Self); + + /** Lock the igtlFastMutexLock. */ + void Lock(); + + /** Unlock the FastMutexLock. */ + void Unlock(); + +protected: + FastMutexLock() {} + ~FastMutexLock() {} + + SimpleFastMutexLock m_SimpleFastMutexLock; + void PrintSelf(std::ostream& os) const override; + +private: + FastMutexLock(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + + +inline void FastMutexLock::Lock( void ) +{ + m_SimpleFastMutexLock.Lock(); +} + +inline void FastMutexLock::Unlock( void ) +{ + m_SimpleFastMutexLock.Unlock(); +} + + +}//end igtl namespace +#endif + diff --git a/openigtlink/repo/Source/igtlGeneralSocket.cxx b/openigtlink/repo/Source/igtlGeneralSocket.cxx new file mode 100755 index 0000000..7daafa0 --- /dev/null +++ b/openigtlink/repo/Source/igtlGeneralSocket.cxx @@ -0,0 +1,880 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: igtlSocket.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + + =========================================================================*/ + +#include "igtlGeneralSocket.h" +#include +#include + +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define WSA_VERSION MAKEWORD(1,1) +#define igtlCloseSocketMacro(sock) (closesocket(sock)) +#else +#define igtlCloseSocketMacro(sock) (shutdown(sock, 2)) +#endif + +#if defined (_WIN32) + #define TTL_TYPE const char +#else + #define TTL_TYPE igtl_uint8 +#endif + +namespace igtl +{ + + //----------------------------------------------------------------------------- + GeneralSocket::GeneralSocket() + { + this->m_SocketDescriptor = -1; + this->m_SendTimeoutFlag = 0; + this->m_ReceiveTimeoutFlag = 0; + } + + //----------------------------------------------------------------------------- + GeneralSocket::~GeneralSocket() + { + if (this->m_SocketDescriptor != -1) + { + this->CloseSocket(this->m_SocketDescriptor); + this->m_SocketDescriptor = -1; + } + } + + //----------------------------------------------------------------------------- + int GeneralSocket::CreateSocket() + { + #if defined(_WIN32) && !defined(__CYGWIN__) + // Declare variables + WSADATA wsaData; + + //--------------------------------------- + // Initialize Winsock + int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); + if( iResult != NO_ERROR ) + { + std::cerr << "Error at WSAStartup" << std::endl; + return -1; + } + #endif + + int sock = socket(AF_INET, SOCK_STREAM, 0); + // Elimate windows 0.2 second delay sending (buffering) data. + int on = 1; + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on))) + { + return -1; + } + return sock; + } + + + //----------------------------------------------------------------------------- + int GeneralSocket::CreateUDPServerSocket() + { + #if defined(_WIN32) && !defined(__CYGWIN__) + // Declare variables + WSADATA wsaData; + + //--------------------------------------- + // Initialize Winsock + int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); + if( iResult != NO_ERROR ) + { + std::cerr << "Error at WSAStartup" << std::endl; + return -1; + } + #endif + int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + int bcast = 1; + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *)&bcast, sizeof(bcast)) < 0) + { + CloseSocket(sock); + return -1; + } + return sock; + } + + int GeneralSocket::CreateUDPClientSocket() + { + #if defined(_WIN32) && !defined(__CYGWIN__) + // Declare variables + WSADATA wsaData; + + //--------------------------------------- + // Initialize Winsock + int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); + if( iResult != NO_ERROR ) + { + std::cerr << "Error at WSAStartup" << std::endl; + return -1; + } + #endif + int err; + struct addrinfo * info; + struct addrinfo hints; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + // maximum port number is less than 65536, 128byte is sufficient. std::to_string needs c++ 11 support + char portStr[128]; + sprintf(portStr, "%d", this->PortNum); + if (0 != (err = getaddrinfo(this->IPAddress, portStr, &hints, &info))) + { + return -1; + } + int sock; + struct addrinfo * p; + for (p = info; p != NULL; p = p->ai_next) + { + if (0 > (sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol))) + { + continue; + } + + if (0 > bind(sock, p->ai_addr, p->ai_addrlen)) + { + CloseSocket(sock); + continue; + } + + break; + } + int bcast = 1; + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *)&bcast, sizeof(bcast)) < 0) + { + CloseSocket(sock); + return -1; + } + return sock; + } + + //----------------------------------------------------------------------------- + int GeneralSocket::BindSocket(int socketdescriptor, int port) + { + struct sockaddr_in server; + + server.sin_family = AF_INET; + server.sin_addr.s_addr = htonl(INADDR_ANY); + server.sin_port = htons(port); + // Allow the socket to be bound to an address that is already in use + #ifdef _WIN32 + int opt=1; + setsockopt(socketdescriptor, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(int)); + #elif defined(VTK_HAVE_SO_REUSEADDR) + int opt=1; + setsockopt(socketdescriptor, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, sizeof(int)); + #endif + + if ( bind(socketdescriptor, reinterpret_cast(&server), sizeof(server)) ) + { + return -1; + } + return 0; + } + + //----------------------------------------------------------------------------- + int GeneralSocket::Accept(int socketdescriptor) + { + if (socketdescriptor < 0) + { + return -1; + } + return accept(socketdescriptor, 0, 0); + } + + //----------------------------------------------------------------------------- + int GeneralSocket::Listen(int socketdescriptor) + { + if (socketdescriptor < 0) + { + return -1; + } + return listen(socketdescriptor, 1); + } + + //----------------------------------------------------------------------------- + int GeneralSocket::SelectSocket(int socketdescriptor, unsigned long msec) + { + if (socketdescriptor < 0 ) + { + // invalid socket descriptor. + return -1; + } + + fd_set rset; + struct timeval tval; + struct timeval* tvalptr = 0; + if ( msec > 0 ) + { + tval.tv_sec = msec / 1000; + tval.tv_usec = (msec % 1000)*1000; + tvalptr = &tval; + } + FD_ZERO(&rset); + FD_SET(socketdescriptor, &rset); + int res = select(socketdescriptor + 1, &rset, 0, 0, tvalptr); + if(res == 0) + { + return 0;//for time limit expire + } + + if ( res < 0 || !(FD_ISSET(socketdescriptor, &rset)) ) + { + // Some error. + return -1; + } + // The indicated socket has some activity on it. + return 1; + } + + //----------------------------------------------------------------------------- + int GeneralSocket::SelectSockets(const int* sockets_to_select, int size, + unsigned long msec, int* selected_index) + { + int i; + int max_fd = -1; + *selected_index = -1; + if (size < 0) + { + return -1; + } + + fd_set rset; + struct timeval tval; + struct timeval* tvalptr = 0; + if ( msec > 0 ) + { + tval.tv_sec = msec / 1000; + tval.tv_usec = msec % 1000; + tvalptr = &tval; + } + FD_ZERO(&rset); + for (i=0; i max_fd)? sockets_to_select[i] : max_fd; + } + + int res = select(max_fd + 1, &rset, 0, 0, tvalptr); + if (res == 0) + { + return 0; //Timeout + } + if (res < 0) + { + // SelectSocket error. + return -1; + } + + //check which socket has some activity. + for (i=0; ih_addr, hp->h_length); + name.sin_port = htons(port); + + int r = connect(socketdescriptor, reinterpret_cast(&name), + sizeof(name)); + + return r; + } + + //----------------------------------------------------------------------------- + int GeneralSocket::GetPort(int sock) + { + struct sockaddr_in sockinfo; + memset(&sockinfo, 0, sizeof(sockinfo)); + #if defined(OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T) + socklen_t sizebuf = sizeof(sockinfo); + #else + int sizebuf = sizeof(sockinfo); + #endif + // FIXME: Setup configuration for VTK_HAVE_GETSOCKNAME_WITH_SOCKLEN_T so we can uncomment these lines + if(getsockname(sock, reinterpret_cast(&sockinfo), &sizebuf) != 0) + { + return 0; + } + return ntohs(sockinfo.sin_port); + } + + //----------------------------------------------------------------------------- + void GeneralSocket::CloseSocket(int socketdescriptor) + { + if (socketdescriptor < 0) + { + return; + } + igtlCloseSocketMacro(socketdescriptor); + } + + //----------------------------------------------------------------------------- + int GeneralSocket::Send(const void* data, int length) + { + if (!this->GetConnected()) + { + return 0; + } + if (length == 0) + { + // nothing to send. + return 1; + } + const char* buffer = reinterpret_cast(data); + int total = 0; + do + { + int flags; + #if defined(_WIN32) && !defined(__CYGWIN__) + flags = 0; + #else + // On unix boxes if the client disconnects and the server attempts + // to send data through the socket then the application crashes + // due to SIGPIPE signal. Disable the signal to prevent crash. + //#ifndef __sun + // flags = MSG_NOSIGNAL; + //#else + // // Signal is not present on SUN systems, the signal has + // // to be managed at application level. + // flags = 0; + //#endif + #if defined(MSG_NOSIGNAL) // For Linux > 2.2 + flags = MSG_NOSIGNAL; + #else + #if defined(SO_NOSIGPIPE) // Mac OS X + int set = 1; + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); + #endif + flags = 0; + #endif + #endif + int n = send(this->m_SocketDescriptor, buffer+total, length-total, flags); + if(n < 0) + { + // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Send failed."); + return 0; + } + total += n; + } while(total < length); + return 1; + } + + //----------------------------------------------------------------------------- + int GeneralSocket::Receive(void* data, int length, int readFully/*=1*/) + { + if (!this->GetConnected()) + { + return 0; + } + + char* buffer = reinterpret_cast(data); + int total = 0; + do + { + #if defined(_WIN32) && !defined(__CYGWIN__) + int trys = 0; + #endif + + int n = recv(this->m_SocketDescriptor, buffer+total, length-total, 0); + + #if defined(_WIN32) && !defined(__CYGWIN__) + if(n == 0) + { + // On long messages, Windows recv sometimes fails with WSAENOBUFS, but + // will work if you try again. + int error = WSAGetLastError(); + if ((error == WSAENOBUFS) && (trys++ < 1000)) + { + Sleep(1); + continue; + } + // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Receive failed."); + return 0; + } + else if (n < 0) + { + // TODO: Need to check if this means timeout. + return -1; + } + #else + if(n == 0) // Disconnected + { + // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Receive failed."); + return 0; + } + else if (n < 0) // Error (including time out) + { + // TODO: If it is time-out, errno == EAGAIN + return -1; + } + #endif + + total += n; + } while(readFully && total < length); + return total; + } + + int GeneralSocket::SetIPAddress(const char* ip) + { + if(strcpy(this->IPAddress,ip)) + { + return 0; + } + return -1; + } + + int GeneralSocket::SetPortNumber(igtl_uint16 port) + { + #if defined(_WIN32) && !defined(__CYGWIN__) + this->PortNum = port; + #else + this->PortNum = (in_port_t) port; + #endif + return 0; + } + + //----------------------------------------------------------------------------- + int GeneralSocket::SendUDP(const void* data, int length) + { + if (!this->GetConnected()) + { + return 0; + } + if (length == 0) + { + // nothing to send. + return 1; + } + int flags; + #if defined(_WIN32) && !defined(__CYGWIN__) + flags = 0; + #else + // On unix boxes if the client disconnects and the server attempts + // to send data through the socket then the application crashes + // due to SIGPIPE signal. Disable the signal to prevent crash. + //#ifndef __sun + // flags = MSG_NOSIGNAL; + //#else + // // Signal is not present on SUN systems, the signal has + // // to be managed at application level. + // flags = 0; + //#endif + #if defined(MSG_NOSIGNAL) // For Linux > 2.2 + flags = MSG_NOSIGNAL; + #else + #if defined(SO_NOSIGPIPE) // Mac OS X + int set = 1; + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); + #endif + flags = 0; + #endif + #endif + igtl_uint8 ttlArg = 1; // 1 is the default value , valid value from 0 to 255 + TTL_TYPE ttl = (TTL_TYPE)ttlArg; + if (setsockopt(this->m_SocketDescriptor, IPPROTO_IP, IP_MULTICAST_TTL, + (const char*)&ttl, sizeof ttl) < 0) { + return 0; + } + + struct sockaddr_in dest; + dest.sin_family = AF_INET; + + // store this IP address in dest: + dest.sin_addr.s_addr = inet_addr(this->IPAddress); + dest.sin_port = htons(this->PortNum); + + int n = sendto(this->m_SocketDescriptor, (char*)data, length, 0, (struct sockaddr*)&dest, sizeof dest); + if(n < 0) + { + // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Send failed."); + return 0; + } + return n; + } + + //----------------------------------------------------------------------------- + int GeneralSocket::ReceiveUDP(void* data, int length) + { + if (!this->GetConnected()) + { + return 0; + } + + char* buffer = reinterpret_cast(data); + #if defined(_WIN32) && !defined(__CYGWIN__) + int trys = 0; + #endif + struct sockaddr_storage from; + #if defined(OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T) + // store this IP address in dest: + socklen_t addressLen = sizeof(from); + #else + int addressLen = sizeof(from); + #endif + + //dest.sin_port = htons(this->PortNum); + #if defined(_WIN32) && !defined(__CYGWIN__) + int n = recvfrom(this->m_SocketDescriptor, buffer, length, 0, (struct sockaddr*)&from, &addressLen); + #else + int n = recvfrom(this->m_SocketDescriptor, (void*)buffer, length, 0, (struct sockaddr*)&from, &addressLen); + #endif + #if defined(_WIN32) && !defined(__CYGWIN__) + if(n == 0) + { + // On long messages, Windows recv sometimes fails with WSAENOBUFS, but + // will work if you try again. + int error = WSAGetLastError(); + if ((error == WSAENOBUFS) && (trys++ < 1000)) + { + Sleep(1); + } + // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Receive failed."); + return 0; + } + else if (n < 0) + { + // TODO: Need to check if this means timeout. + return -1; + } + #else + if(n == 0) // Disconnected + { + // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Receive failed."); + return 0; + } + else if (n < 0) // Error (including time out) + { + // TODO: If it is time-out, errno == EAGAIN + return -1; + } + #endif + return n; + } + + + //----------------------------------------------------------------------------- + int GeneralSocket::SetTimeout(int timeout) + { + if (SetReceiveTimeout(timeout) && SetSendTimeout(timeout)) + { + return 1; + } + else + { + return 0; + } + } + + + //----------------------------------------------------------------------------- + int GeneralSocket::SetReceiveTimeout(int timeout) + { + if (!this->GetConnected()) + { + return 0; + } + + #if defined(_WIN32) && !defined(__CYGWIN__) + this->m_ReceiveTimeout = timeout; + int len; + #else + this->m_ReceiveTimeout.tv_sec = timeout/1000; /* second */ + this->m_ReceiveTimeout.tv_usec = (timeout%1000) * 1000; /* microsecond */ + socklen_t len; + #endif + if ( timeout > 0 ) + { + getsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_OrigReceiveTimeout), &len); + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_ReceiveTimeout), sizeof(this->m_ReceiveTimeout)); + this->m_ReceiveTimeoutFlag = 1; + } + else if (this->m_ReceiveTimeoutFlag) + { + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_OrigReceiveTimeout), sizeof(this->m_OrigReceiveTimeout)); + this->m_ReceiveTimeoutFlag = 0; + } + + return timeout; + } + + + //----------------------------------------------------------------------------- + int GeneralSocket::SetSendTimeout(int timeout) + { + if (!this->GetConnected()) + { + return 0; + } + + #if defined(_WIN32) && !defined(__CYGWIN__) + this->m_SendTimeout = timeout; + int len; + #else + this->m_SendTimeout.tv_sec = timeout/1000; /* second */ + this->m_SendTimeout.tv_usec = (timeout%1000) * 1000; /* microsecond */ + socklen_t len; + #endif + if ( timeout > 0 ) + { + getsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_OrigSendTimeout), &len); + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_SendTimeout), sizeof(this->m_SendTimeout)); + this->m_SendTimeoutFlag = 1; + } + else if (this->m_SendTimeoutFlag) + { + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_OrigSendTimeout), sizeof(this->m_OrigSendTimeout)); + this->m_SendTimeoutFlag = 0; + } + + return timeout; + } + + + //----------------------------------------------------------------------------- + int GeneralSocket::SetReceiveBlocking(int sw) + { + if (!this->GetConnected()) + { + return 0; + } + + // If sw == 1, timeout is set to 0 (wait until it receives message) + #if defined(_WIN32) && !defined(__CYGWIN__) + if (sw==0) + { + this->m_ReceiveTimeout = 1; + } + else + { + this->m_ReceiveTimeout = 0; + } + int len; + #else + if (sw==0) + { + this->m_ReceiveTimeout.tv_sec = 0; /* second */ + this->m_ReceiveTimeout.tv_usec = 1; /* nanosecond */ + } + else + { + this->m_ReceiveTimeout.tv_sec = 0; /* second */ + this->m_ReceiveTimeout.tv_usec = 0; /* nanosecond */ + } + socklen_t len; + #endif + if (sw==0) + { + getsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_OrigReceiveTimeout), &len); + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_ReceiveTimeout), sizeof(this->m_ReceiveTimeout)); + this->m_ReceiveTimeoutFlag = 1; + } + else if (this->m_ReceiveTimeoutFlag) + { + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_OrigReceiveTimeout), sizeof(this->m_OrigReceiveTimeout)); + this->m_ReceiveTimeoutFlag = 0; + } + + return sw; + } + + + //----------------------------------------------------------------------------- + int GeneralSocket::SetSendBlocking(int sw) + { + if (!this->GetConnected()) + { + return 0; + } + + // If sw == 1, timeout is set to 0 (wait until it receives message) + #if defined(_WIN32) && !defined(__CYGWIN__) + if (sw==0) + { + this->m_SendTimeout = 1; + } + else + { + this->m_SendTimeout = 0; + } + int len; + #else + if (sw==0) + { + this->m_SendTimeout.tv_sec = 0; /* second */ + this->m_SendTimeout.tv_usec = 1; /* nanosecond */ + } + else + { + this->m_SendTimeout.tv_sec = 0; /* second */ + this->m_SendTimeout.tv_usec = 0; /* nanosecond */ + } + socklen_t len; + #endif + if (sw==0) + { + getsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_OrigSendTimeout), &len); + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_SendTimeout), sizeof(this->m_SendTimeout)); + this->m_SendTimeoutFlag = 1; + } + else if (this->m_SendTimeoutFlag) + { + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_OrigSendTimeout), sizeof(this->m_OrigSendTimeout)); + this->m_SendTimeoutFlag = 0; + } + + return sw; + } + + + //----------------------------------------------------------------------------- + int GeneralSocket::GetSocketAddressAndPort(std::string& address, int& port) + { + struct sockaddr_in sockinfo; + + memset(&sockinfo, 0, sizeof(sockinfo)); + + #if defined(OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T) + socklen_t sizebuf = sizeof(sockinfo); + #else + int sizebuf = sizeof(sockinfo); + #endif + + if( getsockname(this->m_SocketDescriptor, reinterpret_cast(&sockinfo), &sizebuf) != 0) + { + return -1; + } + const char* a = inet_ntoa(sockinfo.sin_addr); + if ( a == NULL ) + { + return -1; + } + address = a; + port = ntohs(sockinfo.sin_port); + + return 0; + } + + + //----------------------------------------------------------------------------- + int GeneralSocket::Skip(int length, int skipFully/*=1*/) + { + if (length == 0) + { + return 0; + } + + unsigned char dummy[256]; + int block = 256; + int n = 0; + int remain = length; + + do + { + if (remain < block) + { + block = remain; + } + + n = this->Receive(dummy, block, skipFully); + if (!skipFully && n <= 0) + { + break; + } + remain -= n; + } + while (remain > 0 || (skipFully && n < block)); + + return (length - remain); + + } + + //----------------------------------------------------------------------------- + void GeneralSocket::PrintSelf(std::ostream& os) const + { + this->Superclass::PrintSelf(os); + } + + +} // end of igtl namespace diff --git a/openigtlink/repo/Source/igtlGeneralSocket.h b/openigtlink/repo/Source/igtlGeneralSocket.h new file mode 100755 index 0000000..cc35ad0 --- /dev/null +++ b/openigtlink/repo/Source/igtlGeneralSocket.h @@ -0,0 +1,224 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: igtlSocket.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + + =========================================================================*/ + +/** \class Socket + * \brief BSD socket encapsulation. + * + * This abstract class encapsulates a BSD socket. + * It provides an API for basic socket operations. + * + * This class was largely based on the igtlSocket class + * from the Visualization Toolkit VTK. + * + */ + +#ifndef __igtlGeneralSocket_h +#define __igtlGeneralSocket_h + +#include "igtlObject.h" +#include "igtlObjectFactory.h" +#include "igtlMacro.h" +#include "igtlWin32Header.h" +#include "igtl_types.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) +#else +#include +#endif + +#define IP4AddressStrLen 16 +#define IP6AddressStrLen 46 + +#define RTP_HEADER_LENGTH 12 +#define RTP_PAYLOAD_LENGTH 8900 //typical Ethernet MTU is 1500 bytes, minus 12 byte RTP and 32 byte IP address +#define MINIMUM_PACKET_LENGTH RTP_PAYLOAD_LENGTH/3 + +namespace igtl +{ + + class SocketCollection; + + /// class IGTL_EXPORT Socket + class IGTLCommon_EXPORT GeneralSocket : public Object + { + public: + igtlTypeMacro(igtl::GeneralSocket, igtl::Object) + igtlNewMacro(igtl::GeneralSocket); + + public: + /// Check is the socket is alive. + int GetConnected() { return (this->m_SocketDescriptor >=0); } + + /// Close the socket. + void CloseSocket() { + this->CloseSocket(this->m_SocketDescriptor); + this->m_SocketDescriptor = -1; + } + /// Get socket address + int GetSocketAddressAndPort(std::string& address, int & port); + + /// Skip reading data from the socket. + /// The Skip() call has been newly introduced to the igtlSocket, + /// after the class is imported from VTK, thus the call is + /// not available in vtkSocket class. + int Skip(int length, int skipFully=1); + + int SetIPAddress(const char* ip); + + int SetPortNumber(igtl_uint16 port); + + /// These methods send data over the socket. + /// Returns 1 on success, 0 on error and raises vtkCommand::ErrorEvent. + /// SIGPIPE or other signal may be raised on systems (e.g., Sun Solaris) where + /// MSG_NOSIGNAL flag is not supported for the socket send method. + int Send(const void* data, int length); + + /// Receive data from the socket. + /// This call blocks until some data is read from the socket, unless timeout is set + /// by SetTimeout() or SetReceiveTimeout(). + /// When the readFully flag is set, this call will block until all the requested data is + /// read from the socket. The readFully flag will be ignored if the timeout is active. + /// 0 on error, -1 on timeout, else number of bytes read is returned. + int Receive(void* data, int length, int readFully=1); + + /// These methods send UDP Diagram data over the socket. + /// Returns 1 on success, 0 on error + /// SIGPIPE or other signal may be raised on systems (e.g., Sun Solaris) where + /// MSG_NOSIGNAL flag is not supported for the socket send method. + int SendUDP(const void* data, int length); + + /// Receive UDP Diagram data from the socket. + /// This function is able to receive the data at a group Ip (broadcast IP) by setting the IP Address 'SetIPAddress()' + /// This call blocks until some data is read from the socket, unless timeout is set + /// by SetTimeout() or SetReceiveTimeout(). + int ReceiveUDP(void* data, int length); + + + /// Set sending/receiving timeout for the existing socket in millisecond. + /// This function should be called after opening the socket. + int SetTimeout(int timeout); + + /// Set reciving timeout for the existing socket in millisecond. + /// This function should be called after opening the socket. + int SetReceiveTimeout(int timeout); + + /// Set sending timeout for the existing socket in millisecond. + /// This function should be called after opening the socket. + int SetSendTimeout(int timeout); + + /// Set (psuedo) non-blocking mode for recv(). When sw=1, the time out is set to + /// minimum value (1 microsecond in UNIX, 1 millisecond in Windows) for receiving. + int SetReceiveBlocking(int sw); + + /// Set (psuedo) non-blocking mode for recv(). When sw=1, the time out is set to + /// minimum value (1 microsecond in UNIX, 1 millisecond in Windows) for sending. + int SetSendBlocking(int sw); + + protected: + GeneralSocket(); + ~GeneralSocket(); + + void PrintSelf(std::ostream& os) const override; + + int m_SocketDescriptor; + igtlGetMacro(SocketDescriptor, int); + + //BTX + friend class vtkSocketCollection; + //ETX + + /// Creates an endpoint for communication and returns the descriptor. + /// -1 indicates error. + int CreateSocket(); + + /// Creates an endpoint for communication and returns the descriptor. + /// -1 indicates error. + int CreateUDPServerSocket(); + + /// Creates an endpoint for communication and returns the descriptor. + /// -1 indicates error. + int CreateUDPClientSocket(); + + /// Close the socket. + void CloseSocket(int socketdescriptor); + + /// Binds socket to a particular port. + /// Returns 0 on success other -1 is returned. + int BindSocket(int socketdescriptor, int port); + + /// Selects a socket ie. waits for it to change status. + /// Returns 1 on success; 0 on timeout; -1 on error. msec=0 implies + /// no timeout. + int SelectSocket(int socketdescriptor, unsigned long msec); + + /// Accept a connection on a socket. Returns -1 on error. Otherwise + /// the descriptor of the accepted socket. + int Accept(int socketdescriptor); + + /// Listen for connections on a socket. Returns 0 on success. -1 on error. + int Listen(int socketdescriptor); + + /// Connect to a server socket. Returns 0 on success, -1 on error. + int Connect(int socketdescriptor, const char* hostname, int port); + + /// Returns the port to which the socket is connected. + /// 0 on error. + int GetPort(int socketdescriptor); + + /// Selects set of sockets. Returns 0 on timeout, -1 on error. + /// 1 on success. Selected socket's index is returned thru + /// selected_index + static int SelectSockets(const int* sockets_to_select, int size, + unsigned long msec, int* selected_index); + + + private: + GeneralSocket(const GeneralSocket&); // Not implemented. + void operator=(const GeneralSocket&); // Not implemented. + +#if defined(_WIN32) && !defined(__CYGWIN__) + DWORD m_SendTimeout; + DWORD m_ReceiveTimeout; + DWORD m_OrigSendTimeout; + DWORD m_OrigReceiveTimeout; +#else + struct timeval m_SendTimeout; + struct timeval m_ReceiveTimeout; + struct timeval m_OrigSendTimeout; + struct timeval m_OrigReceiveTimeout; +#endif + int m_SendTimeoutFlag; + int m_ReceiveTimeoutFlag; + + short PortNum; + char IPAddress[IP4AddressStrLen]; + }; + +} + +#endif diff --git a/openigtlink/repo/Source/igtlImageMessage.cxx b/openigtlink/repo/Source/igtlImageMessage.cxx new file mode 100644 index 0000000..3564b22 --- /dev/null +++ b/openigtlink/repo/Source/igtlImageMessage.cxx @@ -0,0 +1,489 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlImageMessage.h" + +#include "igtl_header.h" +#include "igtl_image.h" + +namespace igtl { + + +ImageMessage::ImageMessage(): + MessageBase() +{ + for (int i = 0; i < 3; i ++) + { + dimensions[i] = 0; + spacing[i] = 0.0; + subDimensions[i] = 0; + subOffset[i] = 0; + } + for (int i = 0; i < 4; i ++) + { + for (int j = 0; j < 4; j ++) + { + matrix[i][j] = (i == j ? 1.0 : 0.0); + } + } + + endian = ENDIAN_BIG; + coordinate = COORDINATE_RAS; + scalarType = TYPE_UINT8; + m_ImageHeader = NULL; + m_Image = NULL; + numComponents = 1; + + m_SendMessageType = "IMAGE"; + + ScalarSizeTable[0] = 0; + ScalarSizeTable[1] = 0; + ScalarSizeTable[2] = sizeof(igtlInt8); // TYPE_INT8 + ScalarSizeTable[3] = sizeof(igtlUint8); // TYPE_UINT8 + ScalarSizeTable[4] = sizeof(igtlInt16); // TYPE_INT16 + ScalarSizeTable[5] = sizeof(igtlUint16); // TYPE_UINT16 + ScalarSizeTable[6] = sizeof(igtlInt32); // TYPE_INT32 + ScalarSizeTable[7] = sizeof(igtlUint32); // TYPE_UINT32 + ScalarSizeTable[8] = 0; // not defined + ScalarSizeTable[9] = 0; // not defined + ScalarSizeTable[10]= sizeof(igtlFloat32); // TYPE_FLOAT32 + ScalarSizeTable[11]= sizeof(igtlFloat64); // TYPE_FLOAT64 +} + +ImageMessage::~ImageMessage() +{ +} + +void ImageMessage::SetDimensions(int s[3]) +{ + m_IsBodyPacked = false; + dimensions[0] = s[0]; + dimensions[1] = s[1]; + dimensions[2] = s[2]; + + // initialize sub-volume + subDimensions[0] = dimensions[0]; + subDimensions[1] = dimensions[1]; + subDimensions[2] = dimensions[2]; + subOffset[0] = 0; + subOffset[1] = 0; + subOffset[2] = 0; +} + +void ImageMessage::SetDimensions(int i, int j, int k) +{ + m_IsBodyPacked = false; + dimensions[0] = i; + dimensions[1] = j; + dimensions[2] = k; + + // initialize sub-volume + subDimensions[0] = dimensions[0]; + subDimensions[1] = dimensions[1]; + subDimensions[2] = dimensions[2]; + subOffset[0] = 0; + subOffset[1] = 0; + subOffset[2] = 0; +} + +void ImageMessage::GetDimensions(int s[3]) +{ + s[0] = dimensions[0]; + s[1] = dimensions[1]; + s[2] = dimensions[2]; +} + +void ImageMessage::GetDimensions(int &i, int &j, int &k) +{ + i = dimensions[0]; + j = dimensions[1]; + k = dimensions[2]; +} + +int ImageMessage::SetSubVolume(int dim[3], int off[3]) +{ + // make sure that sub-volume fits in the dimensions + if (off[0] + dim[0] <= dimensions[0] && + off[1] + dim[1] <= dimensions[1] && + off[2] + dim[2] <= dimensions[2]) + { + m_IsBodyPacked = false; + subDimensions[0] = dim[0]; + subDimensions[1] = dim[1]; + subDimensions[2] = dim[2]; + subOffset[0] = off[0]; + subOffset[1] = off[1]; + subOffset[2] = off[2]; + return 1; + } + else + { + return 0; + } +} + +int ImageMessage::SetSubVolume(int dimi, int dimj, int dimk, int offi, int offj, int offk) +{ + // make sure that sub-volume fits in the dimensions + if (offi + dimi <= dimensions[0] && + offj + dimj <= dimensions[1] && + offk + dimk <= dimensions[2]) + { + m_IsBodyPacked = false; + subDimensions[0] = dimi; + subDimensions[1] = dimj; + subDimensions[2] = dimk; + subOffset[0] = offi; + subOffset[1] = offj; + subOffset[2] = offk; + return 1; + } + else + { + return 0; + } +} + +void ImageMessage::GetSubVolume(int dim[3], int off[3]) +{ + dim[0] = subDimensions[0]; + dim[1] = subDimensions[1]; + dim[2] = subDimensions[2]; + off[0] = subOffset[0]; + off[1] = subOffset[1]; + off[2] = subOffset[2]; +} + +void ImageMessage::GetSubVolume(int &dimi, int &dimj, int &dimk, + int &offi, int &offj, int &offk) +{ + dimi = subDimensions[0]; + dimj = subDimensions[1]; + dimk = subDimensions[2]; + offi = subOffset[0]; + offj = subOffset[1]; + offk = subOffset[2]; +} + + +void ImageMessage::SetSpacing(float s[3]) +{ + m_IsBodyPacked = false; + spacing[0] = s[0]; + spacing[1] = s[1]; + spacing[2] = s[2]; +} + +void ImageMessage::SetSpacing(float si, float sj, float sk) +{ + m_IsBodyPacked = false; + spacing[0] = si; + spacing[1] = sj; + spacing[2] = sk; +} + +void ImageMessage::GetSpacing(float s[3]) +{ + s[0] = spacing[0]; + s[1] = spacing[1]; + s[2] = spacing[2]; +} + +void ImageMessage::GetSpacing(float &si, float &sj, float &sk) +{ + si = spacing[0]; + sj = spacing[1]; + sk = spacing[2]; +} + +void ImageMessage::SetOrigin(float p[3]) +{ + m_IsBodyPacked = false; + matrix[0][3] = p[0]; + matrix[1][3] = p[1]; + matrix[2][3] = p[2]; +} + +void ImageMessage::SetOrigin(float px, float py, float pz) +{ + m_IsBodyPacked = false; + matrix[0][3] = px; + matrix[1][3] = py; + matrix[2][3] = pz; +} + +void ImageMessage::GetOrigin(float p[3]) +{ + p[0] = matrix[0][3]; + p[1] = matrix[1][3]; + p[2] = matrix[2][3]; +} + +void ImageMessage::GetOrigin(float &px, float &py, float &pz) +{ + px = matrix[0][3]; + py = matrix[1][3]; + pz = matrix[2][3]; +} + +void ImageMessage::SetNormals(float o[3][3]) +{ + m_IsBodyPacked = false; + matrix[0][0] = o[0][0]; + matrix[0][1] = o[0][1]; + matrix[0][2] = o[0][2]; + matrix[1][0] = o[1][0]; + matrix[1][1] = o[1][1]; + matrix[1][2] = o[1][2]; + matrix[2][0] = o[2][0]; + matrix[2][1] = o[2][1]; + matrix[2][2] = o[2][2]; +} + +void ImageMessage::SetNormals(float t[3], float s[3], float n[3]) +{ + m_IsBodyPacked = false; + matrix[0][0] = t[0]; + matrix[1][0] = t[1]; + matrix[2][0] = t[2]; + matrix[0][1] = s[0]; + matrix[1][1] = s[1]; + matrix[2][1] = s[2]; + matrix[0][2] = n[0]; + matrix[1][2] = n[1]; + matrix[2][2] = n[2]; +} + +void ImageMessage::GetNormals(float o[3][3]) +{ + o[0][0] = matrix[0][0]; + o[0][1] = matrix[0][1]; + o[0][2] = matrix[0][2]; + o[1][0] = matrix[1][0]; + o[1][1] = matrix[1][1]; + o[1][2] = matrix[1][2]; + o[2][0] = matrix[2][0]; + o[2][1] = matrix[2][1]; + o[2][2] = matrix[2][2]; +} + +void ImageMessage::GetNormals(float t[3], float s[3], float n[3]) +{ + t[0] = matrix[0][0]; + t[1] = matrix[1][0]; + t[2] = matrix[2][0]; + s[0] = matrix[0][1]; + s[1] = matrix[1][1]; + s[2] = matrix[2][1]; + n[0] = matrix[0][2]; + n[1] = matrix[1][2]; + n[2] = matrix[2][2]; +} + +void ImageMessage::SetMatrix(Matrix4x4& mat) +{ + m_IsBodyPacked = false; + matrix[0][0] = mat[0][0]; + matrix[1][0] = mat[1][0]; + matrix[2][0] = mat[2][0]; + matrix[3][0] = mat[3][0]; + + matrix[0][1] = mat[0][1]; + matrix[1][1] = mat[1][1]; + matrix[2][1] = mat[2][1]; + matrix[3][1] = mat[3][1]; + + matrix[0][2] = mat[0][2]; + matrix[1][2] = mat[1][2]; + matrix[2][2] = mat[2][2]; + matrix[3][2] = mat[3][2]; + + matrix[0][3] = mat[0][3]; + matrix[1][3] = mat[1][3]; + matrix[2][3] = mat[2][3]; + matrix[3][3] = mat[3][3]; +} + +void ImageMessage::GetMatrix(Matrix4x4& mat) +{ + mat[0][0] = matrix[0][0]; + mat[1][0] = matrix[1][0]; + mat[2][0] = matrix[2][0]; + mat[3][0] = matrix[3][0]; + + mat[0][1] = matrix[0][1]; + mat[1][1] = matrix[1][1]; + mat[2][1] = matrix[2][1]; + mat[3][1] = matrix[3][1]; + + mat[0][2] = matrix[0][2]; + mat[1][2] = matrix[1][2]; + mat[2][2] = matrix[2][2]; + mat[3][2] = matrix[3][2]; + + mat[0][3] = matrix[0][3]; + mat[1][3] = matrix[1][3]; + mat[2][3] = matrix[2][3]; + mat[3][3] = matrix[3][3]; +} + +void ImageMessage::AllocateScalars() +{ + // Memory area to store image scalar is allocated with + // message and image header, by using AllocatePack() implemented + // in the parent class. + AllocateBuffer(); +#if OpenIGTLink_HEADER_VERSION >= 2 + m_ImageHeader = m_Content; + m_Image = &m_ImageHeader[IGTL_IMAGE_HEADER_SIZE]; +#else + m_ImageHeader = m_Body; + m_Image = &m_ImageHeader[IGTL_IMAGE_HEADER_SIZE]; +#endif +} + +void* ImageMessage::GetScalarPointer() +{ + return (void*)m_Image; +} + +igtlUint64 ImageMessage::CalculateContentBufferSize() +{ + return GetSubVolumeImageSize() + IGTL_IMAGE_HEADER_SIZE; +} + +int ImageMessage::PackContent() +{ + AllocateScalars(); + + igtl_image_header* image_header = (igtl_image_header*)m_ImageHeader; + + image_header->header_version = IGTL_IMAGE_HEADER_VERSION; + image_header->num_components = this->numComponents; + image_header->scalar_type = this->scalarType; + image_header->endian = this->endian; + image_header->coord = this->coordinate; + image_header->size[0] = this->dimensions[0]; + image_header->size[1] = this->dimensions[1]; + image_header->size[2] = this->dimensions[2]; + image_header->subvol_offset[0] = this->subOffset[0]; + image_header->subvol_offset[1] = this->subOffset[1]; + image_header->subvol_offset[2] = this->subOffset[2]; + image_header->subvol_size[0] = this->subDimensions[0]; + image_header->subvol_size[1] = this->subDimensions[1]; + image_header->subvol_size[2] = this->subDimensions[2]; + + float origin[3]; + float norm_i[3]; + float norm_j[3]; + float norm_k[3]; + + for (int i = 0; i < 3; i ++) + { + norm_i[i] = matrix[i][0]; + norm_j[i] = matrix[i][1]; + norm_k[i] = matrix[i][2]; + origin[i] = matrix[i][3]; + } + + igtl_image_set_matrix(this->spacing, origin, + norm_i, norm_j, norm_k, + image_header); + + igtl_image_convert_byte_order(image_header); + + return 1; + +} + + +int ImageMessage::UnpackContent() +{ +#if OpenIGTLink_HEADER_VERSION >= 2 + m_ImageHeader = m_Content; +#elif OpenIGTLink_PROTOCOL_VERSION <=2 + m_ImageHeader = m_Body; +#endif + igtl_image_header* image_header = (igtl_image_header*)m_ImageHeader; + igtl_image_convert_byte_order(image_header); + + if (image_header->header_version == IGTL_IMAGE_HEADER_VERSION) + { + // Image format version 1 + this->scalarType = image_header->scalar_type; + this->numComponents = image_header->num_components; + this->endian = image_header->endian; + this->coordinate = image_header->coord; + this->dimensions[0] = image_header->size[0]; + this->dimensions[1] = image_header->size[1]; + this->dimensions[2] = image_header->size[2]; + this->subOffset[0] = image_header->subvol_offset[0]; + this->subOffset[1] = image_header->subvol_offset[1]; + this->subOffset[2] = image_header->subvol_offset[2]; + this->subDimensions[0] = image_header->subvol_size[0]; + this->subDimensions[1] = image_header->subvol_size[1]; + this->subDimensions[2] = image_header->subvol_size[2]; + + // Set image orientation + float rspacing[3]; + float origin[3]; + float norm_i[3]; + float norm_j[3]; + float norm_k[3]; + + igtl_image_get_matrix(rspacing, origin, + norm_i, norm_j, norm_k, + image_header); + + for (int i = 0; i < 3; i ++) + { + this->spacing[i] = rspacing[i]; + matrix[i][0] = norm_i[i]; + matrix[i][1] = norm_j[i]; + matrix[i][2] = norm_k[i]; + matrix[i][3] = origin[i]; + } + + matrix[3][0] = 0.0; + matrix[3][1] = 0.0; + matrix[3][2] = 0.0; + matrix[3][3] = 1.0; + + m_Image = &m_ImageHeader[IGTL_IMAGE_HEADER_SIZE]; + + return 1; + } + else + { + // Incompatible version. + return 0; + } +} + + +void ImageMessage::SetNumComponents(int num) +{ + if (num > 0 && num < 255) + { + numComponents = num; + } +} + +int ImageMessage::GetNumComponents() +{ + return numComponents; +} + + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlImageMessage.h b/openigtlink/repo/Source/igtlImageMessage.h new file mode 100644 index 0000000..842b09c --- /dev/null +++ b/openigtlink/repo/Source/igtlImageMessage.h @@ -0,0 +1,319 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlImageMessage_h +#define __igtlImageMessage_h + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtl_header.h" + +namespace igtl +{ + +// A class for the GET_IMAGE message type. +class IGTLCommon_EXPORT GetImageMessage: public HeaderOnlyMessageBase +{ +public: + igtlTypeMacro(igtl::GetImageMessage, igtl::HeaderOnlyMessageBase); + igtlNewMacro(igtl::GetImageMessage); + +protected: + + GetImageMessage() : HeaderOnlyMessageBase() { this->m_SendMessageType = "GET_IMAGE";}; + ~GetImageMessage() {}; + +}; + +// A class for the STP_IMAGE message type. +class IGTLCommon_EXPORT StopImageMessage: public HeaderOnlyMessageBase +{ +public: + igtlTypeMacro(igtl::StopImageMessage, igtl::HeaderOnlyMessageBase); + igtlNewMacro(igtl::StopImageMessage); + +protected: + + StopImageMessage() : HeaderOnlyMessageBase() { this->m_SendMessageType = "STP_IMAGE";}; + ~StopImageMessage() {}; + +}; + + +/// A class for the IMAGE message type. +/// The IMAGE format supports 2D or 3D images with metric information including +/// image matrix size, voxel size, coordinate system type, position, and orientation. +/// The body section of the IMAGE data consists of two parts: image header to transfer +/// the metric information and image body to transfer the array of pixel or voxel values. +/// The data type of pixel or voxel can be either scalar or vector, and numerical values +/// can be 8-, 16-, 32-bit integer, or 32- or 64-bit floating point. The pixel values +/// can be either big-endian or little-endian, since the sender software can specify +/// the byte order in the image header. The format also supports "partial image transfer", +/// in which a region of the image is transferred instead of the whole image. This mechanism +/// is suitable for real-time applications, in which images are updated region-by-region. +/// The sub-volume must be box-shaped and defined by 6 parameters consisting of the indices +/// for the corner voxel of the sub-volume and matrix size of the sub-volume. +class IGTLCommon_EXPORT ImageMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::ImageMessage, igtl::MessageBase) + igtlNewMacro(igtl::ImageMessage); + +public: + + /// Coordinate system. Either left-posterior-superior (LPS) or right-anterior-superior (RAS). + enum { + COORDINATE_RAS=1, + COORDINATE_LPS=2 + }; + + /// Endian used in the bite array for the image data. + enum { + ENDIAN_BIG=1, + ENDIAN_LITTLE=2 + }; + + /// Pixel data type either scalar or vector. + enum { + DTYPE_SCALAR = 1, + DTYPE_VECTOR = 3 + }; + + /// Pixel data type. + enum { + TYPE_INT8 = 2, + TYPE_UINT8 = 3, + TYPE_INT16 = 4, + TYPE_UINT16 = 5, + TYPE_INT32 = 6, + TYPE_UINT32 = 7, + TYPE_FLOAT32 = 10, + TYPE_FLOAT64 = 11 + }; + + +public: + + /// Sets image dimensions by an array of the numbers of pixels in i, j and k directions. + /// SetDimensions() should be called prior to SetSubVolume(), since SetDimensions() + /// sets subvolume parameters automatically assuming that subvolume = entire volume. + void SetDimensions(int s[3]); + + /// Sets image dimensions by the numbers of pixels in i, j and k directions. + /// SetDimensions() should be called prior to SetSubVolume(), since SetDimensions() + /// sets subvolume parameters automatically assuming that subvolume = entire volume. + void SetDimensions(int i, int j, int k); + + /// Gets image dimensions as an array of the numbers of pixels in i, j and k directions. + void GetDimensions(int s[3]); + + /// Gets image dimensions as the numbers of pixels in i, j and k directions. + void GetDimensions(int &i, int &j, int &k); + + /// Sets sub-volume dimensions and offset by arrays of the dimensions and the offset. + /// SetSubVolume() should be called after calling SetDiemensions(), since SetDimensions() + /// reset the subvolume parameters automatically. Returns non-zero value if the subvolume + /// is successfully specified. Returns zero, if invalid subvolume is specified. + int SetSubVolume(int dim[3], int off[3]); + + /// Sets sub-volume dimensions and offset by the dimensions and the offset in i, j and k + /// directions. SetSubVolume() should be called after calling SetDiemensions(), + /// since SetDimensions() reset the subvolume parameters automatically. + /// Returns non-zero value if the subvolume is successfully specified. + /// Returns zero, if invalid subvolume is specified. + int SetSubVolume(int dimi, int dimj, int dimk, int offi, int offj, int offk); + + /// Gets sub-volume dimensions and offset using arrays of the dimensions and the offset. + void GetSubVolume(int dim[3], int off[3]); + + /// Gets sub-volume dimensions and offset by the dimensions and the offset in i, j and k + /// directions. + void GetSubVolume(int &dimi, int &dimj, int &dimk, int &offi, int &offj, int &offk); + + /// Sets spacings by an array of spacing values in i, j and k directions. + void SetSpacing(float s[3]); + + /// Sets spacings by spacing values in i, j and k directions. + void SetSpacing(float si, float sj, float sk); + + /// Gets spacings using an array of spacing values in i, j and k directions. + void GetSpacing(float s[3]); + + /// Gets spacings using spacing values in i, j and k directions. + void GetSpacing(float &si, float &sj, float &sk); + + /// Sets the coordinates of the origin by an array of positions along the first (R or L), + /// second (A or P) and the third (S) axes. + void SetOrigin(float p[3]); + + /// Sets the coordinates of the origin by positions along the first (R or L), second (A or P) + /// and the third (S) axes. + void SetOrigin(float px, float py, float pz); + + /// Gets the coordinates of the origin using an array of positions along the first (R or L), + /// second (A or P) and the third (S) axes. + void GetOrigin(float p[3]); + + /// Gets the coordinates of the origin by positions along the first (R or L), second (A or P) + /// and the third (S) axes. + void GetOrigin(float &px, float &py, float &pz); + + /// Sets the orientation of the image by an array of the normal vectors for the i, j + /// and k indices. + void SetNormals(float o[3][3]); + + /// Sets the orientation of the image by the normal vectors for the i, j and k indeces. + void SetNormals(float t[3], float s[3], float n[3]); + + /// Gets the orientation of the image using an array of the normal vectors for the i, j + /// and k indices. + void GetNormals(float o[3][3]); + + /// Gets the orientation of the image using the normal vectors for the i, j and k indeces. + void GetNormals(float t[3], float s[3], float n[3]); + + /// Sets the number of components for each voxel. + void SetNumComponents(int num); + + /// Gets the number of components for each voxel. + int GetNumComponents(); + + /// Sets the origin/orientation matrix. + void SetMatrix(Matrix4x4& mat); + + /// Gets the origin/orientation matrix. + void GetMatrix(Matrix4x4& mat); + + /// Sets the image scalar type. + void SetScalarType(int t) { scalarType = t; }; + + /// Sets the image scalar type to 8-bit integer. + void SetScalarTypeToInt8() { scalarType = TYPE_INT8; }; + + /// Sets the image scalar type to unsigned 8-bit integer. + void SetScalarTypeToUint8() { scalarType = TYPE_UINT8; }; + + /// Sets the image scalar type to 16-bit integer. + void SetScalarTypeToInt16() { scalarType = TYPE_INT16; }; + + /// Sets the image scalar type to unsigned 16-bit integer. + void SetScalarTypeToUint16() { scalarType = TYPE_UINT16; }; + + /// Sets the image scalar type to 32-bit integer. + void SetScalarTypeToInt32() { scalarType = TYPE_INT32; }; + + /// Sets the image scalar type to unsigned 32-bit integer. + void SetScalarTypeToUint32() { scalarType = TYPE_UINT32; }; + + /// Gets the image scalar type. + int GetScalarType() { return scalarType; }; + + /// Gets the size of the scalar type used in the current image data. + /// (e.g. 1 byte for 8-bit integer) + int GetScalarSize() { return ScalarSizeTable[scalarType]; }; + + /// Gets the size of the specified scalar type. (e.g. 1 byte for 8-bit integer) + int GetScalarSize(int type) { return ScalarSizeTable[type]; }; + + /// Sets the Endianess of the image scalars. (default is ENDIAN_BIG) + void SetEndian(int e) { endian = e; }; + + /// Gets the Endianess of the image scalars. + int GetEndian() { return endian; }; + + /// Gets the size (length) of the byte array for the image data. + /// The size is defined by dimensions[0]*dimensions[1]*dimensions[2]*scalarSize*numComponents. + /// TODO: Should returned value be 64-bit integer? + int GetImageSize() + { + return dimensions[0]*dimensions[1]*dimensions[2]*GetScalarSize()*numComponents; + }; + + /// Returns coordinate system (COORDINATE_RAS or COORDINATE_LPS) + int GetCoordinateSystem() { return coordinate;}; + + /// Sets coordinate system (COORDINATE_RAS or COORDINATE_LPS) + void SetCoordinateSystem(int c) {coordinate = c;}; + + + /// Gets the size (length) of the byte array for the subvolume image data. + /// The size is defined by subDimensions[0]*subDimensions[1]*subDimensions[2]* + /// scalarSize*numComponents. + igtlUint64 GetSubVolumeImageSize() + { + return subDimensions[0]*subDimensions[1]*subDimensions[2]*GetScalarSize()*numComponents; + }; + + /// Allocates a memory area for the scalar data based on the dimensions of the subvolume, + /// the number of components, and the scalar type. + void AllocateScalars(); + + /// Gets a pointer to the scalar data. + void* GetScalarPointer(); + +protected: + ImageMessage(); + ~ImageMessage() override; + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// A vector containing the numbers of voxels in i, j and k directions. + int dimensions[3]; + + /// A vector containing the spacings of the voxels in i, j and k directions. + float spacing[3]; + + /// A vector containing the numbers of voxels of the subvolume in i, j and k directions. + int subDimensions[3]; + + /// A vector containing the offset (number of voxels) of the first voxel of + /// the subvolume from the first voxel of the original image. + int subOffset[3]; + + /// A matrix representing the origin and the orientation of the image. + /// The matrix is set to identity by default + Matrix4x4 matrix; + + /// A variable for the Endian of the scalar values in the image. + int endian; + + /// A variable for the number of components. + int numComponents; + + /// A variable for the scalar type of the voxels. + int scalarType; + + /// A variable for the scalar type of the voxels. + int coordinate; + + /// A pointer to the serialized image header. + unsigned char* m_ImageHeader; + + /// A pointer to the serialized image data. + unsigned char* m_Image; + + /// A table to look up the size of a given scalar type. + int ScalarSizeTable[12]; +}; + + +} // namespace igtl + +#endif // _igtlImageMessage_h \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlImageMessage2.cxx b/openigtlink/repo/Source/igtlImageMessage2.cxx new file mode 100644 index 0000000..5bfed38 --- /dev/null +++ b/openigtlink/repo/Source/igtlImageMessage2.cxx @@ -0,0 +1,741 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlImageMessage2.h" + +#include + +#include "igtl_header.h" +#include "igtl_image.h" + +namespace igtl { + + +ImageMessage2::ImageMessage2(): + MessageBase() +{ + for (int i = 0; i < 3; i ++) + { + dimensions[i] = 0; + spacing[i] = 0.0; + subDimensions[i] = 0; + subOffset[i] = 0; + } + for (int i = 0; i < 4; i ++) + { + for (int j = 0; j < 4; j ++) + { + matrix[i][j] = (i == j ? 1.0 : 0.0); + } + } + + endian = ENDIAN_BIG; + coordinate = COORDINATE_RAS; + scalarType = TYPE_UINT8; + m_ImageHeader = NULL; + m_Image = NULL; + numComponents = 1; + + m_SendMessageType = "IMAGE"; + + ScalarSizeTable[0] = 0; + ScalarSizeTable[1] = 0; + ScalarSizeTable[2] = sizeof(igtlInt8); // TYPE_INT8 + ScalarSizeTable[3] = sizeof(igtlUint8); // TYPE_UINT8 + ScalarSizeTable[4] = sizeof(igtlInt16); // TYPE_INT16 + ScalarSizeTable[5] = sizeof(igtlUint16); // TYPE_UINT16 + ScalarSizeTable[6] = sizeof(igtlInt32); // TYPE_INT32 + ScalarSizeTable[7] = sizeof(igtlUint32); // TYPE_UINT32 + ScalarSizeTable[8] = 0; // not defined + ScalarSizeTable[9] = 0; // not defined + ScalarSizeTable[10]= sizeof(igtlFloat32); // TYPE_FLOAT32 + ScalarSizeTable[11]= sizeof(igtlFloat64); // TYPE_FLOAT64 + +#ifdef FRAGMENTED_PACK + this->m_Header = new unsigned char [IGTL_HEADER_SIZE]; + this->m_Content = NULL; + + this->m_SelfAllocatedImageHeader = 0; + this->m_ImageSize = 0; + this->m_SelfAllocatedImage = 0; + + this->m_SinglePack = NULL; + this->m_SinglePackSize = 0; + + // Size of the pack. Only header can be used after initialization + this->m_MessageSize = IGTL_HEADER_SIZE; +#endif + +} + + +ImageMessage2::~ImageMessage2() +{ +#ifdef FRAGMENTED_PACK + //if (this->m_Header) + // { + // delete [] this->m_Header; + // } + if (this->m_ImageHeader && this->m_ImageHeader!= this->m_Content && this->m_SelfAllocatedImageHeader) + { + delete [] this->m_ImageHeader; + } + if (this->m_Image && this->m_SelfAllocatedImage) + { + delete [] this->m_Image; + this->m_SelfAllocatedImage = 0; + } +#endif +} + +void ImageMessage2::SetDimensions(int s[3]) +{ + m_IsBodyPacked = false; + dimensions[0] = s[0]; + dimensions[1] = s[1]; + dimensions[2] = s[2]; + + // initialize sub-volume + subDimensions[0] = dimensions[0]; + subDimensions[1] = dimensions[1]; + subDimensions[2] = dimensions[2]; + subOffset[0] = 0; + subOffset[1] = 0; + subOffset[2] = 0; +} + +void ImageMessage2::SetDimensions(int i, int j, int k) +{ + m_IsBodyPacked = false; + dimensions[0] = i; + dimensions[1] = j; + dimensions[2] = k; + + // initialize sub-volume + subDimensions[0] = dimensions[0]; + subDimensions[1] = dimensions[1]; + subDimensions[2] = dimensions[2]; + subOffset[0] = 0; + subOffset[1] = 0; + subOffset[2] = 0; +} + +void ImageMessage2::GetDimensions(int s[3]) +{ + s[0] = dimensions[0]; + s[1] = dimensions[1]; + s[2] = dimensions[2]; +} + +void ImageMessage2::GetDimensions(int &i, int &j, int &k) +{ + i = dimensions[0]; + j = dimensions[1]; + k = dimensions[2]; +} + +int ImageMessage2::SetSubVolume(int dim[3], int off[3]) +{ + // make sure that sub-volume fits in the dimensions + if (off[0] + dim[0] <= dimensions[0] && + off[1] + dim[1] <= dimensions[1] && + off[2] + dim[2] <= dimensions[2]) + { + m_IsBodyPacked = false; + subDimensions[0] = dim[0]; + subDimensions[1] = dim[1]; + subDimensions[2] = dim[2]; + subOffset[0] = off[0]; + subOffset[1] = off[1]; + subOffset[2] = off[2]; + return 1; + } + else + { + return 0; + } +} + +int ImageMessage2::SetSubVolume(int dimi, int dimj, int dimk, int offi, int offj, int offk) +{ + // make sure that sub-volume fits in the dimensions + if (offi + dimi <= dimensions[0] && + offj + dimj <= dimensions[1] && + offk + dimk <= dimensions[2]) + { + m_IsBodyPacked = false; + subDimensions[0] = dimi; + subDimensions[1] = dimj; + subDimensions[2] = dimk; + subOffset[0] = offi; + subOffset[1] = offj; + subOffset[2] = offk; + return 1; + } + else + { + return 0; + } +} + +void ImageMessage2::GetSubVolume(int dim[3], int off[3]) +{ + dim[0] = subDimensions[0]; + dim[1] = subDimensions[1]; + dim[2] = subDimensions[2]; + off[0] = subOffset[0]; + off[1] = subOffset[1]; + off[2] = subOffset[2]; +} + +void ImageMessage2::GetSubVolume(int &dimi, int &dimj, int &dimk, + int &offi, int &offj, int &offk) +{ + dimi = subDimensions[0]; + dimj = subDimensions[1]; + dimk = subDimensions[2]; + offi = subOffset[0]; + offj = subOffset[1]; + offk = subOffset[2]; +} + + +void ImageMessage2::SetSpacing(float s[3]) +{ + m_IsBodyPacked = false; + spacing[0] = s[0]; + spacing[1] = s[1]; + spacing[2] = s[2]; +} + +void ImageMessage2::SetSpacing(float si, float sj, float sk) +{ + m_IsBodyPacked = false; + spacing[0] = si; + spacing[1] = sj; + spacing[2] = sk; +} + +void ImageMessage2::GetSpacing(float s[3]) +{ + s[0] = spacing[0]; + s[1] = spacing[1]; + s[2] = spacing[2]; +} + +void ImageMessage2::GetSpacing(float &si, float &sj, float &sk) +{ + si = spacing[0]; + sj = spacing[1]; + sk = spacing[2]; +} + +void ImageMessage2::SetOrigin(float p[3]) +{ + m_IsBodyPacked = false; + matrix[0][3] = p[0]; + matrix[1][3] = p[1]; + matrix[2][3] = p[2]; +} + +void ImageMessage2::SetOrigin(float px, float py, float pz) +{ + m_IsBodyPacked = false; + matrix[0][3] = px; + matrix[1][3] = py; + matrix[2][3] = pz; +} + +void ImageMessage2::GetOrigin(float p[3]) +{ + p[0] = matrix[0][3]; + p[1] = matrix[1][3]; + p[2] = matrix[2][3]; +} + +void ImageMessage2::GetOrigin(float &px, float &py, float &pz) +{ + px = matrix[0][3]; + py = matrix[1][3]; + pz = matrix[2][3]; +} + +void ImageMessage2::SetNormals(float o[3][3]) +{ + m_IsBodyPacked = false; + matrix[0][0] = o[0][0]; + matrix[0][1] = o[0][1]; + matrix[0][2] = o[0][2]; + matrix[1][0] = o[1][0]; + matrix[1][1] = o[1][1]; + matrix[1][2] = o[1][2]; + matrix[2][0] = o[2][0]; + matrix[2][1] = o[2][1]; + matrix[2][2] = o[2][2]; +} + +void ImageMessage2::SetNormals(float t[3], float s[3], float n[3]) +{ + m_IsBodyPacked = false; + matrix[0][0] = t[0]; + matrix[1][0] = t[1]; + matrix[2][0] = t[2]; + matrix[0][1] = s[0]; + matrix[1][1] = s[1]; + matrix[2][1] = s[2]; + matrix[0][2] = n[0]; + matrix[1][2] = n[1]; + matrix[2][2] = n[2]; +} + +void ImageMessage2::GetNormals(float o[3][3]) +{ + o[0][0] = matrix[0][0]; + o[0][1] = matrix[0][1]; + o[0][2] = matrix[0][2]; + o[1][0] = matrix[1][0]; + o[1][1] = matrix[1][1]; + o[1][2] = matrix[1][2]; + o[2][0] = matrix[2][0]; + o[2][1] = matrix[2][1]; + o[2][2] = matrix[2][2]; +} + +void ImageMessage2::GetNormals(float t[3], float s[3], float n[3]) +{ + t[0] = matrix[0][0]; + t[1] = matrix[1][0]; + t[2] = matrix[2][0]; + s[0] = matrix[0][1]; + s[1] = matrix[1][1]; + s[2] = matrix[2][1]; + n[0] = matrix[0][2]; + n[1] = matrix[1][2]; + n[2] = matrix[2][2]; +} + +void ImageMessage2::SetMatrix(Matrix4x4& mat) +{ + m_IsBodyPacked = false; + matrix[0][0] = mat[0][0]; + matrix[1][0] = mat[1][0]; + matrix[2][0] = mat[2][0]; + matrix[3][0] = mat[3][0]; + + matrix[0][1] = mat[0][1]; + matrix[1][1] = mat[1][1]; + matrix[2][1] = mat[2][1]; + matrix[3][1] = mat[3][1]; + + matrix[0][2] = mat[0][2]; + matrix[1][2] = mat[1][2]; + matrix[2][2] = mat[2][2]; + matrix[3][2] = mat[3][2]; + + matrix[0][3] = mat[0][3]; + matrix[1][3] = mat[1][3]; + matrix[2][3] = mat[2][3]; + matrix[3][3] = mat[3][3]; +} + +void ImageMessage2::GetMatrix(Matrix4x4& mat) +{ + mat[0][0] = matrix[0][0]; + mat[1][0] = matrix[1][0]; + mat[2][0] = matrix[2][0]; + mat[3][0] = matrix[3][0]; + + mat[0][1] = matrix[0][1]; + mat[1][1] = matrix[1][1]; + mat[2][1] = matrix[2][1]; + mat[3][1] = matrix[3][1]; + + mat[0][2] = matrix[0][2]; + mat[1][2] = matrix[1][2]; + mat[2][2] = matrix[2][2]; + mat[3][2] = matrix[3][2]; + + mat[0][3] = matrix[0][3]; + mat[1][3] = matrix[1][3]; + mat[2][3] = matrix[2][3]; + mat[3][3] = matrix[3][3]; +} + +void ImageMessage2::AllocateScalars() +{ + // Memory area to store image scalar is allocated with + // message and image header, by using AllocatePack() implemented + // in the parent class. + +#ifdef FRAGMENTED_PACK + MessageBase::AllocateBuffer(); + if (!this->m_ImageHeader) + { + this->m_ImageHeader = new unsigned char [IGTL_IMAGE_HEADER_SIZE]; + this->m_SelfAllocatedImageHeader = 1; + } + + int s = GetSubVolumeImageSize(); + if (this->m_SelfAllocatedImage && this->m_Image) + { + delete [] this->m_Image; + } + this->m_Image = new unsigned char [s]; + this->m_SelfAllocatedImage = 1; + this->m_ImageSize = s; + this->m_MessageSize = IGTL_HEADER_SIZE + IGTL_IMAGE_HEADER_SIZE + s; + +#else + AllocateBuffer(); + this->m_ImageHeader = m_Content; + this->m_Image = &m_ImageHeader[IGTL_IMAGE_HEADER_SIZE]; +#endif +} + + +void* ImageMessage2::GetScalarPointer() +{ + return (void*)m_Image; +} + +#ifdef FRAGMENTED_PACK +void ImageMessage2::SetScalarPointer(void * p) +{ + if (this->m_SelfAllocatedImage && this->m_Image) + { + this->m_SelfAllocatedImage = 0; + this->m_ImageSize = 0; + + delete [] this->m_Image; + } + this->m_Image = (unsigned char *) p; + for (int i = 0;im_Content[i] = m_ImageHeader[i]; + } + for (int i = 0;im_Content[i+IGTL_IMAGE_HEADER_SIZE] = m_Image[i]; + } +} + + +void* ImageMessage2::GetBufferPointer() +{ + // This function is re-implemented for backward compatibility. + // If fragmented pack is supported, this function may cause + // memory copy that may considerably slows the program. + + // When the pack only contains header + if (this->m_MessageSize == IGTL_HEADER_SIZE) + { + return this->m_Header; + } + + // + int vs = this->GetSubVolumeImageSize(); + if (this->m_SinglePackSize < IGTL_HEADER_SIZE + IGTL_IMAGE_HEADER_SIZE + vs) + { + if (this->m_SinglePack) + { + delete [] this->m_SinglePack; + } + this->m_SinglePack = new unsigned char [IGTL_HEADER_SIZE + IGTL_IMAGE_HEADER_SIZE + vs]; + this->m_SinglePackSize = IGTL_HEADER_SIZE + IGTL_IMAGE_HEADER_SIZE + vs; + } + + if (this->m_SinglePack == NULL) + { + return NULL; + } + + unsigned char * ptr = this->m_SinglePack; + memcpy(ptr, this->m_Header, IGTL_HEADER_SIZE); + ptr += IGTL_HEADER_SIZE; + memcpy(ptr, this->m_ImageHeader, IGTL_IMAGE_HEADER_SIZE); + ptr += IGTL_IMAGE_HEADER_SIZE; + memcpy(ptr, this->m_Image, vs); + + return (void*) this->m_SinglePack; +} + + +void* ImageMessage2::GetPackFragmentPointer(int id) +{ + if (id == 0) + { + return this->m_Header; + } + else if (id == 1) + { + return this->m_ImageHeader; + } + else if (id == 2) + { + return this->m_Image; + } + + return NULL; + +} + + +int ImageMessage2::GetPackFragmentSize(int id) +{ + if (id == 0) + { + return IGTL_HEADER_SIZE; + } + else if (id == 1) + { + return IGTL_IMAGE_HEADER_SIZE; + } + else if (id == 2) + { + return GetSubVolumeImageSize(); + } + + return 0; +} + +#endif // FRAGMENTED_PACK + + +igtlUint64 ImageMessage2::CalculateContentBufferSize() +{ + // This function is called by: + // MessageBase::Pack() + // MessageBase::AllocatePack() + return GetSubVolumeImageSize() + IGTL_IMAGE_HEADER_SIZE; +} + + +#ifdef FRAGMENTED_PACK +int ImageMessage2::Pack() +{ + PackContent(); + m_IsBodyUnpacked = false; + + // pack header + igtl_header* h = (igtl_header*) m_Header; + + igtl_uint64 crc = crc64(0, 0, 0LL); // initial crc + + h->header_version = IGTL_HEADER_VERSION_1; + + igtl_uint64 ts = m_TimeStampSec & 0xFFFFFFFF; + ts = (ts << 32) | (m_TimeStampSecFraction & 0xFFFFFFFF); + + h->timestamp = ts; + h->body_size = CalculateContentBufferSize(); + + // Note pack fragment #0 is the OpenIGTLink general header. + for (int i = 1; i < this->GetNumberOfPackFragments(); i ++) + { + crc = crc64((unsigned char*)this->GetPackFragmentPointer(i), + this->GetPackFragmentSize(i), crc); + } + h->crc = crc; + + strncpy(h->name, m_SendMessageType.c_str(), 12); + + strncpy(h->device_name, m_DeviceName.c_str(), 20); + + igtl_header_convert_byte_order(h); + + m_IsHeaderUnpacked = false; + + return 1; +} +#endif // FRAGMENTED_PACK + + +int ImageMessage2::PackContent() +{ + igtl_image_header* image_header = (igtl_image_header*)this->m_ImageHeader; + + image_header->header_version = IGTL_IMAGE_HEADER_VERSION; + image_header->num_components = this->numComponents; + image_header->scalar_type = this->scalarType; + image_header->endian = this->endian; + image_header->coord = this->coordinate; + image_header->size[0] = this->dimensions[0]; + image_header->size[1] = this->dimensions[1]; + image_header->size[2] = this->dimensions[2]; + image_header->subvol_offset[0] = this->subOffset[0]; + image_header->subvol_offset[1] = this->subOffset[1]; + image_header->subvol_offset[2] = this->subOffset[2]; + image_header->subvol_size[0] = this->subDimensions[0]; + image_header->subvol_size[1] = this->subDimensions[1]; + image_header->subvol_size[2] = this->subDimensions[2]; + + float origin[3]; + float norm_i[3]; + float norm_j[3]; + float norm_k[3]; + + for (int i = 0; i < 3; i ++) { + norm_i[i] = matrix[i][0]; + norm_j[i] = matrix[i][1]; + norm_k[i] = matrix[i][2]; + origin[i] = matrix[i][3]; + } + + igtl_image_set_matrix(this->spacing, origin, + norm_i, norm_j, norm_k, + image_header); + + igtl_image_convert_byte_order(image_header); + + return 1; + +} + + +int ImageMessage2::UnpackContent() +{ + if (this->m_ImageHeader && this->m_SelfAllocatedImageHeader) + { + delete [] this->m_ImageHeader; + this->m_SelfAllocatedImageHeader = 0; + } + if (this->m_Image && this->m_SelfAllocatedImage) + { + delete [] this->m_Image; + this->m_SelfAllocatedImage = 0; + } + + this->m_ImageHeader = this->m_Content; + + igtl_image_header* image_header = (igtl_image_header*)m_ImageHeader; + igtl_image_convert_byte_order(image_header); + + if (image_header->header_version == IGTL_IMAGE_HEADER_VERSION) + { + // Image format version 1 + this->scalarType = image_header->scalar_type; + this->numComponents = image_header->num_components; + this->endian = image_header->endian; + this->coordinate = image_header->coord; + this->dimensions[0] = image_header->size[0]; + this->dimensions[1] = image_header->size[1]; + this->dimensions[2] = image_header->size[2]; + this->subOffset[0] = image_header->subvol_offset[0]; + this->subOffset[1] = image_header->subvol_offset[1]; + this->subOffset[2] = image_header->subvol_offset[2]; + this->subDimensions[0] = image_header->subvol_size[0]; + this->subDimensions[1] = image_header->subvol_size[1]; + this->subDimensions[2] = image_header->subvol_size[2]; + + // Set image orientation + float rspacing[3]; + float origin[3]; + float norm_i[3]; + float norm_j[3]; + float norm_k[3]; + + igtl_image_get_matrix(rspacing, origin, + norm_i, norm_j, norm_k, + image_header); + + for (int i = 0; i < 3; i ++) + { + this->spacing[i] = rspacing[i]; + matrix[i][0] = norm_i[i]; + matrix[i][1] = norm_j[i]; + matrix[i][2] = norm_k[i]; + matrix[i][3] = origin[i]; + } + + matrix[3][0] = 0.0; + matrix[3][1] = 0.0; + matrix[3][2] = 0.0; + matrix[3][3] = 1.0; + + this->m_Image = this->m_ImageHeader; + this->m_Image += IGTL_IMAGE_HEADER_SIZE; + + return 1; + } + else + { + // Incompatible version. + return 0; + } +} + +#ifdef FRAGMENTED_PACK +void ImageMessage2::AllocateBuffer(igtlUint64 contentSize) +{ + MessageBase::AllocateBuffer(contentSize); + if (contentSize == 0) + { + contentSize = 0; + this->m_IsBodyUnpacked = false; + } + + igtlUint64 s = IGTL_HEADER_SIZE + contentSize; + + m_IsHeaderUnpacked = false; + m_IsBodyUnpacked = false; + + if (this->m_ImageHeader && this->m_SelfAllocatedImageHeader) + { + delete[] this->m_ImageHeader; + this->m_ImageHeader = NULL; + this->m_SelfAllocatedImageHeader = 0; + } + if (this->m_Image && this->m_SelfAllocatedImage) + { + delete[] this->m_Image; + this->m_Image = NULL; + this->m_SelfAllocatedImage = 0; + } + if (this->m_Body) + { + if (this->m_MessageSize != s) + { + // If the pack area exists but needs to be reallocated + // m_IsHeaderUnpacked status is not changed in this case. + unsigned char* old = this->m_Body; + this->m_Body = new unsigned char[contentSize]; + memcpy(this->m_Body, old, contentSize); + delete[] old; + } + } + else + { + this->m_Body = new unsigned char[contentSize]; + } + this->m_MessageSize = s; +} +#endif // FRAGMENTED_PACK + + +void ImageMessage2::SetNumComponents(int num) +{ + if (num > 0 && num < 255) + { + numComponents = num; + } +} + + +int ImageMessage2::GetNumComponents() +{ + return numComponents; +} + + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlImageMessage2.h b/openigtlink/repo/Source/igtlImageMessage2.h new file mode 100644 index 0000000..3936e18 --- /dev/null +++ b/openigtlink/repo/Source/igtlImageMessage2.h @@ -0,0 +1,378 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlImageMessage2_h +#define __igtlImageMessage2_h + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" + + +#define FRAGMENTED_PACK + + +namespace igtl +{ + + +/// A class for the GET_IMAGE message type. The difference between the ImageMessage and +/// ImageMessage2 classes is that the ImageMessage2 class supports fragmented pack. +/// Fragmented pack allows allocating memory for each segment independently. +/// The version 1 library assumes that the memory area for entire message pack +/// is allocated at once, causing extra memory copies in some applications. +/// (For example, copying image from source into the pack memory) +class IGTLCommon_EXPORT GetImageMessage2: public MessageBase +{ +public: + igtlTypeMacro(igtl::GetImageMessage2, igtl::MessageBase); + igtlNewMacro(igtl::GetImageMessage2); + +protected: + GetImageMessage2() : MessageBase() { this->m_SendMessageType = "GET_IMAGE"; }; + ~GetImageMessage2() {}; +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; +}; + + +/// A class for the IMAGE message type with support for fragmented packing. +/// The IMAGE format supports 2D or 3D images with metric information including +/// image matrix size, voxel size, coordinate system type, position, and orientation. +/// The body section of the IMAGE data consists of two parts: image header to transfer +/// the metric information and image body to transfer the array of pixel or voxel values. +/// The data type of pixel or voxel can be either scalar or vector, and numerical values +/// can be 8-, 16-, 32-bit integer, or 32- or 64-bit floating point. The pixel values +/// can be either big-endian or little-endian, since the sender software can specify +/// the byte order in the image header. The format also supports "partial image transfer", +/// in which a region of the image is transferred instead of the whole image. This mechanism +/// is suitable for real-time applications, in which images are updated region-by-region. +/// The sub-volume must be box-shaped and defined by 6 parameters consisting of the indices +/// for the corner voxel of the sub-volume and matrix size of the sub-volume. +/// +/// The difference between the ImageMessage and +/// ImageMessage2 classes is that the ImageMessage2 class supports fragmented pack. +/// Fragmeted pack allows allocating memory for each segment independently. +/// The version 1 library assumes that the memory area for entire message pack +/// is allocated at once, causing extra memory copies in some applications. +/// (For example, copying image from source into the pack memory) +class IGTLCommon_EXPORT ImageMessage2: public MessageBase +{ +public: + igtlTypeMacro(igtl::ImageMessage2, igtl::MessageBase) + igtlNewMacro(igtl::ImageMessage2); + +public: + + /// Coordinate system. Either left-posterior-superior (LPS) or right-anterior-superior (RAS). + enum { + COORDINATE_RAS=1, + COORDINATE_LPS=2 + }; + + /// Endian used in the bite array for the image data. + enum { + ENDIAN_BIG=1, + ENDIAN_LITTLE=2 + }; + + /// Pixel data type either scalar or vector. + enum { + DTYPE_SCALAR = 1, + DTYPE_VECTOR = 3 + }; + + /// Pixel data type. + enum { + TYPE_INT8 = 2, + TYPE_UINT8 = 3, + TYPE_INT16 = 4, + TYPE_UINT16 = 5, + TYPE_INT32 = 6, + TYPE_UINT32 = 7, + TYPE_FLOAT32 = 10, + TYPE_FLOAT64 = 11 + }; + + +public: + + /// Sets image dimensions by an array of the numbers of pixels in i, j and k directions. + /// SetDimensions() should be called prior to SetSubVolume(), since SetDimensions() + /// sets subvolume parameters automatically assuming that subvolume = entire volume. + void SetDimensions(int s[3]); + + /// Sets image dimensions by the numbers of pixels in i, j and k directions. + /// SetDimensions() should be called prior to SetSubVolume(), since SetDimensions() + /// sets subvolume parameters automatically assuming that subvolume = entire volume. + void SetDimensions(int i, int j, int k); + + /// Gets image dimensions as an array of the numbers of pixels in i, j and k directions. + void GetDimensions(int s[3]); + + /// Gets image dimensions as the numbers of pixels in i, j and k directions. + void GetDimensions(int &i, int &j, int &k); + + /// Sets sub-volume dimensions and offset by arrays of the dimensions and the offset. + /// SetSubVolume() should be called after calling SetDiemensions(), since SetDimensions() + /// reset the subvolume parameters automatically. Returns non-zero value if the subvolume + /// is successfully specified. Returns zero, if invalid subvolume is specified. + int SetSubVolume(int dim[3], int off[3]); + + /// Sets sub-volume dimensions and offset by the dimensions and the offset in i, j and k + /// directions. SetSubVolume() should be called after calling SetDiemensions(), + /// since SetDimensions() reset the subvolume parameters automatically. + /// Returns non-zero value if the subvolume is successfully specified. + /// Returns zero, if invalid subvolume is specified. + int SetSubVolume(int dimi, int dimj, int dimk, int offi, int offj, int offk); + + /// Gets sub-volume dimensions and offset using arrays of the dimensions and the offset. + void GetSubVolume(int dim[3], int off[3]); + + /// Gets sub-volume dimensions and offset by the dimensions and the offset in i, j and k + /// directions. + void GetSubVolume(int &dimi, int &dimj, int &dimk, int &offi, int &offj, int &offk); + + /// Sets spacings by an array of spacing values in i, j and k directions. + void SetSpacing(float s[3]); + + /// Sets spacings by spacing values in i, j and k directions. + void SetSpacing(float si, float sj, float sk); + + /// Gets spacings using an array of spacing values in i, j and k directions. + void GetSpacing(float s[3]); + + /// Gets spacings using spacing values in i, j and k directions. + void GetSpacing(float &si, float &sj, float &sk); + + /// Sets the coordinates of the origin by an array of positions along the first (R or L), + /// second (A or P) and the third (S) axes. + void SetOrigin(float p[3]); + + /// Sets the coordinates of the origin by positions along the first (R or L), second (A or P) + /// and the third (S) axes. + void SetOrigin(float px, float py, float pz); + + /// Gets the coordinates of the origin using an array of positions along the first (R or L), + /// second (A or P) and the third (S) axes. + void GetOrigin(float p[3]); + + /// Gets the coordinates of the origin by positions along the first (R or L), second (A or P) + /// and the third (S) axes. + void GetOrigin(float &px, float &py, float &pz); + + /// Sets the orientation of the image by an array of the normal vectors for the i, j + /// and k indices. + void SetNormals(float o[3][3]); + + /// Sets the orientation of the image by the normal vectors for the i, j and k indeces. + void SetNormals(float t[3], float s[3], float n[3]); + + /// Gets the orientation of the image using an array of the normal vectors for the i, j + /// and k indices. + void GetNormals(float o[3][3]); + + /// Gets the orientation of the image using the normal vectors for the i, j and k indeces. + void GetNormals(float t[3], float s[3], float n[3]); + + /// Sets the number of components for each voxel. + void SetNumComponents(int num); + + /// Gets the number of components for each voxel. + int GetNumComponents(); + + /// Sets the origin/orientation matrix. + void SetMatrix(Matrix4x4& mat); + + /// Gets the origin/orientation matrix. + void GetMatrix(Matrix4x4& mat); + + /// Sets the image scalar type. + void SetScalarType(int t) { scalarType = t; }; + + /// Sets the image scalar type to 8-bit integer. + void SetScalarTypeToInt8() { scalarType = TYPE_INT8; }; + + /// Sets the image scalar type to unsigned 8-bit integer. + void SetScalarTypeToUint8() { scalarType = TYPE_UINT8; }; + + /// Sets the image scalar type to 16-bit integer. + void SetScalarTypeToInt16() { scalarType = TYPE_INT16; }; + + /// Sets the image scalar type to unsigned 16-bit integer. + void SetScalarTypeToUint16() { scalarType = TYPE_UINT16; }; + + /// Sets the image scalar type to 32-bit integer. + void SetScalarTypeToInt32() { scalarType = TYPE_INT32; }; + + /// Sets the image scalar type to unsigned 32-bit integer. + void SetScalarTypeToUint32() { scalarType = TYPE_UINT32; }; + + /// Gets the image scalar type. + int GetScalarType() { return scalarType; }; + + /// Gets the size of the scalar type used in the current image data. + /// (e.g. 1 byte for 8-bit integer) + int GetScalarSize() { return ScalarSizeTable[scalarType]; }; + + /// Gets the size of the specified scalar type. (e.g. 1 byte for 8-bit integer) + int GetScalarSize(int type) { return ScalarSizeTable[type]; }; + + /// Sets the Endianess of the image scalars. (default is ENDIAN_BIG) + void SetEndian(int e) { endian = e; }; + + /// Gets the Endianess of the image scalars. + int GetEndian() { return endian; }; + + /// Gets the size (length) of the byte array for the image data. + /// The size is defined by dimensions[0]*dimensions[1]*dimensions[2]*scalarSize*numComponents. + // TODO: Should returned value be 64-bit integer? + int GetImageSize() + { + return dimensions[0]*dimensions[1]*dimensions[2]*GetScalarSize()*numComponents; + }; + + /// Returns coordinate system (COORDINATE_RAS or COORDINATE_LPS) + int GetCoordinateSystem() { return coordinate;}; + + /// Sets coordinate system (COORDINATE_RAS or COORDINATE_LPS) + void SetCoordinateSystem(int c) {coordinate = c;}; + + /// Gets the size (length) of the byte array for the subvolume image data. + /// The size is defined by subDimensions[0]*subDimensions[1]*subDimensions[2]* + /// scalarSize*numComponents. + igtlUint64 GetSubVolumeImageSize() + { + return subDimensions[0]*subDimensions[1]*subDimensions[2]*GetScalarSize()*numComponents; + }; + + + /// Allocates a memory area for the scalar data based on the dimensions of the subvolume, + /// the number of components, and the scalar type. + /// Note: If FragmentedPack is active, GetScalarPointer() causes extra memory allocation to + /// create a single pack memory degrading the performance. + virtual void AllocateScalars(); + + /// Gets a pointer to the scalar data. + virtual void* GetScalarPointer(); + +#ifdef FRAGMENTED_PACK + /// Sets the pointer to the scalar data (for fragmented pack support). + virtual void SetScalarPointer(void * p); + + /// Gets a pointer to the scalar data (for fragmented pack support). + void* GetBufferPointer(); + + /// Gets the number of fragments for the packed (serialized) data. Returns 3 + /// consisting of header, image header and image body. (for fragmented pack support) + int GetNumberOfPackFragments() { return 3; /* header, image header and image body */ } + + /// Gets a pointer to the specified fragment of the packed data. (for fragmented pack support) + void* GetPackFragmentPointer(int id); + + /// Gets the size of the specified fragment. (for fragmented pack support) + int GetPackFragmentSize(int id); +#endif // FRAGMENTED_PACK + + +protected: + ImageMessage2(); + ~ImageMessage2(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + +#ifdef FRAGMENTED_PACK +public: + /// Pack() serializes the header and body based on the member variables. + /// PackBody() must be implemented in the child class. (for fragmented pack support) + int Pack() override; +public: +#endif //FRAGMENTED_PACK + + int PackContent() override; + int UnpackContent() override; + +#ifdef FRAGMENTED_PACK + /// Allocate memory specifying the body size + /// (used when create a brank package to receive data) (for fragmented pack support) + void AllocateBuffer(igtlUint64 contentSize) override; +#endif //FRAGMENTED_PACK + + /// A vector containing the numbers of voxels in i, j and k directions. + int dimensions[3]; + + /// A vector containing the spacings of the voxels in i, j and k directions. + float spacing[3]; + + /// A vector containing the numbers of voxels of the subvolume in i, j and k directions. + int subDimensions[3]; + + /// A vector containing the offset (number of voxels) of the first voxel of + /// the subvolume from the first voxel of the original image. + int subOffset[3]; + + /// A matrix representing the origin and the orientation of the image. + /// The matrix is set to identity by default + Matrix4x4 matrix; + + /// A variable for the Endian of the scalar values in the image. + int endian; + + /// A variable for the number of components. + int numComponents; + + /// A variable for the scalar type of the voxels. + int scalarType; + + /// A variable for the scalar type of the voxels. + int coordinate; + + /// A pointer to the serialized image header. + unsigned char* m_ImageHeader; + + /// A pointer to the serialized image data. + unsigned char* m_Image; + +#ifdef FRAGMENTED_PACK + /// A pointer to the serialized data (for backward compatibility with the conventional packing) + unsigned char* m_SinglePack; + + /// A variable for the memory size of this->m_SinglePack (for backward compatibility with the + /// conventional packing) + int m_SinglePackSize; + /// A variable for the memory size of this->m_Image (for backward compatibility with the + /// conventional packing) + int m_ImageSize; + + /// A flag for the fragmented image pack (allocated by this class). + int m_SelfAllocatedImage; + + /// A flag for the fragmented image pack (allocated by this class). + int m_SelfAllocatedImageHeader; + +#endif + + /// A table to look up the size of a given scalar type. + int ScalarSizeTable[12]; +}; + + +} // namespace igtl + +#endif // _igtlImageMessage2_h diff --git a/openigtlink/repo/Source/igtlImageMetaMessage.cxx b/openigtlink/repo/Source/igtlImageMetaMessage.cxx new file mode 100644 index 0000000..09574ee --- /dev/null +++ b/openigtlink/repo/Source/igtlImageMetaMessage.cxx @@ -0,0 +1,334 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlImageMetaMessage.h" + +#include "igtl_header.h" +#include "igtl_imgmeta.h" +#include "igtl_image.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include +#include + +namespace igtl { + + +//---------------------------------------------------------------------- +// igtl::ImageMetaElement class + +ImageMetaElement::ImageMetaElement() : Object() +{ + this->m_TimeStamp = 0; + this->m_Size[0] = 0; + this->m_Size[1] = 0; + this->m_Size[2] = 0; + this->m_ScalarType = 0; +} + + +ImageMetaElement::~ImageMetaElement() +{ +} + + +int ImageMetaElement::SetName(const char* name) +{ + if (strlen(name) <= IGTL_IMGMETA_LEN_NAME) + { + this->m_Name = name; + return 1; + } + else + { + return 0; + } +} + + +int ImageMetaElement::SetDeviceName(const char* devname) +{ + if (strlen(devname) <= IGTL_IMGMETA_LEN_DEVICE_NAME) + { + this->m_DeviceName = devname; + return 1; + } + else + { + return 0; + } +} + + +int ImageMetaElement::SetModality(const char* modality) +{ + if (strlen(modality) <= IGTL_IMGMETA_LEN_MODALITY) + { + this->m_Modality = modality; + return 1; + } + else + { + return 0; + } +} + + +int ImageMetaElement::SetPatientName(const char* patname) +{ + if (strlen(patname) <= IGTL_IMGMETA_LEN_PATIENT_NAME) + { + this->m_PatientName = patname; + return 1; + } + else + { + return 0; + } +} + + +int ImageMetaElement::SetPatientID(const char* patid) +{ + if (strlen(patid) <= IGTL_IMGMETA_LEN_PATIENT_ID) + { + this->m_PatientID = patid; + return 1; + } + else + { + return 0; + } +} + + +void ImageMetaElement::SetTimeStamp(igtl::TimeStamp::Pointer& time) +{ + this->m_TimeStamp = time; +} + + +void ImageMetaElement::GetTimeStamp(igtl::TimeStamp::Pointer& time) +{ + time = this->m_TimeStamp; +} + + +void ImageMetaElement::SetSize(igtlUint16 size[3]) +{ + this->m_Size[0] = size[0]; + this->m_Size[1] = size[1]; + this->m_Size[2] = size[2]; +} + + +void ImageMetaElement::SetSize(igtlUint16 si, igtlUint16 sj, igtlUint16 sk) +{ + this->m_Size[0] = si; + this->m_Size[1] = sj; + this->m_Size[2] = sk; +} + + +void ImageMetaElement::GetSize(igtlUint16* size) +{ + size[0] = this->m_Size[0]; + size[1] = this->m_Size[1]; + size[2] = this->m_Size[2]; +} + + +void ImageMetaElement::GetSize(igtlUint16& si, igtlUint16& sj, igtlUint16& sk) +{ + si = this->m_Size[0]; + sj = this->m_Size[1]; + sk = this->m_Size[2]; +} + + +void ImageMetaElement::SetScalarType(igtlUint8 type) +{ + if (type == IGTL_IMAGE_STYPE_TYPE_INT8 || + type == IGTL_IMAGE_STYPE_TYPE_UINT8 || + type == IGTL_IMAGE_STYPE_TYPE_INT16 || + type == IGTL_IMAGE_STYPE_TYPE_UINT16 || + type == IGTL_IMAGE_STYPE_TYPE_INT32 || + type == IGTL_IMAGE_STYPE_TYPE_UINT32 || + type == IGTL_IMAGE_STYPE_TYPE_FLOAT32 || + type == IGTL_IMAGE_STYPE_TYPE_FLOAT64) + { + this->m_ScalarType = type; + } + else + { + this->m_ScalarType = 0; + } +} + + +igtlUint8 ImageMetaElement::GetScalarType() +{ + return this->m_ScalarType; +} + + + +//---------------------------------------------------------------------- +// igtl::ImageMetaMessage class + +ImageMetaMessage::ImageMetaMessage() +{ + this->m_SendMessageType = "IMGMETA"; + this->m_ImageMetaList.clear(); +} + + +ImageMetaMessage::~ImageMetaMessage() +{ +} + + +int ImageMetaMessage::AddImageMetaElement(ImageMetaElement::Pointer& elem) +{ + m_IsBodyPacked = false; + this->m_ImageMetaList.push_back(elem); + return this->m_ImageMetaList.size(); +} + + +void ImageMetaMessage::ClearImageMetaElement() +{ + this->m_ImageMetaList.clear(); +} + + +int ImageMetaMessage::GetNumberOfImageMetaElement() +{ + return this->m_ImageMetaList.size(); +} + + +void ImageMetaMessage::GetImageMetaElement(int index, ImageMetaElement::Pointer& elem) +{ + if (index >= 0 && index < (int) this->m_ImageMetaList.size()) + { + elem = this->m_ImageMetaList[index]; + } +} + + +igtlUint64 ImageMetaMessage::CalculateContentBufferSize() +{ + // The body size sum of the header size and status message size. + return IGTL_IMGMETA_ELEMENT_SIZE * this->m_ImageMetaList.size(); +} + + +int ImageMetaMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + igtl_imgmeta_element* element = (igtl_imgmeta_element*)this->m_Content; + + std::vector::iterator iter; + for (iter = this->m_ImageMetaList.begin(); iter != this->m_ImageMetaList.end(); iter ++) + { + strncpy((char*)element->name, (*iter)->GetName(), IGTL_IMGMETA_LEN_NAME); + strncpy((char*)element->device_name, (*iter)->GetDeviceName(), IGTL_IMGMETA_LEN_DEVICE_NAME); + strncpy((char*)element->modality, (*iter)->GetModality(), IGTL_IMGMETA_LEN_MODALITY); + strncpy((char*)element->patient_name, (*iter)->GetPatientName(), IGTL_IMGMETA_LEN_PATIENT_NAME); + strncpy((char*)element->patient_id, (*iter)->GetPatientID(), IGTL_IMGMETA_LEN_PATIENT_ID); + + igtl::TimeStamp::Pointer ts; + (*iter)->GetTimeStamp(ts); + if (ts.IsNotNull()) + { + element->timestamp = ts->GetTimeStampUint64(); + } + else + { + element->timestamp = 0; + } + igtlUint16 size[3]; + (*iter)->GetSize(size); + element->size[0] = size[0]; + element->size[1] = size[1]; + element->size[2] = size[2]; + element->scalar_type = (*iter)->GetScalarType(); + element->reserved = 0; + element ++; + } + + igtl_imgmeta_convert_byte_order((igtl_imgmeta_element*)this->m_Content, this->m_ImageMetaList.size()); + + return 1; +} + + +int ImageMetaMessage::UnpackContent() +{ + + this->m_ImageMetaList.clear(); + + igtl_imgmeta_element* element = (igtl_imgmeta_element*) this->m_Content; + int nElement = igtl_imgmeta_get_data_n(this->m_BodySizeToRead); + + igtl_imgmeta_convert_byte_order(element, nElement); + + char strbuf[128]; + for (int i = 0; i < nElement; i ++) + { + ImageMetaElement::Pointer elemClass = ImageMetaElement::New(); + + // Add '\n' at the end of each string + // (necessary for a case, where a string reaches the maximum length.) + strbuf[IGTL_IMGMETA_LEN_NAME] = '\n'; + strncpy(strbuf, (char*)element->name, IGTL_IMGMETA_LEN_NAME); + elemClass->SetName((const char*)strbuf); + + strbuf[IGTL_IMGMETA_LEN_DEVICE_NAME] = '\n'; + strncpy(strbuf, (char*)element->device_name, IGTL_IMGMETA_LEN_DEVICE_NAME); + elemClass->SetDeviceName(strbuf); + + strbuf[IGTL_IMGMETA_LEN_MODALITY] = '\n'; + strncpy(strbuf, (char*)element->modality, IGTL_IMGMETA_LEN_MODALITY); + elemClass->SetModality(strbuf); + + strbuf[IGTL_IMGMETA_LEN_PATIENT_NAME] = '\n'; + strncpy(strbuf, (char*)element->patient_name, IGTL_IMGMETA_LEN_PATIENT_NAME); + elemClass->SetPatientName(strbuf); + + strbuf[IGTL_IMGMETA_LEN_PATIENT_ID] = '\n'; + strncpy(strbuf, (char*)element->patient_id, IGTL_IMGMETA_LEN_PATIENT_ID); + elemClass->SetPatientID(strbuf); + + TimeStamp::Pointer ts = TimeStamp::New(); + ts->SetTime(element->timestamp); + elemClass->SetTimeStamp(ts); + + elemClass->SetSize(element->size); + elemClass->SetScalarType(element->scalar_type); + + this->m_ImageMetaList.push_back(elemClass); + + element ++; + } + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlImageMetaMessage.h b/openigtlink/repo/Source/igtlImageMetaMessage.h new file mode 100644 index 0000000..db9afab --- /dev/null +++ b/openigtlink/repo/Source/igtlImageMetaMessage.h @@ -0,0 +1,193 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlImageMetaMessage_h +#define __igtlImageMetaMessage_h + +#include +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +#include "igtlImageMessage.h" + +namespace igtl +{ + +/// A class to manage meta data of images. +class IGTLCommon_EXPORT ImageMetaElement: public Object +{ +public: + igtlTypeMacro(igtl::ImageMetaElement, igtl::Object); + igtlNewMacro(igtl::ImageMetaElement); + +public: + + /// Sets the image name/description. The string 'name' must not exceed 64 characters. + int SetName(const char* name); + + /// Gets the image name/description. + const char* GetName() { return this->m_Name.c_str(); }; + + /// Sets the device name (message name). The string 'devname' must not exceed 20 + /// characters. + int SetDeviceName(const char* devname); + + /// Gets the device name (message name). + const char* GetDeviceName() { return this->m_DeviceName.c_str(); }; + + /// Sets the name of the image modality (e.g. CT, MRI). The string 'modality' must not + /// exceed 32 characters. + int SetModality(const char* modality); + + /// Gets the name of the image modality. + const char* GetModality() { return this->m_Modality.c_str(); }; + + /// Sets the patient name. The string 'patname' must not exceed 64 characters. + int SetPatientName(const char* patname); + + /// Gets the patient name. + const char* GetPatientName() { return this->m_PatientName.c_str(); }; + + /// Sets the patient ID. The string 'patid' must not exceed 64 characters. + int SetPatientID(const char* patid); + + /// Gets the patient ID. + const char* GetPatientID() { return this->m_PatientID.c_str(); } + + /// Sets the scan time for the image. + void SetTimeStamp(igtl::TimeStamp::Pointer& time); + + /// Gets the scan time for the image. + void GetTimeStamp(igtl::TimeStamp::Pointer& time); + + /// Sets the size of the image by an array containing the numbers of voxels in i, j, and k + /// directions. + void SetSize(igtlUint16 size[3]); + + /// Sets the size of the image by the numbers of voxels in i, j, and k directions. + void SetSize(igtlUint16 si, igtlUint16 sj, igtlUint16 sk); + + /// Gets the size of the image using an array containing the numbers of voxels in i, j, and k + /// directions. + void GetSize(igtlUint16* size); + + /// Gets the size of the image by the numbers of voxels in i, j, and k directions. + void GetSize(igtlUint16& si, igtlUint16& sj, igtlUint16& sk); + + /// Sets the scalar type of the image + void SetScalarType(igtlUint8 type); + + /// Gets the scalar type of the image. + igtlUint8 GetScalarType(); + +protected: + ImageMetaElement(); + ~ImageMetaElement(); + +protected: + + /// name / description (<= 64 bytes) + std::string m_Name; + + /// device name to query the IMAGE and COLORT + std::string m_DeviceName; + + /// modality name (<= 32 bytes) + std::string m_Modality; + + /// patient name (<= 64 bytes) + std::string m_PatientName; + + /// patient ID (MRN etc.) (<= 64 bytes) + std::string m_PatientID; + + /// scan time + TimeStamp::Pointer m_TimeStamp; + + /// entire image volume size + igtlUint16 m_Size[3]; + + /// scalar type. see scalar_type in IMAGE message + igtlUint8 m_ScalarType; + +}; + + +/// A class for the GET_IMGMETA message type. +class IGTLCommon_EXPORT GetImageMetaMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::GetImageMetaMessage, igtl::MessageBase); + igtlNewMacro(igtl::GetImageMetaMessage); + +protected: + GetImageMetaMessage() : MessageBase() { this->m_SendMessageType = "GET_IMGMETA"; }; + ~GetImageMetaMessage() {}; +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; +}; + + +/// The IMGMETA message is used to transfer image meta information which are not +/// available in the IMAGE message type, such as patient name, medical record number, +/// modality etc. An IMGMETA message can contain meta data for multiple images. +/// This message type may be used to obtain a list of images available in +/// the remote system, such as image database or commercial image-guided surgery (IGS) system. +class IGTLCommon_EXPORT ImageMetaMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::ImageMetaMessage, igtl::MessageBase); + igtlNewMacro(igtl::ImageMetaMessage); + +public: + + /// Adds an image meta element to the list. Returns the number of elements after + /// adding the image meta element. + int AddImageMetaElement(ImageMetaElement::Pointer& elem); + + /// Clears the all image meta elements in the list. + void ClearImageMetaElement(); + + /// Gets the number of the image meta elements in the list. + int GetNumberOfImageMetaElement(); + + /// Gets the image meta data specified by the index. + void GetImageMetaElement(int index, ImageMetaElement::Pointer& elem); + + +protected: + ImageMetaMessage(); + ~ImageMetaMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// A list of pointers to image meta data. + std::vector m_ImageMetaList; + +}; + + +} // namespace igtl + +#endif // _igtlImageMetaMessage_h diff --git a/openigtlink/repo/Source/igtlLabelMetaMessage.cxx b/openigtlink/repo/Source/igtlLabelMetaMessage.cxx new file mode 100644 index 0000000..d125b01 --- /dev/null +++ b/openigtlink/repo/Source/igtlLabelMetaMessage.cxx @@ -0,0 +1,299 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlLabelMetaMessage.h" + +#include "igtl_header.h" +#include "igtl_imgmeta.h" +#include "igtl_lbmeta.h" +#include "igtl_image.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include +#include + +namespace igtl { + + +//---------------------------------------------------------------------- +// igtl::LabelMetaElement class + +LabelMetaElement::LabelMetaElement() : Object() +{ + this->m_Name = ""; + this->m_DeviceName = ""; + this->m_Label = 0; + this->m_RGBA[0] = 0; + this->m_RGBA[1] = 0; + this->m_RGBA[2] = 0; + this->m_RGBA[3] = 0; + this->m_Size[0] = 0; + this->m_Size[1] = 0; + this->m_Size[2] = 0; + this->m_Owner = ""; +} + + +LabelMetaElement::~LabelMetaElement() +{ +} + + +int LabelMetaElement::SetName(const char* name) +{ + if (strlen(name) <= IGTL_LBMETA_LEN_NAME) + { + this->m_Name = name; + return 1; + } + else + { + return 0; + } +} + + +int LabelMetaElement::SetDeviceName(const char* devname) +{ + if (strlen(devname) <= IGTL_LBMETA_LEN_DEVICE_NAME) + { + this->m_DeviceName = devname; + return 1; + } + else + { + return 0; + } +} + + +void LabelMetaElement::SetRGBA(igtlUint8 rgba[4]) +{ + this->m_RGBA[0] = rgba[0]; + this->m_RGBA[1] = rgba[1]; + this->m_RGBA[2] = rgba[2]; + this->m_RGBA[3] = rgba[3]; +} + + +void LabelMetaElement::SetRGBA(igtlUint8 r, igtlUint8 g, igtlUint8 b, igtlUint8 a) +{ + this->m_RGBA[0] = r; + this->m_RGBA[1] = g; + this->m_RGBA[2] = b; + this->m_RGBA[3] = a; +} + + +void LabelMetaElement::GetRGBA(igtlUint8* rgba) +{ + rgba[0] = this->m_RGBA[0]; + rgba[1] = this->m_RGBA[1]; + rgba[2] = this->m_RGBA[2]; + rgba[3] = this->m_RGBA[3]; +} + + + +void LabelMetaElement::GetRGBA(igtlUint8& r, igtlUint8& g, igtlUint8& b, igtlUint8& a) +{ + r = this->m_RGBA[0]; + g = this->m_RGBA[1]; + b = this->m_RGBA[2]; + a = this->m_RGBA[3]; +} + + +void LabelMetaElement::SetSize(igtlUint16 size[3]) +{ + this->m_Size[0] = size[0]; + this->m_Size[1] = size[1]; + this->m_Size[2] = size[2]; +} + + +void LabelMetaElement::SetSize(igtlUint16 si, igtlUint16 sj, igtlUint16 sk) +{ + this->m_Size[0] = si; + this->m_Size[1] = sj; + this->m_Size[2] = sk; +} + + +void LabelMetaElement::GetSize(igtlUint16* size) +{ + size[0] = this->m_Size[0]; + size[1] = this->m_Size[1]; + size[2] = this->m_Size[2]; +} + + +void LabelMetaElement::GetSize(igtlUint16& si, igtlUint16& sj, igtlUint16& sk) +{ + si = this->m_Size[0]; + sj = this->m_Size[1]; + sk = this->m_Size[2]; +} + + +int LabelMetaElement::SetOwner(const char* owner) +{ + if (strlen(owner) <= IGTL_LBMETA_LEN_OWNER) + { + this->m_Owner = owner; + return 1; + } + else + { + return 0; + } + +} + + +//---------------------------------------------------------------------- +// igtl::LabelMetaMessage class + +LabelMetaMessage::LabelMetaMessage() +{ + this->m_SendMessageType = "LBMETA"; + this->m_LabelMetaList.clear(); +} + + +LabelMetaMessage::~LabelMetaMessage() +{ +} + + +int LabelMetaMessage::AddLabelMetaElement(LabelMetaElement::Pointer& elem) +{ + m_IsBodyPacked = false; + this->m_LabelMetaList.push_back(elem); + return this->m_LabelMetaList.size(); +} + + +void LabelMetaMessage::ClearLabelMetaElement() +{ + this->m_LabelMetaList.clear(); +} + + +int LabelMetaMessage::GetNumberOfLabelMetaElement() +{ + return this->m_LabelMetaList.size(); +} + + +void LabelMetaMessage::GetLabelMetaElement(int index, LabelMetaElement::Pointer& elem) +{ + if (index >= 0 && index < (int)this->m_LabelMetaList.size()) + { + elem = this->m_LabelMetaList[index]; + } +} + + +igtlUint64 LabelMetaMessage::CalculateContentBufferSize() +{ + // The body size sum of the header size and status message size. + return IGTL_LBMETA_ELEMENT_SIZE * this->m_LabelMetaList.size(); +} + + +int LabelMetaMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + igtl_lbmeta_element* element; + element = (igtl_lbmeta_element*)this->m_Content; + std::vector::iterator iter; + + for (iter = this->m_LabelMetaList.begin(); iter != this->m_LabelMetaList.end(); iter ++) + { + strncpy((char*)element->name, (*iter)->GetName(), IGTL_LBMETA_LEN_NAME); + strncpy((char*)element->device_name, (*iter)->GetDeviceName(), IGTL_LBMETA_LEN_DEVICE_NAME); + + element->label = (*iter)->GetLabel(); + element->reserved = 0; + igtlUint8 rgba[4]; + (*iter)->GetRGBA(rgba); + element->rgba[0] = rgba[0]; + element->rgba[1] = rgba[1]; + element->rgba[2] = rgba[2]; + element->rgba[3] = rgba[3]; + + igtlUint16 size[3]; + (*iter)->GetSize(size); + element->size[0] = size[0]; + element->size[1] = size[1]; + element->size[2] = size[2]; + + strncpy((char*)element->owner, (*iter)->GetOwner(), IGTL_LBMETA_LEN_OWNER); + + element ++; + } + + igtl_lbmeta_convert_byte_order((igtl_lbmeta_element*)this->m_Content, this->m_LabelMetaList.size()); + + return 1; +} + + +int LabelMetaMessage::UnpackContent() +{ + + this->m_LabelMetaList.clear(); + + igtl_lbmeta_element* element = (igtl_lbmeta_element*) this->m_Content; + int nElement = igtl_lbmeta_get_data_n(this->m_BodySizeToRead); + + igtl_lbmeta_convert_byte_order(element, nElement); + + char strbuf[128]; + for (int i = 0; i < nElement; i ++) + { + LabelMetaElement::Pointer elemClass = LabelMetaElement::New(); + + // Add '\n' at the end of each string + // (neccesary for a case, where a string reaches the maximum length.) + strbuf[IGTL_LBMETA_LEN_NAME] = '\n'; + strncpy(strbuf, (char*)element->name, IGTL_LBMETA_LEN_NAME); + elemClass->SetName((const char*)strbuf); + + strbuf[IGTL_LBMETA_LEN_DEVICE_NAME] = '\n'; + strncpy(strbuf, (char*)element->device_name, IGTL_LBMETA_LEN_DEVICE_NAME); + elemClass->SetDeviceName(strbuf); + + elemClass->SetLabel(element->label); + elemClass->SetRGBA(element->rgba); + elemClass->SetSize(element->size); + + strbuf[IGTL_LBMETA_LEN_OWNER] = '\n'; + strncpy(strbuf, (char*)element->owner, IGTL_LBMETA_LEN_OWNER); + elemClass->SetOwner(strbuf); + + this->m_LabelMetaList.push_back(elemClass); + + element ++; + } + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlLabelMetaMessage.h b/openigtlink/repo/Source/igtlLabelMetaMessage.h new file mode 100644 index 0000000..426183a --- /dev/null +++ b/openigtlink/repo/Source/igtlLabelMetaMessage.h @@ -0,0 +1,176 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlLabelMetaMessage_h +#define __igtlLabelMetaMessage_h + +#include +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +#include "igtlImageMessage.h" + +namespace igtl +{ + +class IGTLCommon_EXPORT LabelMetaElement: public Object +{ +public: + igtlTypeMacro(igtl::LabelMetaElement, igtl::Object); + igtlNewMacro(igtl::LabelMetaElement); + +public: + + /// Sets the image name/description. The string 'name' must not exceed 64 characters. + int SetName(const char* name); + + /// Gets the image name/description. + const char* GetName() { return this->m_Name.c_str(); }; + + /// Sets the device name (message name). The string 'devname' must not exceed 20 + /// characters. + int SetDeviceName(const char* devname); + + /// Gets the device name (message name). + const char* GetDeviceName() { return this->m_DeviceName.c_str(); }; + + /// Sets the label of the structure. + void SetLabel(igtlUint8 label) { this->m_Label = label; }; + + /// Gets the label of the structure. + igtlUint8 GetLabel() { return this->m_Label; }; + + /// Sets the color of the structure by an array representing RGBA. + void SetRGBA(igtlUint8 rgba[4]); + + /// Sets the color of the structure by R, G, B, and A values. + void SetRGBA(igtlUint8 r, igtlUint8 g, igtlUint8 b, igtlUint8 a); + + /// Gets the color of the structure by an array representing RGBA. + void GetRGBA(igtlUint8* rgba); + + /// Gets the color of the structure by R, G, B, and A values. + void GetRGBA(igtlUint8& r, igtlUint8& g, igtlUint8& b, igtlUint8& a); + + /// Sets the size of the image by an array containing the numbers of voxels in i, j, and k + /// directions. + void SetSize(igtlUint16 size[3]); + + /// Sets the size of the image by the numbers of voxels in i, j, and k directions. + void SetSize(igtlUint16 si, igtlUint16 sj, igtlUint16 sk); + + /// Gets the size of the image using an array containing the numbers of voxels in i, j, and k + /// directions. + void GetSize(igtlUint16* size); + + /// Gets the size of the image by the numbers of voxels in i, j, and k directions. + void GetSize(igtlUint16& si, igtlUint16& sj, igtlUint16& sk); + + /// Sets the name of the image that owns this label map. + int SetOwner(const char* owner); + + /// Gets the name of the image that owns this label map. + const char* GetOwner() { return this->m_Owner.c_str(); }; + +protected: + LabelMetaElement(); + ~LabelMetaElement(); + +protected: + + /// Name / description (<= 64 bytes) + std::string m_Name; + + /// Device name to query the IMAGE and COLORT + std::string m_DeviceName; + + /// Label + igtlUint8 m_Label; + + /// Color in RGBA. default: (0, 0, 0, 0) + igtlUint8 m_RGBA[4]; + + /// entire image volume size + igtlUint16 m_Size[3]; + + /// device name of the owner image. (can be empty) + std::string m_Owner; + +}; + + +/// A class for the GET_LBMETA message type. +class IGTLCommon_EXPORT GetLabelMetaMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::GetLabelMetaMessage, igtl::MessageBase); + igtlNewMacro(igtl::GetLabelMetaMessage); + +protected: + GetLabelMetaMessage() : MessageBase() { this->m_SendMessageType = "GET_LBMETA"; }; + ~GetLabelMetaMessage() {}; +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; +}; + + +/// The LBMETA is used to transfer meta information for label maps, which are not available +/// in the IMAGE message type. To retrieve voxel objects or a label map, GET_IMAGE / IMAGE +/// can be used. But the client should be able to get a list of available structures. +class IGTLCommon_EXPORT LabelMetaMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::LabelMetaMessage, igtl::MessageBase); + igtlNewMacro(igtl::LabelMetaMessage); + +public: + + /// Adds an label meta element to the list. + int AddLabelMetaElement(LabelMetaElement::Pointer& elem); + + /// Clears the all label meta elements in the list. + void ClearLabelMetaElement(); + + /// Gets the number of the label meta elements in the list. + int GetNumberOfLabelMetaElement(); + + /// Gets the label meta element specified by the index. + void GetLabelMetaElement(int index, LabelMetaElement::Pointer& elem); + + +protected: + LabelMetaMessage(); + ~LabelMetaMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + // A list of pointers to label meta data. + std::vector m_LabelMetaList; + +}; + + +} // namespace igtl + +#endif // _igtlLabelMetaMessage_h diff --git a/openigtlink/repo/Source/igtlLightObject.cxx b/openigtlink/repo/Source/igtlLightObject.cxx new file mode 100644 index 0000000..7da1775 --- /dev/null +++ b/openigtlink/repo/Source/igtlLightObject.cxx @@ -0,0 +1,279 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkLightObject.cxx,v $ + Language: C++ + Date: $Date: 2009-11-12 23:48:21 -0500 (Thu, 12 Nov 2009) $ + Version: $Revision: 5332 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "igtlLightObject.h" +#include "igtlObjectFactory.h" +#include "igtlFastMutexLock.h" + +#include +#include +#include + +// Better name demanging for gcc +#if __GNUC__ > 3 || ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) +#define GCC_USEDEMANGLE +#endif + +#ifdef GCC_USEDEMANGLE +#include +#include +#endif + +namespace igtl +{ + +LightObject::Pointer +LightObject::New() +{ + Pointer smartPtr; + LightObject *rawPtr = ::igtl::ObjectFactory::Create(); + if(rawPtr == NULL) + { + rawPtr = new LightObject; + } + smartPtr = rawPtr; + rawPtr->UnRegister(); + return smartPtr; +} + +LightObject::Pointer +LightObject::CreateAnother() const +{ + return LightObject::New(); +} + +/** + * Delete a igtl object. This method should always be used to delete an object + * when the new operator was used to create it. Using the C++ delete method + * will not work with reference counting. + */ +void +LightObject +::Delete() +{ + this->UnRegister(); +} + + +/** + * Avoid DLL boundary problems. + */ +#ifdef _WIN32 +void* +LightObject +::operator new(size_t n) +{ + return new char[n]; +} + +void* +LightObject +::operator new[](size_t n) +{ + return new char[n]; +} + +void +LightObject +::operator delete(void* m) +{ + delete [] (char*)m; +} + +void +LightObject +::operator delete[](void* m, size_t) +{ + delete [] (char*)m; +} +#endif + + +/** + * This function will be common to all igtl objects. It just calls the + * header/self/trailer virtual print methods, which can be overriden by + * subclasses (any igtl object). + */ +void +LightObject +::Print(std::ostream& os) const +{ + this->PrintHeader(os); + this->PrintSelf(os); + this->PrintTrailer(os); +} + + +/** + * This method is called when igtlExceptionMacro executes. It allows + * the debugger to break on error. + */ +void +LightObject +::BreakOnError() +{ + ; +} + + +/** + * Increase the reference count (mark as used by another object). + */ +void +LightObject +::Register() const +{ + m_ReferenceCountLock.Lock(); + m_ReferenceCount++; + m_ReferenceCountLock.Unlock(); +} + + +/** + * Decrease the reference count (release by another object). + */ +void +LightObject +::UnRegister() const +{ + m_ReferenceCountLock.Lock(); + int tmpReferenceCount = --m_ReferenceCount; + m_ReferenceCountLock.Unlock(); + + // ReferenceCount in now unlocked. We may have a race condition + // to delete the object. + if ( tmpReferenceCount <= 0) + { + delete this; + } +} + + +/** + * Sets the reference count (use with care) + */ +void +LightObject +::SetReferenceCount(int ref) +{ + m_ReferenceCountLock.Lock(); + m_ReferenceCount = ref; + m_ReferenceCountLock.Unlock(); + + if ( ref <= 0) + { + delete this; + } +} + +LightObject +::~LightObject() +{ + /** + * warn user if reference counting is on and the object is being referenced + * by another object. + */ + if(m_ReferenceCount > 0) + { + igtlWarningMacro("Trying to delete object with non-zero reference count."); + } +} + + +/** + * Chaining method to print an object's instance variables, as well as + * its superclasses. + */ +void +LightObject +::PrintSelf(std::ostream& os) const +{ + const char* indent = " "; + +#ifdef GCC_USEDEMANGLE + char const * mangledName = typeid(*this).name(); + int status; + char* unmangled = abi::__cxa_demangle(mangledName, 0, 0, &status); + + os << indent << "RTTI typeinfo: "; + + if(status == 0) + { + os << unmangled; + free(unmangled); + } + else + { + os << mangledName; + } + + os << std::endl; +#else + os << indent << "RTTI typeinfo: " << typeid( *this ).name() << std::endl; +#endif + os << indent << "Reference Count: " << m_ReferenceCount << std::endl; +} + + +/** + * Define a default print header for all objects. + */ +void +LightObject +::PrintHeader(std::ostream& os) const +{ + os << " " << this->GetNameOfClass() << " (" << this << ")\n"; +} + + +/** + * Define a default print trailer for all objects. + */ +void +LightObject +::PrintTrailer(std::ostream& igtlNotUsed(os)) const +{ +} + + +/** + * This operator allows all subclasses of LightObject to be printed via <<. + * It in turn invokes the Print method, which in turn will invoke the + * PrintSelf method that all objects should define, if they have anything + * interesting to print out. + */ +std::ostream& +operator<<(std::ostream& os, const LightObject& o) +{ + o.Print(os); + return os; +} + + +} // end namespace igtl diff --git a/openigtlink/repo/Source/igtlLightObject.h b/openigtlink/repo/Source/igtlLightObject.h new file mode 100644 index 0000000..914bd69 --- /dev/null +++ b/openigtlink/repo/Source/igtlLightObject.h @@ -0,0 +1,143 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkLightObject.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlLightObject_h +#define __igtlLightObject_h + +#include "igtlSmartPointer.h" +#include "igtlSimpleFastMutexLock.h" +#include "igtlMacro.h" + +#include +#include + + +namespace igtl +{ + +/** \class LightObject + * \brief Light weight base class for most igtl classes. + * + * LightObject is the highest level base class for most igtl objects. It + * implements reference counting and the API for object printing. + * It can be used as a lightweight base class in preference to Object. + * (LightObject does not support callbacks or modified time as Object + * does.) All IGTL objects should be a subclass of LightObject or Object + * with few exceptions (due to performance concerns). + * + * \sa Object + * \ingroup IGTLSystemObjects + * \ingroup DataRepresentation + */ +class IGTLCommon_EXPORT LightObject +{ +public: + /** Standard clas typedefs. */ + typedef LightObject Self; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + static Pointer New(); + + /** Create an object from an instance, potentially deferring to a + * factory. This method allows you to create an instance of an + * object that is exactly the same type as the referring object. + * This is useful in cases where an object has been cast back to a + * base class. */ + virtual Pointer CreateAnother() const; + + /** Delete an igtl object. This method should always be used to delete an + * object when the new operator was used to create it. Using the C + * delete method will not work with reference counting. */ + virtual void Delete(); + + /** Return the name of this class as a string. Used by the object factory + * (implemented in New()) to instantiate objects of a named type. Also + * used for debugging and other output information. */ + virtual const char *GetNameOfClass() const + {return "LightObject";} + +#ifdef _WIN32 + /** Used to avoid dll boundary problems. */ + void* operator new(size_t); + void* operator new[](size_t); + void operator delete(void*); + void operator delete[](void*, size_t); +#endif + + /** Cause the object to print itself out. */ + void Print(std::ostream& os) const; + + /** This method is called when igtlExceptionMacro executes. It allows + * the debugger to break on error. */ + static void BreakOnError(); + + /** Increase the reference count (mark as used by another object). */ + virtual void Register() const; + + /** Decrease the reference count (release by another object). */ + virtual void UnRegister() const; + + /** Gets the reference count on this object. */ + virtual int GetReferenceCount() const + {return m_ReferenceCount;} + + /** Sets the reference count on this object. This is a dangerous + * method, use it with care. */ + virtual void SetReferenceCount(int); + +protected: + LightObject():m_ReferenceCount(1) {} + virtual ~LightObject(); + + /** Methods invoked by Print() to print information about the object + * including superclasses. Typically not called by the user (use Print() + * instead) but used in the hierarchical print process to combine the + * output of several classes. */ + virtual void PrintSelf(std::ostream& os) const; + virtual void PrintHeader(std::ostream& os) const; + virtual void PrintTrailer(std::ostream& os) const; + + /** Number of uses of this object by other objects. */ + mutable volatile int m_ReferenceCount; + + /** Mutex lock to protect modification to the reference count */ + mutable SimpleFastMutexLock m_ReferenceCountLock; + +private: + LightObject(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + +}; + +} // end namespace igtl + +#endif diff --git a/openigtlink/repo/Source/igtlMacro.h b/openigtlink/repo/Source/igtlMacro.h new file mode 100644 index 0000000..47e91de --- /dev/null +++ b/openigtlink/repo/Source/igtlMacro.h @@ -0,0 +1,1002 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkMacro.h,v $ + Language: C++ + Date: $Date: 2009-05-22 15:29:17 -0400 (Fri, 22 May 2009) $ + Version: $Revision: 4248 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/** + * igtlMacro.h defines standard system-wide macros, constants, and other + * parameters. One of its most important functions is to define macros used + * to interface to instance variables in a standard fashion. For example, + * these macros manage modified time, debugging information, and provide a + * standard interface to set and get instance variables. Macros are + * available for built-in types; for string classe; vector arrays; + * object pointers; and debug, warning, and error printout information. + */ + +#ifndef __igtlMacro_h +#define __igtlMacro_h + +#include "igtlWin32Header.h" +//#include "igtlConfigure.h" + +#include + +// Determine type of string stream to use. +#if !defined(CMAKE_NO_ANSI_STRING_STREAM) +# include +#elif !defined(CMAKE_NO_ANSI_STREAM_HEADERS) +# include +# define IGTL_NO_ANSI_STRING_STREAM +#else +# include +# define IGTL_NO_ANSI_STRING_STREAM +#endif + +/** \namespace igtl + * \brief The "igtl" namespace contains all OpenIGTLink classes. There are several nested namespaces + * within the igtl:: namespace. */ +namespace igtl +{ +} // end namespace igtl - this is here for documentation purposes + +/** A convenience macro marks variables as not being used by a method, + * avoiding compile-time warnings. */ +#define igtlNotUsed(x) + +/** Macro to initialize static constants. This is used frequently to replace + * the use of enum's within a class. Some compilers do not allow an enum of + * one class to be passed as template argument to another class. Other + * uses of this macro as possible. + * + * This is based (verbatim) on the BOOST_STATIC_CONSTANT macro. The original + * Boost documentation is below. + * + * BOOST_STATIC_CONSTANT workaround --------------------------------------- // + * On compilers which don't allow in-class initialization of static integral + * constant members, we must use enums as a workaround if we want the constants + * to be available at compile-time. This macro gives us a convenient way to + * declare such constants. + */ +#if defined(_MSC_VER) && (_MSC_VER <= 1300) +# define IGTL_NO_INCLASS_MEMBER_INITIALIZATION +#endif +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x540) +# define IGTL_NO_INCLASS_MEMBER_INITIALIZATION +#endif +#if defined(__SVR4) && !defined(__SUNPRO_CC) +# define IGTL_NO_INCLASS_MEMBER_INITIALIZATION +#endif + +// A class template like this will not instantiate on GCC 2.95: +// template struct A +// { +// static const int N = 1; +// enum { S = sizeof(A::N) }; +// }; +// We need to use enum for static constants instead. +#if defined(__GNUC__) +# define IGTL_NO_SIZEOF_CONSTANT_LOOKUP +#endif + +#if defined(_MSC_VER) && (_MSC_VER <= 1300) +#define IGTL_NO_SELF_AS_TRAIT_IN_TEMPLATE_ARGUMENTS +#endif + +#if defined(IGTL_NO_INCLASS_MEMBER_INITIALIZATION) || \ + defined(IGTL_NO_SIZEOF_CONSTANT_LOOKUP) +# define igtlStaticConstMacro(name,type,value) enum { name = value } +#else +# define igtlStaticConstMacro(name,type,value) static const type name = value +#endif + +#ifdef IGTL_NO_SELF_AS_TRAIT_IN_TEMPLATE_ARGUMENTS +# define igtlGetStaticConstMacro(name) name +#else +# define igtlGetStaticConstMacro(name) (Self::name) +#endif + +/** Set an input. This defines the Set"name"Input() method */ +#define igtlSetInputMacro(name, type, number) \ + virtual void Set##name##Input(const type *_arg) \ + { \ + igtlDebugMacro("setting input " #name " to " << _arg); \ + if (_arg != static_cast(this->ProcessObject::GetInput( number ))) \ + { \ + this->ProcessObject::SetNthInput( number, const_cast(_arg) ); \ + } \ + } \ + virtual void SetInput##number(const type *_arg) \ + { \ + igtlDebugMacro("setting input " #number " to " << _arg); \ + if (_arg != static_cast(this->ProcessObject::GetInput( number ))) \ + { \ + this->ProcessObject::SetNthInput( number, const_cast(_arg) ); \ + } \ + } + +/** Macro used to redefine a type from the superclass. */ +#define igtlSuperclassTraitMacro(traitnameType) \ + typedef typename Superclass::traitnameType traitnameType; + +/** Get an input. This defines the Get"name"Input() method */ +#define igtlGetInputMacro(name, type, number) \ + virtual const type * Get##name##Input() const \ + { \ + igtlDebugMacro("returning input " << #name " of " << static_cast(this->ProcessObject::GetInput( number )) ); \ + return static_cast(this->ProcessObject::GetInput( number )); \ + } \ + virtual const type * GetInput##number() const \ + { \ + igtlDebugMacro("returning input " << #number " of " << static_cast(this->ProcessObject::GetInput( number )) ); \ + return static_cast(this->ProcessObject::GetInput( number )); \ + } + +/** Set a decorated input. This defines the Set"name"() method. + * It invokes SetInputMacro() and GetInputMacro() for the decorated object */ +#define igtlSetDecoratedInputMacro(name, type, number) \ + igtlSetInputMacro(name, SimpleDataObjectDecorator, number); \ + igtlGetInputMacro(name, SimpleDataObjectDecorator, number); \ + virtual void Set##name(const type &_arg) \ + { \ + typedef SimpleDataObjectDecorator< type > DecoratorType; \ + igtlDebugMacro("setting input " #name " to " << _arg); \ + const DecoratorType * oldInput = \ + static_cast< const DecoratorType * >( \ + this->ProcessObject::GetInput(number) ); \ + if( oldInput && oldInput->Get() == _arg ) \ + { \ + return; \ + } \ + typename DecoratorType::Pointer newInput = DecoratorType::New(); \ + newInput->Set( _arg ); \ + this->Set##name##Input( newInput ); \ + } + +/** Set a decorated input that derives from igtl::Object, but not from + * igtl::DataObject. This defines the Set"name"() method. It invokes + * SetInputMacro() and GetInputMacro() for the decorated object */ +#define igtlSetDecoratedObjectInputMacro(name, type, number) \ + igtlSetInputMacro(name, DataObjectDecorator, number); \ + igtlGetInputMacro(name, DataObjectDecorator, number); \ + virtual void Set##name(const type *_arg) \ + { \ + typedef DataObjectDecorator< type > DecoratorType; \ + igtlDebugMacro("setting input " #name " to " << _arg); \ + const DecoratorType * oldInput = \ + static_cast< const DecoratorType * >( \ + this->ProcessObject::GetInput(number) ); \ + if( oldInput && oldInput->Get() == _arg ) \ + { \ + return; \ + } \ + typename DecoratorType::Pointer newInput = DecoratorType::New(); \ + newInput->Set( _arg ); \ + this->Set##name##Input( newInput ); \ + } + + +/** Set built-in type. Creates member Set"name"() (e.g., SetVisibility()); */ +#define igtlSetMacro(name,type) \ + virtual void Set##name (const type _arg) \ + { \ + igtlDebugMacro("setting " #name " to " << _arg); \ + if (this->m_##name != _arg) \ + { \ + this->m_##name = _arg; \ + } \ + } + +/** Get built-in type. Creates member Get"name"() (e.g., GetVisibility()); */ +#define igtlGetMacro(name,type) \ + virtual type Get##name () \ + { \ + igtlDebugMacro("returning " << #name " of " << this->m_##name ); \ + return this->m_##name; \ + } + +/** Get built-in type. Creates member Get"name"() (e.g., GetVisibility()); + * This is the "const" form of the igtlGetMacro. It should be used unless + * the member can be changed through the "Get" access routine. */ +#define igtlGetConstMacro(name,type) \ + virtual type Get##name () const \ + { \ + igtlDebugMacro("returning " << #name " of " << this->m_##name ); \ + return this->m_##name; \ + } + +/** Get built-in type. Creates member Get"name"() (e.g., GetVisibility()); + * This is the "const" form of the igtlGetMacro. It should be used unless + * the member can be changed through the "Get" access routine. + * This versions returns a const reference to the variable. */ +#define igtlGetConstReferenceMacro(name,type) \ + virtual const type & Get##name () const \ + { \ + igtlDebugMacro("returning " << #name " of " << this->m_##name ); \ + return this->m_##name; \ + } + + /** Set built-in type. Creates member Set"name"() (e.g., SetVisibility()); + * This should be use when the type is an enum. It is use to avoid warnings on + * some compilers with non specified enum types passed to igtlDebugMacro.*/ +#define igtlSetEnumMacro(name,type) \ + virtual void Set##name (const type _arg) \ + { \ + igtlDebugMacro("setting " #name " to " << static_cast(_arg)); \ + if (this->m_##name != _arg) \ + { \ + this->m_##name = _arg; \ + } \ + } + +/** Get built-in type. Creates member Get"name"() (e.g., GetVisibility()); + * This should be use when the type is an enum. It is use to avoid warnings on + * some compilers with non specified enum types passed to igtlDebugMacro.*/ +#define igtlGetEnumMacro(name,type) \ + virtual type Get##name () const \ + { \ + igtlDebugMacro("returning " << #name " of " << static_cast(this->m_##name) ); \ + return this->m_##name; \ + } + +/** Set character string. Creates member Set"name"() + * (e.g., SetFilename(char *)). The macro assumes that + * the class member (name) is declared a type std::string. */ +#define igtlSetStringMacro(name) \ + virtual void Set##name (const char* _arg) \ + { \ + if ( _arg && (_arg == this->m_##name) ) { return;} \ + if (_arg) \ + { \ + this->m_##name = _arg;\ + } \ + else \ + { \ + this->m_##name = ""; \ + } \ + } \ + virtual void Set##name (const std::string & _arg) \ + { \ + this->Set##name( _arg.c_str() ); \ + } \ + + +/** Get character string. Creates member Get"name"() + * (e.g., SetFilename(char *)). The macro assumes that + * the class member (name) is declared as a type std::string. */ +#define igtlGetStringMacro(name) \ + virtual const char* Get##name () const \ + { \ + return this->m_##name.c_str(); \ + } + +/** Set built-in type where value is constrained between min/max limits. + * Create member Set"name"() (e.q., SetRadius()). #defines are + * convienience for clamping open-ended values. */ +#define igtlSetClampMacro(name,type,min,max) \ + virtual void Set##name (type _arg) \ + { \ + igtlDebugMacro("setting " << #name " to " << _arg ); \ + if (this->m_##name != (_argmax?max:_arg))) \ + { \ + this->m_##name = (_argmax?max:_arg)); \ + } \ + } + +/** Set pointer to object; uses Object reference counting methodology. + * Creates method Set"name"() (e.g., SetPoints()). Note that using + * smart pointers requires using real pointers when setting input, + * but returning smart pointers on output. */ +#define igtlSetObjectMacro(name,type) \ + virtual void Set##name (type* _arg) \ + { \ + igtlDebugMacro("setting " << #name " to " << _arg ); \ + if (this->m_##name != _arg) \ + { \ + this->m_##name = _arg; \ + } \ + } + +/** Get a smart pointer to an object. Creates the member + * Get"name"() (e.g., GetPoints()). */ +#define igtlGetObjectMacro(name,type) \ + virtual type * Get##name () \ + { \ + igtlDebugMacro("returning " #name " address " << this->m_##name ); \ + return this->m_##name.GetPointer(); \ + } + +/** Set const pointer to object; uses Object reference counting methodology. + * Creates method Set"name"() (e.g., SetPoints()). Note that using + * smart pointers requires using real pointers when setting input, + * but returning smart pointers on output. */ +#define igtlSetConstObjectMacro(name,type) \ + virtual void Set##name (const type* _arg) \ + { \ + igtlDebugMacro("setting " << #name " to " << _arg ); \ + if (this->m_##name != _arg) \ + { \ + this->m_##name = _arg; \ + } \ + } + + +/** Get a smart const pointer to an object. Creates the member + * Get"name"() (e.g., GetPoints()). */ +#define igtlGetConstObjectMacro(name,type) \ + virtual const type * Get##name () const \ + { \ + igtlDebugMacro("returning " #name " address " << this->m_##name ); \ + return this->m_##name.GetPointer(); \ + } + +/** Get a const reference to a smart pointer to an object. + * Creates the member Get"name"() (e.g., GetPoints()). */ +#define igtlGetConstReferenceObjectMacro(name,type) \ + virtual const typename type::Pointer & Get##name () const \ + { \ + igtlDebugMacro("returning " #name " address " << this->m_##name ); \ + return this->m_##name; \ + } + +/** Create members "name"On() and "name"Off() (e.g., DebugOn() DebugOff()). + * Set method must be defined to use this macro. */ +#define igtlBooleanMacro(name) \ + virtual void name##On () { this->Set##name(true);} \ + virtual void name##Off () { this->Set##name(false);} + +/** General set vector macro creates a single method that copies specified + * number of values into object. + * Examples: void SetColor(c,3) */ +#define igtlSetVectorMacro(name,type,count) \ + virtual void Set##name(type data[]) \ + { \ + unsigned int i; \ + for (i=0; im_##name[i] ) { break; }} \ + if ( i < count ) \ + { \ + for (i=0; im_##name[i] = data[i]; }\ + } \ + } + +/** Get vector macro. Returns pointer to type (i.e., array of type). + * This is for efficiency. */ +#define igtlGetVectorMacro(name,type,count) \ + virtual type *Get##name () const \ + { \ + return this->m_##name; \ + } + +/** Define two object creation methods. The first method, New(), + * creates an object from a class, potentially deferring to a factory. + * The second method, CreateAnother(), creates an object from an + * instance, potentially deferring to a factory. This second method + * allows you to create an instance of an object that is exactly the + * same type as the referring object. This is useful in cases where + * an object has been cast back to a base class. + * + * These creation methods first try asking the object factory to create + * an instance, and then default to the standard "new" operator if the + * factory fails. + * + * These routines assigns the raw pointer to a smart pointer and then call + * UnRegister() on the rawPtr to compensate for LightObject's constructor + * initializing an object's reference count to 1 (needed for proper + * initialization of process objects and data objects cycles). */ +#define igtlNewMacro(x) \ +static Pointer New(void) \ +{ \ + Pointer smartPtr = ::igtl::ObjectFactory::Create(); \ + if(smartPtr.GetPointer() == NULL) \ + { \ + smartPtr = new x; \ + } \ + smartPtr->UnRegister(); \ + return smartPtr; \ +} \ +::igtl::LightObject::Pointer CreateAnother(void) const override\ +{ \ + return x::New().GetPointer(); \ +} \ + + +/** Define two object creation methods. The first method, New(), + * creates an object from a class but does not defer to a factory. + * The second method, CreateAnother(), creates an object from an + * instance, again without deferring to a factory. This second method + * allows you to create an instance of an object that is exactly the + * same type as the referring object. This is useful in cases where + * an object has been cast back to a base class. + * + * These creation methods first try asking the object factory to create + * an instance, and then default to the standard "new" operator if the + * factory fails. + * + * These routines assigns the raw pointer to a smart pointer and then call + * UnRegister() on the rawPtr to compensate for LightObject's constructor + * initializing an object's reference count to 1 (needed for proper + * initialization of process objects and data objects cycles). */ +#define igtlFactorylessNewMacro(x) \ +static Pointer New(void) \ +{ \ + Pointer smartPtr; \ + x *rawPtr = new x; \ + smartPtr = rawPtr; \ + rawPtr->UnRegister(); \ + return smartPtr; \ +} \ + virtual ::igtl::LightObject::Pointer CreateAnother(void) const \ +{ \ + ::igtl::LightObject::Pointer smartPtr; \ + smartPtr = x::New().GetPointer(); \ + return smartPtr; \ +} + +/** Macro used to add standard methods and typedef to all classes, mainly type + * information. */ +#define igtlTypeMacro(thisClass,superclass) \ + const char *GetNameOfClass() const override {return #thisClass;} \ + typedef thisClass Self; \ + typedef superclass Superclass; \ + typedef igtl::SmartPointer Pointer; \ + typedef igtl::SmartPointer ConstPointer; + +//namespace igtl +//{ +///** +// * The following is used to output debug, warning, and error messages. +// * Use a global function which actually calls: +// * OutputWindow::GetInstance()->DisplayText(); +// * This is to avoid Object #include of OutputWindow +// * while OutputWindow #includes Object. */ +//extern IGTLCommon_EXPORT void OutputWindowDisplayText(const char*); +//extern IGTLCommon_EXPORT void OutputWindowDisplayErrorText(const char*); +//extern IGTLCommon_EXPORT void OutputWindowDisplayWarningText(const char*); +//extern IGTLCommon_EXPORT void OutputWindowDisplayGenericOutputText(const char*); +//extern IGTLCommon_EXPORT void OutputWindowDisplayDebugText(const char*); +//} // end namespace igtl + +/** This macro is used to print debug (or other information). They are + * also used to catch errors, etc. Example usage looks like: + * igtlDebugMacro(<< "this is debug info" << this->SomeVariable); */ +#if defined(IGTL_LEAN_AND_MEAN) || defined(__BORLANDC__) +#define igtlDebugMacro(x) +#else +#define igtlDebugMacro(x) \ + { if (this->GetDebug() /*&& ::igtl::Object::GetGlobalWarningDisplay()*/) \ + { ::igtl::OStringStream igtlmsg; \ + igtlmsg << "Debug: In " __FILE__ ", line " << __LINE__ << "\n" \ + << this->GetNameOfClass() << " (" << this << "): " x \ + << "\n\n"; \ + std::cerr << igtlmsg.str(); /*::igtl::OutputWindowDisplayDebugText(igtlmsg.str().c_str());*/} \ +} +#endif + + +/** This macro is used to print warning information (i.e., unusual circumstance + * but not necessarily fatal.) Example usage looks like: + * igtlWarningMacro(<< "this is warning info" << this->SomeVariable); */ +#ifdef IGTL_LEAN_AND_MEAN +#define igtlWarningMacro(x) +#else +#define igtlWarningMacro(x) \ + { if ( 1/*::igtl::Object::GetGlobalWarningDisplay()*/) \ + { ::igtl::OStringStream igtlmsg; \ + igtlmsg << "WARNING: In " __FILE__ ", line " << __LINE__ << "\n" \ + << this->GetNameOfClass() << " (" << this << "): " x \ + << "\n\n"; \ + std::cerr << igtlmsg.str(); /*::igtl::OutputWindowDisplayWarningText(igtlmsg.str().c_str());*/} \ +} +#endif + +namespace igtl +{ + +/** + * igtl::OStringStream wrapper to hide differences between + * std::ostringstream and the old ostrstream. Necessary for + * portability. + */ +#if !defined(IGTL_NO_ANSI_STRING_STREAM) +class OStringStream: public std::ostringstream +{ +public: + OStringStream() {} +private: + OStringStream(const OStringStream&); + void operator=(const OStringStream&); +}; +#else +namespace OStringStreamDetail +{ + class Cleanup + { + public: + Cleanup(std::ostrstream& ostr): m_OStrStream(ostr) {} + ~Cleanup() { m_OStrStream.rdbuf()->freeze(0); } + static void IgnoreUnusedVariable(const Cleanup&) {} + protected: + std::ostrstream& m_OStrStream; + }; +}//namespace OStringStreamDetail + +class OStringStream: public std::ostrstream +{ +public: + typedef std::ostrstream Superclass; + OStringStream() {} + std::string str() + { + OStringStreamDetail::Cleanup cleanup(*this); + OStringStreamDetail::Cleanup::IgnoreUnusedVariable(cleanup); + int pcount = this->pcount(); + const char* ptr = this->Superclass::str(); + return std::string(ptr?ptr:"", pcount); + } +private: + OStringStream(const OStringStream&); + void operator=(const OStringStream&); +}; +#endif + +}//namespace igtl + +#if defined(IGTL_CPP_FUNCTION) + #if defined(__BORLANDC__) + #define IGTL_LOCATION __FUNC__ + #elif defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(CABLE_CONFIGURATION) && !defined(CSWIG) + #define IGTL_LOCATION __FUNCSIG__ + #elif defined(__GNUC__) + #define IGTL_LOCATION __PRETTY_FUNCTION__ + #else + #define IGTL_LOCATION __FUNCTION__ + #endif +#else + #define IGTL_LOCATION "unknown" +#endif + +#define igtlExceptionMacro(x) \ + { \ + ::igtl::OStringStream igtlmsg; \ + igtlmsg << "Debug: In " __FILE__ ", line " << __LINE__ << "\n" \ + << this->GetNameOfClass() << " (" << this << "): " x \ + << "\n\n"; \ + std::cerr << igtlmsg.str(); /*::igtl::OutputWindowDisplayDebugText(igtlmsg.str().c_str());*/ \ +} + +#define igtlErrorMacro(x) \ + { \ + ::igtl::OStringStream igtlmsg; \ + igtlmsg << "Debug: In " __FILE__ ", line " << __LINE__ << "\n" \ + << this->GetNameOfClass() << " (" << this << "): " x \ + << "\n\n"; \ + std::cerr << igtlmsg.str(); /*::igtl::OutputWindowDisplayDebugText(igtlmsg.str().c_str());*/ \ +} + + +#ifdef IGTL_LEAN_AND_MEAN +#define igtlGenericOutputMacro(x) +#else +#define igtlGenericOutputMacro(x) \ + { if (1/*::igtl::Object::GetGlobalWarningDisplay()*/) \ + { ::igtl::OStringStream igtlmsg; \ + igtlmsg << "WARNING: In " __FILE__ ", line " << __LINE__ << "\n" \ + x << "\n\n"; \ + std::cerr << igtlmsg.str();/*::igtl::OutputWindowDisplayGenericOutputText(igtlmsg.str().c_str());*/} \ +} +#endif + + + +//---------------------------------------------------------------------------- +// Macros for simplifying the use of logging +// +#define igtlLogMacro( x, y) \ +{ \ + if (this->GetLogger() ) \ + { \ + this->GetLogger()->Write(::igtl::LoggerBase::x, y); \ + } \ +} + + +#define igtlLogMacroStatic( obj, x, y) \ +{ \ + if (obj->GetLogger() ) \ + { \ + obj->GetLogger()->Write(::igtl::LoggerBase::x, y); \ + } \ +} + + +//---------------------------------------------------------------------------- +// Setup legacy code policy. +// +// CMake options IGTL_LEGACY_REMOVE and IGTL_LEGACY_SILENT are converted +// to definitions (or non-defs) in igtlConfigure.h and tested below. +// They may be used to completely remove legacy code or silence the +// warnings. The default is to warn about their use. +// +// Source files that test the legacy code may define IGTL_LEGACY_TEST +// like this: +// +// #define IGTL_LEGACY_TEST +// #include "igtlClassWithDeprecatedMethod.h" +// +// in order to silence the warnings for calling deprecated methods. +// No other source files in IGTL should call the methods since they are +// provided only for compatibility with older user code. + +// Define igtlLegacyMacro to mark legacy methods where they are +// declared in their class. Example usage: +// +// // @deprecated Replaced by MyOtherMethod() as of IGTL 2.0. +// igtlLegacyMacro(void MyMethod()); +#if defined(IGTL_LEGACY_REMOVE) +// Remove legacy methods completely. Put a bogus declaration in +// place to avoid stray semicolons because this is an error for some +// compilers. Using a class forward declaration allows any number +// of repeats in any context without generating unique names. +# define igtlLegacyMacro(method) class igtlLegacyMethodRemoved /* no ';' */ +#elif defined(IGTL_LEGACY_SILENT) || defined(IGTL_LEGACY_TEST) || defined(CSWIG) + // Provide legacy methods with no warnings. +# define igtlLegacyMacro(method) method +#else + // Setup compile-time warnings for uses of deprecated methods if + // possible on this compiler. +# if defined(__GNUC__) && !defined(__INTEL_COMPILER) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define igtlLegacyMacro(method) method __attribute__((deprecated)) +# elif defined(_MSC_VER) && _MSC_VER >= 1300 +# define igtlLegacyMacro(method) __declspec(deprecated) method +# else +# define igtlLegacyMacro(method) method +# endif +#endif + +// Macros to create runtime deprecation warning messages in function +// bodies. Example usage: +// +// void igtlMyClass::MyOldMethod() +// { +// igtlLegacyBodyMacro(igtlMyClass::MyOldMethod, 2.0); +// } +// +// void igtlMyClass::MyMethod() +// { +// igtlLegacyReplaceBodyMacro(igtlMyClass::MyMethod, 2.0, +// igtlMyClass::MyOtherMethod); +// } +#if defined(IGTL_LEGACY_REMOVE) || defined(IGTL_LEGACY_SILENT) +# define igtlLegacyBodyMacro(method, version) +# define igtlLegacyReplaceBodyMacro(method, version, replace) +#else +# define igtlLegacyBodyMacro(method, version) \ + igtlWarningMacro(#method " was deprecated for IGTL " #version " and will be removed in a future version.") +# define igtlLegacyReplaceBodyMacro(method, version, replace) \ + igtlWarningMacro(#method " was deprecated for IGTL " #version " and will be removed in a future version. Use " #replace " instead.") +#endif + +#if defined(__INTEL_COMPILER) +# pragma warning (disable: 193) /* #if testing undefined identifier */ +#endif + +//============================================================================= +/* Choose a way to prevent template instantiation on this platform. + - IGTL_TEMPLATE_DO_NOT_INSTANTIATE = use #pragma do_not_instantiate to + prevent instantiation + - IGTL_TEMPLATE_EXTERN = use extern template to prevent instantiation + + Note that VS 6 supports extern template instantiation but it is + hard to block the resulting warning because its stream headers + re-enable it. Therefore we just disable support for now. +*/ +#if defined(__sgi) && defined(_COMPILER_VERSION) +# define IGTL_TEMPLATE_DO_NOT_INSTANTIATE 1 +#elif defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 700 +# define IGTL_TEMPLATE_EXTERN 1 +#elif defined(__GNUC__) && __GNUC__ >= 3 +# define IGTL_TEMPLATE_EXTERN 1 +#elif defined(_MSC_VER) && _MSC_VER >= 1300 +# define IGTL_TEMPLATE_EXTERN 1 +#endif +#if !defined(IGTL_TEMPLATE_DO_NOT_INSTANTIATE) +# define IGTL_TEMPLATE_DO_NOT_INSTANTIATE 0 +#endif +#if !defined(IGTL_TEMPLATE_EXTERN) +# define IGTL_TEMPLATE_EXTERN 0 +#endif + +/* Define a macro to explicitly instantiate a template. + - IGTL_TEMPLATE_EXPORT(X) = + Explicitly instantiate X, where X is of the form N(a1[,a2...,aN]). + examples: IGTL_TEMPLATE_EXPORT(1(class Foo)) + IGTL_TEMPLATE_EXPORT(2(class Bar)) + Use one level of expansion delay to allow user code to have + a macro determining the number of arguments. */ +#define IGTL_TEMPLATE_EXPORT(x) IGTL_TEMPLATE_EXPORT_DELAY(x) +#define IGTL_TEMPLATE_EXPORT_DELAY(x) template IGTL_TEMPLATE_##x; + +/* Define a macro to prevent template instantiations. + - IGTL_TEMPLATE_IMPORT(X) = + Prevent instantiation of X, where X is of the form N(a1[,a2...,aN]). + examples: IGTL_TEMPLATE_IMPORT(1(class Foo)) + IGTL_TEMPLATE_IMPORT(2(class Bar)) + Use one level of expansion delay to allow user code to have + a macro determining the number of arguments. +*/ +#if IGTL_TEMPLATE_EXTERN +# define IGTL_TEMPLATE_IMPORT_DELAY(x) extern template IGTL_TEMPLATE_##x; +# if defined(_MSC_VER) +# pragma warning (disable: 4231) /* extern template extension */ +# endif +#elif IGTL_TEMPLATE_DO_NOT_INSTANTIATE +# define IGTL_TEMPLATE_IMPORT_DELAY(x) \ + IGTL_TEMPLATE_IMPORT_IMPL(do_not_instantiate IGTL_TEMPLATE_##x) +# define IGTL_TEMPLATE_IMPORT_IMPL(x) _Pragma(#x) +#endif +#if defined(IGTL_TEMPLATE_IMPORT_DELAY) +# define IGTL_TEMPLATE_IMPORT(x) IGTL_TEMPLATE_IMPORT_DELAY(x) +# define IGTL_TEMPLATE_IMPORT_WORKS 1 +#else +# define IGTL_TEMPLATE_IMPORT(x) +# define IGTL_TEMPLATE_IMPORT_WORKS 0 +#endif + +/* Define macros to export and import template instantiations. These + depend on each class providing a macro defining the instantiations + given template arguments in X. The argument X is of the form + N(a1[,a2...,aN]). The argument Y is a valid preprocessing token + unique to the template arguments given in X. Typical usage is + + IGTL_EXPORT_TEMPLATE(igtlfoo_EXPORT, Foo, (int), I) + IGTL_EXPORT_TEMPLATE(igtlfoo_EXPORT, Bar, (int, char), IC) + + The IGTL_TEMPLATE_ macro should be defined in igtl.h and + is of the following form: + + #define IGTL_TEMPLATE_(_, EXPORT, x, y) namespace igtl { \ + _((class EXPORT < IGTL_TEMPLATE_ x >)) \ + namespace Templates { typedef < IGTL_TEMPLATE_ x > ##y; }\ + } + + The argument "_" will be replaced by another macro such as + IGTL_TEMPLATE_EXPORT or IGTL_TEMPLATE_IMPORT, so it should be used as + if calling one of these macros. The argument "EXPORT" will be + replaced by a dllexport/dllimport macro such as IGTLCommon_EXPORT. + The argument "x" is a paren-enclosed list of template arguments. + The argument "y" is a preprocessing token corresponding to the + given template arguments and should be used to construct typedef + names for the instantiations. + + Note the use of IGTL_TEMPLATE_, where is the number of + template arguments for the class template. Note also that the + number of template arguments is usually the length of the list + nested within the inner parentheses, so the instantiation is listed + with the form (...). Example definitions: + + #define IGTL_TEMPLATE_Foo(_, EXPORT, x, y) namespace igtl { \ + _(1(class EXPORT Foo< IGTL_TEMPLATE_1 x >)) \ + _(1(EXPORT std::ostream& operator<<(std::ostream&, \ + const Foo< IGTL_TEMPLATE_1 x >&))) \ + namespace Templates { typedef Foo< IGTL_TEMPLATE_1 x > Foo##y; }\ + } + + #define IGTL_TEMPLATE_Bar(_, EXPORT, x, y) namespace igtl { \ + _(2(class EXPORT Bar< IGTL_TEMPLATE_2 x >)) \ + _(1(EXPORT std::ostream& operator<<(std::ostream&, \ + const Bar< IGTL_TEMPLATE_2 x >&))) \ + namespace Templates { typedef Bar< IGTL_TEMPLATE_2 x > Bar##y; }\ + } + + Note that in the stream operator for template Bar there is a "1" at + the beginning even though two arguments are taken. This is because + the expression "IGTL_TEMPLATE_2 x" is contained inside the + parentheses of the function signature which protects the resulting + comma from separating macro arguments. Therefore the nested + parentheses contain a list of only one macro argument. + + The IGTL_EMPTY macro used in these definitions is a hack to work + around a VS 6.0 preprocessor bug when EXPORT is empty. +*/ +#define IGTL_EXPORT_TEMPLATE(EXPORT, c, x, y) \ + IGTL_TEMPLATE_##c(IGTL_TEMPLATE_EXPORT, EXPORT IGTL_EMPTY, x, y) +#define IGTL_IMPORT_TEMPLATE(EXPORT, c, x, y) \ + IGTL_TEMPLATE_##c(IGTL_TEMPLATE_IMPORT, EXPORT IGTL_EMPTY, x, y) +#define IGTL_EMPTY + +/* Define macros to support passing a variable number of arguments + throug other macros. This is used by IGTL_TEMPLATE_EXPORT, + IGTL_TEMPLATE_IMPORT, and by each template's instantiation + macro. */ +#define IGTL_TEMPLATE_1(x1) x1 +#define IGTL_TEMPLATE_2(x1,x2) x1,x2 +#define IGTL_TEMPLATE_3(x1,x2,x3) x1,x2,x3 +#define IGTL_TEMPLATE_4(x1,x2,x3,x4) x1,x2,x3,x4 +#define IGTL_TEMPLATE_5(x1,x2,x3,x4,x5) x1,x2,x3,x4,x5 +#define IGTL_TEMPLATE_6(x1,x2,x3,x4,x5,x6) x1,x2,x3,x4,x5,x6 +#define IGTL_TEMPLATE_7(x1,x2,x3,x4,x5,x6,x7) x1,x2,x3,x4,x5,x6,x7 +#define IGTL_TEMPLATE_8(x1,x2,x3,x4,x5,x6,x7,x8) x1,x2,x3,x4,x5,x6,x7,x8 +#define IGTL_TEMPLATE_9(x1,x2,x3,x4,x5,x6,x7,x8,x9) x1,x2,x3,x4,x5,x6,x7,x8,x9 + +/* In order to support both implicit and explicit instantation a .h + file needs to know whether it should include its .txx file + containing the template definitions. Define a macro to tell + it. Typical usage in igtlFoo.h: + #if IGTL_TEMPLATE_TXX + # include "igtlFoo.txx" + #endif +*/ +#if defined(IGTL_MANUAL_INSTANTIATION) +# define IGTL_TEMPLATE_TXX 0 +#else +# define IGTL_TEMPLATE_TXX !(IGTL_TEMPLATE_CXX || IGTL_TEMPLATE_TYPE) +#endif + +/* All explicit instantiation source files define IGTL_TEMPLATE_CXX. + Define IGTL_MANUAL_INSTANTIATION to tell .h files that have not been + converted to this explicit instantiation scheme to not include + their .txx files. Also disable warnings that commonly occur in + these files but are not useful. */ +#if IGTL_TEMPLATE_CXX +# undef IGTL_MANUAL_INSTANTIATION +# define IGTL_MANUAL_INSTANTIATION +# if defined(_MSC_VER) +# pragma warning (disable: 4275) /* non dll-interface base */ +# pragma warning (disable: 4661) /* no definition available */ +# endif +#endif +//============================================================================= + +/* Define macros to export and import template instantiations for each + library in IGTL. */ +#define IGTL_EXPORT_IGTLCommon(c, x, n) \ + IGTL_EXPORT_TEMPLATE(IGTLCommon_EXPORT, c, x, n) +#define IGTL_IMPORT_IGTLCommon(c, x, n) \ + IGTL_IMPORT_TEMPLATE(IGTLCommon_EXPORT, c, x, n) + +/* Define a macro to decide whether to block instantiation of IGTL + templates. They should be blocked only if the platform supports + blocking template instantiation and the explicit instantiations are + available. + + - IGTL_TEMPLATE_EXPLICIT = + Whether to include "XXX+-.h" from "XXX.h" to prevent implicit + instantiations of templates explicitly instantiated elsewhere. + Typical usage in igtlFoo.h: + #if IGTL_TEMPLATE_EXPLICIT + # include "igtlFoo+-.h" + #endif +*/ +#if IGTL_TEMPLATE_IMPORT_WORKS && defined(IGTL_EXPLICIT_INSTANTIATION) +# define IGTL_TEMPLATE_EXPLICIT !IGTL_TEMPLATE_CXX +#else +# define IGTL_TEMPLATE_EXPLICIT 0 +#endif + + +//---------------------------------------------------------------------------- +// Macro to declare that a function does not return. __attribute__((noreturn)) +// On some compiler, functions that do not return (ex: exit(0)) must +// have the noreturn attribute. Otherwise, a warning is raised. Use +// that macro to avoid those warnings. GCC defines the attribute +// noreturn for versions 2.5 and higher. +#if defined(__GNUC__) +# if (((__GNUC__ == 2) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 3)) +# define IGTL_NO_RETURN \ + __attribute__ ((noreturn)) +# endif +#else +# define IGTL_NO_RETURN +#endif + + +#ifdef IGTL_USE_TEMPLATE_META_PROGRAMMING_LOOP_UNROLLING +//-------------------------------------------------------------------------------- +// Helper macros for Template Meta-Programming techniques of for-loops unrolling +//-------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------- +// Macro that generates an unrolled for loop for assigning elements of one array +// to elements of another array The array are assumed to be of same length +// (dimension), and this is also assumed to be the value of NumberOfIterations. +// No verification of size is performed. Casting is perfomed as part of the +// assignment, by using the DestinationElementType as the casting type. +// Source and destination array types must have defined opearator[] in their API. +#define igtlFoorLoopAssignmentMacro(DestinationType,SourceType,DestinationElementType,DestinationArray,SourceArray,NumberOfIterations) \ + for(unsigned int i=0;i < NumberOfIterations; ++i) \ + { \ + DestinationArray[i] = static_cast< DestinationElementType >( SourceArray[i] ); \ + } + +//-------------------------------------------------------------------------------- +// Macro that generates an unrolled for loop for rounding and assigning +// elements of one array to elements of another array The array are assumed to +// be of same length (dimension), and this is also assumed to be the value of +// NumberOfIterations. No verification of size is performed. Casting is +// perfomed as part of the assignment, by using the DestinationElementType as +// the casting type. +// Source and destination array types must have defined opearator[] in their API. +#define igtlFoorLoopRoundingAndAssignmentMacro(DestinationType,SourceType,DestinationElementType,DestinationArray,SourceArray,NumberOfIterations) \ + for(unsigned int i=0;i < NumberOfIterations; ++i) \ + { \ + DestinationArray[i] = static_cast< DestinationElementType >( vnl_math_rnd( SourceArray[i] ) ); \ + } + +#endif +// end of Template Meta Programming helper macros + +//namespace igtl +//{ +///** +// * The following is used as a convenience macro to define the +// * functions required for C++ range based for loops */ +//} // end namespace igtl + +///** +// * The following is used as a convenience macro to define the +// * functions required for C++ range based for loops */ +#define igtlRangeBasedForHeaderMemberMacro(varType) \ + varType::iterator begin(); \ + varType::iterator end(); \ + varType::const_iterator begin() const; \ + varType::const_iterator end() const; \ + varType::reverse_iterator rbegin(); \ + varType::reverse_iterator rend(); \ + varType::const_reverse_iterator rbegin() const; \ + varType::const_reverse_iterator rend() const; + +#define igtlRangeBasedForHeaderExternalMacro(classType, varType, exportDecl) \ + exportDecl varType::iterator begin(classType& list); \ + exportDecl varType::iterator end(classType& list); \ + exportDecl varType::const_iterator begin(const classType& list); \ + exportDecl varType::const_iterator end(const classType& list); \ + exportDecl varType::reverse_iterator rbegin(classType& list); \ + exportDecl varType::reverse_iterator rend(classType& list); \ + exportDecl varType::const_reverse_iterator rbegin(const classType& list); \ + exportDecl varType::const_reverse_iterator rend(const classType& list); + +#define igtlRangeBasedForBodyMacro(classType, varType, memberVar) \ + varType::iterator classType::begin() { return memberVar.begin(); } \ + varType::iterator classType::end() { return memberVar.end(); } \ + varType::const_iterator classType::begin() const { return memberVar.begin(); } \ + varType::const_iterator classType::end() const { return memberVar.end(); } \ + varType::reverse_iterator classType::rbegin() { return memberVar.rbegin(); } \ + varType::reverse_iterator classType::rend() { return memberVar.rend(); } \ + varType::const_reverse_iterator classType::rbegin() const { return memberVar.rbegin(); } \ + varType::const_reverse_iterator classType::rend() const { return memberVar.rend(); } \ + varType::iterator begin(classType& list) { return list.begin(); } \ + varType::iterator end(classType& list) { return list.end(); } \ + varType::const_iterator begin(const classType& list) { return list.begin(); } \ + varType::const_iterator end(const classType& list) { return list.end(); } \ + varType::reverse_iterator rbegin(classType& list) { return list.rbegin(); } \ + varType::reverse_iterator rend(classType& list) { return list.rend(); } \ + varType::const_reverse_iterator rbegin(const classType& list) { return list.rbegin(); } \ + varType::const_reverse_iterator rend(const classType& list) { return list.rend(); } + +#endif //end of igtlMacro.h diff --git a/openigtlink/repo/Source/igtlMath.cxx b/openigtlink/repo/Source/igtlMath.cxx new file mode 100644 index 0000000..8198aba --- /dev/null +++ b/openigtlink/repo/Source/igtlMath.cxx @@ -0,0 +1,184 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include "igtlWin32Header.h" +#include "igtlMath.h" + +namespace igtl { + +void IGTLCommon_EXPORT PrintMatrix(igtl::Matrix4x4 &matrix) +{ + std::cout << "=============" << std::endl; + std::cout << matrix[0][0] << ", " << matrix[0][1] << ", " << matrix[0][2] << ", " << matrix[0][3] << std::endl; + std::cout << matrix[1][0] << ", " << matrix[1][1] << ", " << matrix[1][2] << ", " << matrix[1][3] << std::endl; + std::cout << matrix[2][0] << ", " << matrix[2][1] << ", " << matrix[2][2] << ", " << matrix[2][3] << std::endl; + std::cout << matrix[3][0] << ", " << matrix[3][1] << ", " << matrix[3][2] << ", " << matrix[3][3] << std::endl; + std::cout << "=============" << std::endl; +} + +void IGTLCommon_EXPORT PrintVector3(float v[3]) +{ + std::cout << v[0] << ", " << v[1] << ", " << v[2] << std::endl; +} + +void IGTLCommon_EXPORT PrintVector3(float x, float y, float z) +{ + std::cout << x << ", " << y << ", " << z << std::endl; +} + +void IGTLCommon_EXPORT PrintVector4(float v[4]) +{ + std::cout << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << std::endl; +} + +void IGTLCommon_EXPORT PrintVector4(float x, float y, float z, float w) +{ + std::cout << x << ", " << y << ", " << z << ", " << w << std::endl; +} + +void IGTLCommon_EXPORT QuaternionToMatrix(float* q, Matrix4x4& m) +{ + + // normalize + float mod = sqrt(q[0]*q[0]+q[1]*q[1]+q[2]*q[2]+q[3]*q[3]); + + // convert to the matrix + const float x = q[0] / mod; + const float y = q[1] / mod; + const float z = q[2] / mod; + const float w = q[3] / mod; + + const float xx = x * x * 2.0; + const float xy = x * y * 2.0; + const float xz = x * z * 2.0; + const float xw = x * w * 2.0; + const float yy = y * y * 2.0; + const float yz = y * z * 2.0; + const float yw = y * w * 2.0; + const float zz = z * z * 2.0; + const float zw = z * w * 2.0; + + m[0][0] = 1.0 - (yy + zz); + m[1][0] = xy + zw; + m[2][0] = xz - yw; + + m[0][1] = xy - zw; + m[1][1] = 1.0 - (xx + zz); + m[2][1] = yz + xw; + + m[0][2] = xz + yw; + m[1][2] = yz - xw; + m[2][2] = 1.0 - (xx + yy); + + m[3][0] = 0.0; + m[3][1] = 0.0; + m[3][2] = 0.0; + m[3][3] = 1.0; + + m[0][3] = 0.0; + m[1][3] = 0.0; + m[2][3] = 0.0; + +} + + +void IGTLCommon_EXPORT MatrixToQuaternion(Matrix4x4& m, float* q) +{ + float trace = m[0][0] + m[1][1] + m[2][2]; + + if ( trace > 0.0 ) + { + + float s = 0.5f / sqrt(trace + 1.0f); + + q[3] = 0.25f / s; + q[0] = ( m[2][1] - m[1][2] ) * s; + q[1] = ( m[0][2] - m[2][0] ) * s; + q[2] = ( m[1][0] - m[0][1] ) * s; + + } + else + { + + if ( m[0][0] > m[1][1] && m[0][0] > m[2][2] ) + { + + float s = 2.0f * sqrt( 1.0f + m[0][0] - m[1][1] - m[2][2]); + + q[3] = (m[2][1] - m[1][2] ) / s; + q[0] = 0.25f * s; + q[1] = (m[0][1] + m[1][0] ) / s; + q[2] = (m[0][2] + m[2][0] ) / s; + + } + else if (m[1][1] > m[2][2]) + { + + float s = 2.0f * sqrt( 1.0f + m[1][1] - m[0][0] - m[2][2]); + + q[3] = (m[0][2] - m[2][0] ) / s; + q[0] = (m[0][1] + m[1][0] ) / s; + q[1] = 0.25f * s; + q[2] = (m[1][2] + m[2][1] ) / s; + + } + else + { + + float s = 2.0f * sqrt( 1.0f + m[2][2] - m[0][0] - m[1][1] ); + + q[3] = (m[1][0] - m[0][1] ) / s; + q[0] = (m[0][2] + m[2][0] ) / s; + q[1] = (m[1][2] + m[2][1] ) / s; + q[2] = 0.25f * s; + + } + } +} + + + +void IGTLCommon_EXPORT Cross(float *a, float *b, float *c) +{ + a[0] = b[1]*c[2] - c[1]*b[2]; + a[1] = c[0]*b[2] - b[0]*c[2]; + a[2] = b[0]*c[1] - c[0]*b[1]; +} + +void IGTLCommon_EXPORT IdentityMatrix(igtl::Matrix4x4 &matrix) +{ + matrix[0][0] = 1.0; + matrix[1][0] = 0.0; + matrix[2][0] = 0.0; + matrix[3][0] = 0.0; + + matrix[0][1] = 0.0; + matrix[1][1] = 1.0; + matrix[2][1] = 0.0; + matrix[3][1] = 0.0; + + matrix[0][2] = 0.0; + matrix[1][2] = 0.0; + matrix[2][2] = 1.0; + matrix[3][2] = 0.0; + + matrix[0][3] = 0.0; + matrix[1][3] = 0.0; + matrix[2][3] = 0.0; + matrix[3][3] = 1.0; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlMath.h b/openigtlink/repo/Source/igtlMath.h new file mode 100644 index 0000000..90b82e1 --- /dev/null +++ b/openigtlink/repo/Source/igtlMath.h @@ -0,0 +1,60 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlMath_h +#define __igtlMath_h + +#include "igtlWin32Header.h" + +namespace igtl +{ + +typedef float Matrix4x4[4][4]; + +/// Prints out a 4-by-4 matrix on the standard output. +void IGTLCommon_EXPORT PrintMatrix(igtl::Matrix4x4 &matrix); + +/// Prints out a 3-element vector on the standard output. +void IGTLCommon_EXPORT PrintVector3(float v[3]); + +/// Prints out a 3-element vector on the standard output. +void IGTLCommon_EXPORT PrintVector3(float x, float y, float z); + +/// Prints out a 4-element vector on the standard output. +void IGTLCommon_EXPORT PrintVector4(float v[4]); + +/// Prints out a 4-element vector on the standard output. +void IGTLCommon_EXPORT PrintVector4(float x, float y, float z, float w); + +/// Converts a quaternion to a 3-by-3 rotation matrix. Only the 3-by-3 rotation matrix part +/// in the 4-by-4 matrix is used. +void IGTLCommon_EXPORT QuaternionToMatrix(float* q, Matrix4x4& m); + +/// Converts a 3-by-3 rotation matrix a quaternion. Only the 3-by-3 rotation matrix part +/// in the 4-by-4 matrix is used. +void IGTLCommon_EXPORT MatrixToQuaternion(Matrix4x4& m, float* q); + +/// Calculates the cross products of 3-element vectors 'b' and 'c'. The result is substituted into +/// a 3-element vector a. +void IGTLCommon_EXPORT Cross(float *a, float *b, float *c); + +/// Initialize a 4-by-4 matrix as an identity matrix. +void IGTLCommon_EXPORT IdentityMatrix(igtl::Matrix4x4 &matrix); + +} + +#endif // __igtlMath_h + + + diff --git a/openigtlink/repo/Source/igtlMessageBase.cxx b/openigtlink/repo/Source/igtlMessageBase.cxx new file mode 100644 index 0000000..e7ee697 --- /dev/null +++ b/openigtlink/repo/Source/igtlMessageBase.cxx @@ -0,0 +1,1023 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlMessageBase.h" +#include "igtlMessageFactory.h" +#include "igtl_header.h" +#include "igtl_util.h" + +#include +#include +#include +#include + +namespace +{ + static const int META_DATA_INDEX_COUNT_SIZE = sizeof(igtlUint16); +} + +namespace igtl +{ + +MessageBase::MessageBase() + : Object() + , m_MessageSize(0) + , m_Header(NULL) + , m_Body(NULL) + , m_Content(NULL) + , m_BodySizeToRead(0) + , m_SendMessageType("") + , m_ReceiveMessageType("") + , m_HeaderVersion(IGTL_HEADER_VERSION_1) + , m_DeviceName("") + , m_TimeStampSec(0) + , m_TimeStampSecFraction(0) + , m_IsHeaderUnpacked(false) + , m_IsBodyUnpacked(false) + , m_IsBodyPacked(false) +#if OpenIGTLink_HEADER_VERSION >= 2 + , m_ExtendedHeader(NULL) + , m_IsExtendedHeaderUnpacked(false) + , m_MetaData(NULL) + , m_MessageId(0) + , m_MetaDataMap(MetaDataMap()) +#endif +{ +} + +MessageBase::~MessageBase() +{ + if (this->m_MessageSize > 0 && this->m_Header != NULL) + { + delete [] m_Header; + m_MessageSize = 0; + m_Header = NULL; + m_Body = NULL; + m_Content = NULL; +#if OpenIGTLink_HEADER_VERSION >= 2 + m_ExtendedHeader = NULL; + m_MetaDataHeader = NULL; + m_MetaData = NULL; +#endif + } +} + +igtlUint64 MessageBase::CalculateContentBufferSize() +{ + return 0; +} + +igtl::MessageBase::Pointer MessageBase::Clone() +{ + igtl::MessageBase::Pointer clone; + { + igtl::MessageFactory::Pointer factory = igtl::MessageFactory::New(); + clone = factory->CreateSendMessage(this->GetMessageType(), this->GetHeaderVersion()); + } + + igtlUint64 bodySize = this->m_MessageSize - IGTL_HEADER_SIZE; + clone->InitBuffer(); + clone->CopyHeader(this); + clone->AllocateBuffer(bodySize); + if (bodySize > 0) + { + clone->CopyBody(this); + } + +#if OpenIGTLink_HEADER_VERSION >= 2 + clone->m_MetaDataHeader = this->m_MetaDataHeader; + clone->m_MetaDataMap = this->m_MetaDataMap; + clone->m_IsExtendedHeaderUnpacked = this->m_IsExtendedHeaderUnpacked; +#endif + + return clone; +} + +void MessageBase::SetHeaderVersion(unsigned short version) +{ + m_HeaderVersion = version; + m_IsBodyPacked = false; +} + +unsigned short MessageBase::GetHeaderVersion() const +{ + return m_HeaderVersion; +} + +void MessageBase::SetDeviceName(const char* name) +{ + if (name == NULL) + { + return; + } + SetDeviceName(std::string(name)); +} + +void MessageBase::SetDeviceName(const std::string& name) +{ + m_DeviceName = name; + m_IsBodyPacked = false; +} + +void MessageBase::SetDeviceType(const std::string& type) +{ + this->m_ReceiveMessageType = type; + m_IsBodyPacked = false; +} + +std::string MessageBase::GetDeviceName() const +{ + return m_DeviceName; +} + +const char* MessageBase::GetDeviceName() +{ + return m_DeviceName.c_str(); +} + +const char* MessageBase::GetDeviceType() +{ + if (m_SendMessageType.length() > 0) + { + return m_SendMessageType.c_str(); + } + else + { + return m_ReceiveMessageType.c_str(); + } +} + +std::string MessageBase::GetMessageType() const +{ + if (m_SendMessageType.length() > 0) + { + return m_SendMessageType; + } + else + { + return m_ReceiveMessageType; + } +} + +#if OpenIGTLink_HEADER_VERSION >= 2 +igtlUint32 MessageBase::GetMetaDataSize() +{ + if( m_HeaderVersion >= IGTL_HEADER_VERSION_2 ) + { + igtlUint32 metaDataSize(0); + for (MetaDataMap::const_iterator it = m_MetaDataMap.begin(); it != m_MetaDataMap.end(); ++it) + { + metaDataSize += it->first.length() + it->second.second.length(); + } + + return metaDataSize; + } + else + { + return 0; + } +} + +igtlUint16 MessageBase::GetMetaDataHeaderSize() +{ + if( m_HeaderVersion >= IGTL_HEADER_VERSION_2 ) + { + return (m_MetaDataMap.size()*sizeof(igtl_metadata_header_entry)) + sizeof(igtlUint16); // index_count is at beginning of header + } + else + { + return 0; + } +} + +igtlUint32 MessageBase::GetMessageID() +{ + return m_MessageId; +} + +void MessageBase::SetMessageID(igtlUint32 idValue) +{ + m_MessageId = idValue; + m_IsBodyPacked = false; +} + +bool MessageBase::SetMetaDataElement(const std::string& key, IANA_ENCODING_TYPE encodingScheme, std::string value) +{ + igtl_metadata_header_entry entry; + if (key.length() > std::numeric_limits::max()) + { + return false; + } + entry.key_size = static_cast(key.length()); + entry.value_encoding = static_cast(encodingScheme); + entry.value_size = value.length(); + + m_MetaDataMap[key] = std::pair(encodingScheme, value); + + m_IsBodyPacked = false; + + return true; +} + +bool MessageBase::SetMetaDataElement(const std::string& key, igtl_uint8 value) +{ + std::stringstream ss; + ss << value; + return SetMetaDataElement(key, IANA_TYPE_US_ASCII, ss.str()); +} + +bool MessageBase::SetMetaDataElement(const std::string& key, igtl_int8 value) +{ + std::stringstream ss; + ss << value; + return SetMetaDataElement(key, IANA_TYPE_US_ASCII, ss.str()); +} + +bool MessageBase::SetMetaDataElement(const std::string& key, igtl_uint16 value) +{ + std::stringstream ss; + ss << value; + return SetMetaDataElement(key, IANA_TYPE_US_ASCII, ss.str()); +} + +bool MessageBase::SetMetaDataElement(const std::string& key, igtl_int16 value) +{ + std::stringstream ss; + ss << value; + return SetMetaDataElement(key, IANA_TYPE_US_ASCII, ss.str()); +} + +bool MessageBase::SetMetaDataElement(const std::string& key, igtl_uint32 value) +{ + std::stringstream ss; + ss << value; + return SetMetaDataElement(key, IANA_TYPE_US_ASCII, ss.str()); +} + +bool MessageBase::SetMetaDataElement(const std::string& key, igtl_int32 value) +{ + std::stringstream ss; + ss << value; + return SetMetaDataElement(key, IANA_TYPE_US_ASCII, ss.str()); +} + +bool MessageBase::SetMetaDataElement(const std::string& key, igtl_uint64 value) +{ + std::stringstream ss; + ss << value; + return SetMetaDataElement(key, IANA_TYPE_US_ASCII, ss.str()); +} + +bool MessageBase::SetMetaDataElement(const std::string& key, igtl_int64 value) +{ + std::stringstream ss; + ss << value; + return SetMetaDataElement(key, IANA_TYPE_US_ASCII, ss.str()); +} + +bool MessageBase::SetMetaDataElement(const std::string& key, float value) +{ + std::stringstream ss; + ss << value; + return SetMetaDataElement(key, IANA_TYPE_US_ASCII, ss.str()); +} + +bool MessageBase::SetMetaDataElement(const std::string& key, double value) +{ + std::stringstream ss; + ss << value; + return SetMetaDataElement(key, IANA_TYPE_US_ASCII, ss.str()); +} + +bool MessageBase::GetMetaDataElement(const std::string& key, std::string& value) const +{ + IANA_ENCODING_TYPE type; + return GetMetaDataElement(key, type, value); +} + +bool MessageBase::GetMetaDataElement(const std::string& key, IANA_ENCODING_TYPE& encoding, std::string& value) const +{ + if (m_MetaDataMap.find(key) != m_MetaDataMap.end()) + { + encoding = m_MetaDataMap.find(key)->second.first; + value = m_MetaDataMap.find(key)->second.second; + return true; + } + + return false; +} + +const MessageBase::MetaDataMap& MessageBase::GetMetaData() const +{ + return this->m_MetaDataMap; +} + +bool MessageBase::PackExtendedHeader() +{ + if( m_HeaderVersion == IGTL_HEADER_VERSION_2 ) + { + //igtlUint64 aSize = m_MessageSize - IGTL_HEADER_SIZE - sizeof(igtl_extended_header); + if(m_MessageSize < (IGTL_HEADER_SIZE + sizeof(igtl_extended_header))) + { + // Ensure we have enough space to write the header + AllocateBuffer(0); + } + + igtl_extended_header* extended_header = (igtl_extended_header*) m_ExtendedHeader; + extended_header->extended_header_size = sizeof(igtl_extended_header); + extended_header->meta_data_header_size = this->GetMetaDataHeaderSize(); + extended_header->meta_data_size = this->GetMetaDataSize(); + extended_header->message_id = this->GetMessageID(); + igtl_extended_header_convert_byte_order(extended_header); + + return true; + } + + return false; +} + +bool MessageBase::PackMetaData() +{ + if( m_HeaderVersion == IGTL_HEADER_VERSION_2 ) + { + if (m_MetaDataMap.size() > std::numeric_limits::max()) + { + return false; + } + igtl_uint16 index_count = static_cast(m_MetaDataMap.size()); // first two byte are the total number of meta data + if(igtl_is_little_endian()) + { + index_count = BYTE_SWAP_INT16(index_count); + } + + // Pack meta data header key/encoding/value trios + memcpy(m_MetaDataHeader, &index_count, META_DATA_INDEX_COUNT_SIZE); + + if (m_MetaDataMap.size() > 0) + { + unsigned char* entryPointer = &m_MetaDataHeader[META_DATA_INDEX_COUNT_SIZE]; + for (MetaDataMap::const_iterator it = m_MetaDataMap.begin(); it != m_MetaDataMap.end();++it) + { + igtl_metadata_header_entry entry; + entry.key_size = it->first.length(); + entry.value_encoding = it->second.first; + entry.value_size = it->second.second.length(); + + if(igtl_is_little_endian()) + { + entry.key_size = BYTE_SWAP_INT16(entry.key_size); + entry.value_encoding = BYTE_SWAP_INT16(entry.value_encoding); + entry.value_size = BYTE_SWAP_INT32(entry.value_size); + } + memcpy(&entryPointer[0], &entry.key_size, sizeof(igtlUint16)); + memcpy(&entryPointer[2], &entry.value_encoding, sizeof(igtlUint16)); + memcpy(&entryPointer[4], &entry.value_size, sizeof(igtlUint32)); + + entryPointer += sizeof(igtl_metadata_header_entry); + } + + // Pack meta data key/value pairs + std::string key(""); + std::string value(""); + + unsigned char* metaDataPointer = m_MetaData; + int i(0); + for (MetaDataMap::iterator it = m_MetaDataMap.begin(); it != m_MetaDataMap.end(); ++it, ++i) + { + memcpy(metaDataPointer, it->first.c_str(), it->first.length()); + metaDataPointer += it->first.length(); + memcpy(metaDataPointer, it->second.second.c_str(), it->second.second.length()); + metaDataPointer += it->second.second.length(); + } + + return true; + } + else + { + return true; + } + } + + return false; +} + +bool MessageBase::UnpackExtendedHeader() +{ + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + igtl_extended_header* extended_header = (igtl_extended_header*)m_ExtendedHeader; + igtl_extended_header_convert_byte_order(extended_header); + if( extended_header->extended_header_size != sizeof(igtl_extended_header) ) + { + // any extra data will be dropped, if the order of variables is changed, this will be seriously broken + // TODO : add error reporting? + } + this->m_MessageId = extended_header->message_id; + + m_Content = &m_Body[extended_header->extended_header_size]; + m_MetaDataHeader = &m_Body[m_BodySizeToRead - extended_header->meta_data_header_size - extended_header->meta_data_size]; + m_MetaData = &m_Body[m_BodySizeToRead - extended_header->meta_data_size]; + + m_IsExtendedHeaderUnpacked = true; + + return true; + } + + return false; +} + +bool MessageBase::UnpackMetaData() +{ + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + // Parse the header + igtl_uint16 index_count = 0; // first two byte are the total number of meta data + memcpy(&index_count, m_MetaDataHeader, META_DATA_INDEX_COUNT_SIZE); + if(igtl_is_little_endian()) + { + index_count = BYTE_SWAP_INT16(index_count); + } + + if( index_count == 0 ) + { + return true; + } + + std::vector metaDataEntries; + igtl_metadata_header_entry entry; + unsigned char* entryPointer = &m_MetaDataHeader[META_DATA_INDEX_COUNT_SIZE]; + const igtl_uint16 metaDataHeaderSize = ((igtl_extended_header*)m_ExtendedHeader)->meta_data_header_size; + igtl_uint32 currentMetaDataHeaderRead = 0; + for (int i = 0; i < index_count; i++) + { + currentMetaDataHeaderRead += sizeof(igtl_metadata_header_entry); + if (currentMetaDataHeaderRead > metaDataHeaderSize) + { + return false; + } + + memcpy(&entry.key_size, &entryPointer[0], sizeof(igtlUint16)); + memcpy(&entry.value_encoding, &entryPointer[2], sizeof(igtlUint16)); + memcpy(&entry.value_size, &entryPointer[4], sizeof(igtlUint32)); + if(igtl_is_little_endian()) + { + entry.key_size = BYTE_SWAP_INT16(entry.key_size); + entry.value_encoding = BYTE_SWAP_INT16(entry.value_encoding); + entry.value_size = BYTE_SWAP_INT32(entry.value_size); + } + metaDataEntries.push_back(entry); + + entryPointer += sizeof(igtl_metadata_header_entry); + } + + // Parse the meta data + m_MetaDataMap.clear(); + + unsigned char* metaDataPointer = m_MetaData; + const igtl_uint16 metaDataSize = ((igtl_extended_header*)m_ExtendedHeader)->meta_data_size; + igtl_uint32 currentMetaDataRead = 0; + for (int i = 0; i < index_count; i++) + { + currentMetaDataRead += metaDataEntries[i].key_size + metaDataEntries[i].value_size; + if (currentMetaDataRead > metaDataSize) + { + return false; + } + std::string key; + key.assign(metaDataPointer, metaDataPointer + metaDataEntries[i].key_size); + metaDataPointer += metaDataEntries[i].key_size; + std::string value; + value.assign(metaDataPointer, metaDataPointer + metaDataEntries[i].value_size); + metaDataPointer += metaDataEntries[i].value_size; + m_MetaDataMap[key] = std::pair((IANA_ENCODING_TYPE)metaDataEntries[i].value_encoding, value); + } + + return true; + } + + return false; +} +#endif + + +int MessageBase::SetTimeStamp(unsigned int sec, unsigned int frac) +{ + m_TimeStampSec = sec; + m_TimeStampSecFraction = frac; + return 1; +} + +int MessageBase::GetTimeStamp(unsigned int* sec, unsigned int* frac) +{ + *sec = m_TimeStampSec; + *frac = m_TimeStampSecFraction; + return 1; +} + +void MessageBase::SetTimeStamp(igtl::TimeStamp::Pointer& ts) +{ + m_TimeStampSec = ts->GetSecond(); + m_TimeStampSecFraction = igtl_nanosec_to_frac(ts->GetNanosecond()); + +} + +void MessageBase::GetTimeStamp(igtl::TimeStamp::Pointer& ts) +{ + ts->SetTime(m_TimeStampSec, igtl_frac_to_nanosec(m_TimeStampSecFraction)); +} + + +int MessageBase::Pack() +{ + if (m_IsBodyPacked) + { + // Allow for multiple packs + return 1; + } + + if( m_SendMessageType.empty() ) + { + // We do not allow sending of base class messages, aka igtl::MessageBase + // TODO : error reporting? + return 0; + } + +#if OpenIGTLink_HEADER_VERSION >= 2 + PackExtendedHeader(); +#endif + + // Derived classes will re-call allocate pack with their required content size + PackContent(); + +#if OpenIGTLink_HEADER_VERSION >= 2 + PackMetaData(); +#endif + + m_IsBodyPacked = true; + + // pack header + igtl_header* h = (igtl_header*) m_Header; + + igtl_uint64 crc = crc64(0, 0, 0LL); // initial crc + h->header_version = m_HeaderVersion; + + igtl_uint64 ts = m_TimeStampSec & 0xFFFFFFFF; + ts = (ts << 32) | (m_TimeStampSecFraction & 0xFFFFFFFF); + + h->timestamp = ts; + h->body_size = GetBufferBodySize(); + h->crc = crc64((unsigned char*)m_Body, h->body_size, crc); + + strncpy(h->name, m_SendMessageType.c_str(), 12); + + strncpy(h->device_name, m_DeviceName.c_str(), 20); + + igtl_header_convert_byte_order(h); + + return 1; +} + +int MessageBase::Unpack(int crccheck) +{ + int r = UNPACK_UNDEF; + + // Check if the pack exists and if it has not been unpacked. + if (m_Header != NULL && m_MessageSize >= IGTL_HEADER_SIZE && !m_IsHeaderUnpacked ) + { + InitBuffer(); + UnpackHeader(r); + } + +#if OpenIGTLink_HEADER_VERSION >= 2 + // Check if the body exists and it has not been unpacked + // The extended header is technically located inside the body, so we have to check to see if the remaining body size + // is > 0, or if full body size > sizeof(igtl_extended_header) + if( m_HeaderVersion >= IGTL_HEADER_VERSION_2 ) + { + if (GetBufferBodySize() > static_cast(sizeof(igtl_extended_header)) + META_DATA_INDEX_COUNT_SIZE && !m_IsBodyUnpacked) + { + UnpackBody(crccheck, r); + } + } + else + { +#endif + if(GetBufferBodySize() > 0 && !m_IsBodyUnpacked) + { + UnpackBody(crccheck, r); + } +#if OpenIGTLink_HEADER_VERSION >= 2 + } +#endif + + return r; +} + +void* MessageBase::GetBufferPointer() +{ + return (void*) m_Header; +} + +void* MessageBase::GetBufferBodyPointer() +{ + return (void*) m_Body; +} + +igtl_uint64 MessageBase::GetBufferSize() +{ + return m_MessageSize; +} + +igtl_uint64 MessageBase::GetBufferBodySize() +{ + return GetBufferSize() - IGTL_HEADER_SIZE; +} + +igtl_uint64 MessageBase::CalculateReceiveContentSize(bool& isUnpacked) +{ + isUnpacked = true; +#if OpenIGTLink_HEADER_VERSION >= 2 + if( m_HeaderVersion >= IGTL_HEADER_VERSION_2 ) + { + if( !m_IsExtendedHeaderUnpacked ) + { + isUnpacked = false; + return 0; + } + igtl_extended_header* header = (igtl_extended_header*)m_ExtendedHeader; + return GetBufferSize() - IGTL_HEADER_SIZE - header->extended_header_size - header->meta_data_header_size - header->meta_data_size; + } + else + { +#endif + return m_BodySizeToRead; +#if OpenIGTLink_HEADER_VERSION >= 2 + } +#endif +} + +const char* MessageBase::GetBodyType() +{ + return this->m_ReceiveMessageType.c_str(); +} + +int MessageBase::PackContent() +{ + return 0; +} + +int MessageBase::UnpackContent() +{ + return 0; +} + +void MessageBase::AllocateBuffer() +{ + if( m_BodySizeToRead > 0 ) + { + // called after receiving general header + AllocateUnpack(m_BodySizeToRead); + } + else + { + // called for creating pack to send + AllocateBuffer(CalculateContentBufferSize()); + } +} + +void MessageBase::InitBuffer() +{ + m_IsHeaderUnpacked = false; + m_IsBodyPacked = false; + m_IsBodyUnpacked = false; + m_BodySizeToRead = 0; + + m_DeviceName = ""; + m_ReceiveMessageType = ""; + + // Re-allocate header area + igtlUint64 message_size = IGTL_HEADER_SIZE; + + if (m_Header == NULL) + { + // For the first time + m_Header = new unsigned char [message_size]; + m_IsHeaderUnpacked = false; + m_IsBodyUnpacked = false; + } + else if (m_MessageSize != message_size) + { + // If the pack area exists but needs to be reallocated + // m_IsHeaderUnpacked status is not changed in this case. + unsigned char* old = m_Header; + m_Header = new unsigned char [message_size]; + memcpy(m_Header, old, std::min(m_MessageSize, message_size)); + delete [] old; + m_IsBodyUnpacked = false; + } + m_Body = &m_Header[IGTL_HEADER_SIZE]; +#if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + m_ExtendedHeader = m_Body; + // Other members can't be populated until the message is unpacked + } + else + { + m_Content = m_Body; + } +#else + m_Content = m_Body; +#endif + m_MessageSize = message_size; +} + +void MessageBase::AllocateBuffer(igtlUint64 contentSize) +{ +#if OpenIGTLink_HEADER_VERSION >= 2 + igtlUint64 message_size(0); + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + message_size = IGTL_HEADER_SIZE + contentSize + sizeof(igtl_extended_header) + GetMetaDataHeaderSize() + GetMetaDataSize(); + } + else + { + message_size = IGTL_HEADER_SIZE + contentSize; + } +#else + igtlUint64 message_size = IGTL_HEADER_SIZE + contentSize; +#endif + + if (m_Header == NULL) + { + // For the first time + m_Header = new unsigned char [message_size]; + m_IsHeaderUnpacked = false; + m_IsBodyUnpacked = false; + m_IsBodyPacked = false; + } + else if (m_MessageSize != message_size) + { + // If the pack area exists but needs to be reallocated + // m_IsHeaderUnpacked status is not changed in this case. + unsigned char* old = m_Header; + m_Header = new unsigned char [message_size]; + memcpy(m_Header, old, std::min(m_MessageSize, message_size)); + delete [] old; + m_IsBodyUnpacked = false; + } + m_Body = &m_Header[IGTL_HEADER_SIZE]; + +#if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + m_ExtendedHeader = m_Body; + m_Content = &m_Body[sizeof(igtl_extended_header)]; + m_MetaDataHeader = &m_Body[sizeof(igtl_extended_header)+contentSize]; + m_MetaData = &m_Body[sizeof(igtl_extended_header)+contentSize+GetMetaDataHeaderSize()]; + } + else + { +#endif + m_Content = m_Body; +#if OpenIGTLink_HEADER_VERSION >= 2 + } +#endif + + m_MessageSize = message_size; +} + +int MessageBase::CopyHeader(const MessageBase* mb) +{ + if (m_Header != NULL && mb->m_Header != NULL) + { + memcpy(m_Header, mb->m_Header, IGTL_HEADER_SIZE); + m_Body = &m_Header[IGTL_HEADER_SIZE]; + if (mb->m_HeaderVersion < IGTL_HEADER_VERSION_2) + { + m_Content = m_Body; + } + } + m_MessageSize = mb->m_MessageSize; + m_ReceiveMessageType = mb->m_ReceiveMessageType; + m_DeviceName = mb->m_DeviceName; + m_TimeStampSec = mb->m_TimeStampSec; + m_TimeStampSecFraction = mb->m_TimeStampSecFraction; + m_IsHeaderUnpacked = mb->m_IsHeaderUnpacked; + m_IsBodyUnpacked = mb->m_IsBodyUnpacked; + m_IsBodyPacked = mb->m_IsBodyPacked; + m_BodySizeToRead = mb->m_BodySizeToRead; + m_HeaderVersion = mb->m_HeaderVersion; + + return 1; +} + +int MessageBase::CopyBody(const MessageBase *mb) +{ + igtlUint64 bodySize = m_MessageSize - IGTL_HEADER_SIZE; + if (m_Body != NULL && mb->m_Body != NULL && bodySize > 0) + { + memcpy(m_Body, mb->m_Body, bodySize); + +#if OpenIGTLink_HEADER_VERSION >= 2 + if( m_HeaderVersion == IGTL_HEADER_VERSION_2 ) + { + igtl_extended_header* other_ext_header = (igtl_extended_header*)(mb->m_ExtendedHeader); + if( other_ext_header->extended_header_size != sizeof(igtl_extended_header) ) + { + return 0; + } + m_ExtendedHeader = m_Body; + m_Content = &m_Body[other_ext_header->extended_header_size]; + m_MetaDataHeader = &m_Body[bodySize - other_ext_header->meta_data_header_size - other_ext_header->meta_data_size]; + m_MetaData = &m_Body[bodySize - other_ext_header->meta_data_size]; + } + else + { +#endif + m_Content = m_Body; +#if OpenIGTLink_HEADER_VERSION >= 2 + } +#endif + + return 1; + } + + return 0; +} + +void MessageBase::UnpackHeader(int& r) +{ + // Unpack (deserialize) the header + igtl_header* h = (igtl_header*) m_Header; + igtl_header_convert_byte_order(h); + m_TimeStampSecFraction = h->timestamp & 0xFFFFFFFF; + m_TimeStampSec = (h->timestamp >> 32 ) & 0xFFFFFFFF; + m_HeaderVersion = h->header_version; + m_BodySizeToRead = h->body_size; + + char bodyType[IGTL_HEADER_TYPE_SIZE+1]; + char deviceName[IGTL_HEADER_NAME_SIZE+1]; + + bodyType[IGTL_HEADER_TYPE_SIZE] = '\0'; + deviceName[IGTL_HEADER_NAME_SIZE] = '\0'; + strncpy(bodyType, h->name, IGTL_HEADER_TYPE_SIZE); + strncpy(deviceName, h->device_name, IGTL_HEADER_NAME_SIZE); + + m_ReceiveMessageType = bodyType; + if( m_ReceiveMessageType.empty() ) + { + // MessageBase class has been sent, this can't be good + // TODO : how to report an error + } + m_DeviceName = deviceName; + + // Mark as unpacked. + m_IsHeaderUnpacked = true; + r |= UNPACK_HEADER; +} + +void MessageBase::UnpackBody(int crccheck, int& r) +{ + igtl_header* h = (igtl_header*) m_Header; + igtl_uint64 crc = crc64(0, 0, 0LL); // initial crc + + if (crccheck) + { + // Calculate CRC of the body + crc = crc64((unsigned char*)m_Body, m_BodySizeToRead, crc); + } + else + { + crc = h->crc; + } + + if (crc == h->crc) + { + bool unpackSuccessful = true; + // Unpack (deserialize) the Body +#if OpenIGTLink_HEADER_VERSION >= 2 + if (h->header_version >= 2) + { + unpackSuccessful &= UnpackExtendedHeader(); + } +#endif + unpackSuccessful &= UnpackContent(); +#if OpenIGTLink_HEADER_VERSION >= 2 + if (h->header_version >= 2) + { + unpackSuccessful &= UnpackMetaData(); + } +#endif + m_IsBodyUnpacked = unpackSuccessful; + if (unpackSuccessful) + { + r |= UNPACK_BODY; + } + } + else + { + m_IsBodyUnpacked = false; + } +} + +void MessageBase::AllocateUnpack(igtl_uint64 bodySizeToRead) +{ + if (bodySizeToRead == 0) + { + bodySizeToRead = 0; + m_IsBodyUnpacked = false; + } + + igtl_uint64 message_size = IGTL_HEADER_SIZE + bodySizeToRead; + + if (m_Header == NULL) + { + // For the first time + m_Header = new unsigned char [message_size]; + m_IsHeaderUnpacked = false; + m_IsBodyUnpacked = false; + m_IsBodyPacked = false; + } + else if (m_MessageSize != message_size) + { + // If the pack area exists but needs to be reallocated + // m_IsHeaderUnpacked status is not changed in this case. + unsigned char* old = m_Header; + m_Header = new unsigned char [message_size]; + memcpy(m_Header, old, std::min(m_MessageSize, message_size)); + delete [] old; + m_IsBodyUnpacked = false; + } + m_Body = &m_Header[IGTL_HEADER_SIZE]; + +#if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion >= IGTL_HEADER_VERSION_2) + { + m_ExtendedHeader = m_Body; + // Other members can't be populated until the message is unpacked + } + else + { +#endif + m_Content = m_Body; +#if OpenIGTLink_HEADER_VERSION >= 2 + } +#endif + + m_MessageSize = message_size; +} + +int MessageBase::Copy(const MessageBase* mb) +{ + if (this == mb) + { + return 0; + } + + // Check if the destination (this class) is MessageBase or + // the source and destination class are the same type. + // The pack size is also checked if it is larger than the header size. + if ((m_SendMessageType.length() == 0 || m_SendMessageType == mb->m_ReceiveMessageType) + && mb->m_MessageSize >= IGTL_HEADER_SIZE) + { + // Set the header version before calling any functions, as it determines later behavior + m_HeaderVersion = mb->m_HeaderVersion; + + igtlUint64 bodySize = mb->m_MessageSize - IGTL_HEADER_SIZE; + AllocateBuffer(bodySize); + CopyHeader(mb); + if (bodySize > 0) + { + CopyBody(mb); + } + return 1; + } + else + { + return 0; + } +} + +int MessageBase::SetMessageHeader(const MessageHeader* mb) +{ + return Copy(mb); +} + +igtl_uint64 MessageBase::GetBodySizeToRead() +{ + return m_BodySizeToRead; +} + +} diff --git a/openigtlink/repo/Source/igtlMessageBase.h b/openigtlink/repo/Source/igtlMessageBase.h new file mode 100644 index 0000000..c247e92 --- /dev/null +++ b/openigtlink/repo/Source/igtlMessageBase.h @@ -0,0 +1,416 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#ifndef __igtlMessageBase_h +#define __igtlMessageBase_h + +#include "igtlMacro.h" +#include "igtlMath.h" +#include "igtlMessageHeader.h" +#include "igtlObject.h" +#include "igtlObjectFactory.h" +#include "igtlTimeStamp.h" +#include "igtl_header.h" +#include "igtl_types.h" + +#include +#include +#include + +namespace igtl +{ + + /// The MessageBase class is the base class of all message type classes + /// used in the OpenIGTLink Library. The message classes can be used + /// both for serializing (packing) OpenIGTLink message byte streams. + /// The class can also deserializing (unpacking) OpenIGTLink. + /// For the deserialization example, please refer igtlMessageHeader.h. + /// + /// The typical packing procedures using sub-classes of + /// MessageBase look like the followings + /// + /// // Create instance and set Device Name + /// igtl::TransformMessage::Pointer transMsg; + /// transMsg = igtl::TransformMessage::New(); + /// transMsg->SetDeviceName("Tracker"); + /// + /// // Create matrix and substitute values + /// igtl::Matrix4x4 matrix; + /// GetRandomTestMatrix(matrix); + /// + /// // Set matrix data, serialize, and send it. + /// transMsg->SetMatrix(matrix); + /// transMsg->AllocatePack(); // optional + /// transMsg->Pack(); + /// socket->Send(transMsg->GetBufferPointer(), transMsg->GetBufferSize()); + /// + /// V1/V2 message structure: + /// GetBodySize() + /// /-------------------------/\----------------------------------------------------------\ + /// GetPackContentSize() (subclassed) + /// /-------------------------------------/\----------------------------------------------\ + /// |____________|_____________________________________________________________________________________| + /// m_Header m_Body + /// + /// + /// V3 message structure: + /// GetBodySize() + /// /-------------------------/\------------------------------------------------------------\ + /// GetPackContentSize() (subclassed) + /// /\ (sending after setters are called, receiving after extended header has been parsed) + /// /--------/ \-----------\ + /// |____________|___________________|________________________|___________________|_______________________| + /// m_Header m_ExtendedHeader m_Content (old m_Body) m_MetaDataHeader m_MetaData + /// m_Body + /// + + class IGTLCommon_EXPORT MessageBase: public Object + { + public: + +#if OpenIGTLink_HEADER_VERSION >= 2 + // Types for managing meta data + typedef std::map > MetaDataMap; +#endif + + igtlTypeMacro(MessageBase, Object) + igtlNewMacro(igtl::MessageBase); + + /// Unpack status. They are returned by the Unpack() function. + enum + { + UNPACK_UNDEF = 0x0000, + UNPACK_HEADER = 0x0001, + UNPACK_BODY = 0x0002 + }; + + public: + /// Create a clone of this message, new memory but all internals are preserved + virtual igtl::MessageBase::Pointer Clone(); + + /// Sets the message version number + void SetHeaderVersion(unsigned short headerVersion); + + /// Gets the message version number + unsigned short GetHeaderVersion() const; + + /// Sets the device name. + void SetDeviceName(const char* name); + + /// Sets the device name. + void SetDeviceName(const std::string& name); + + /// Sets the device (message) type. + void SetDeviceType(const std::string& type); + + /// Gets the device name. + const char* GetDeviceName(); + + /// Gets the device name. + std::string GetDeviceName() const; + + /// Gets the device (message) type. + const char* GetDeviceType(); + +#if OpenIGTLink_HEADER_VERSION >= 2 + /// Gets the size (length) of the byte array for the meta data. + /// The size is defined by the length of each meta data elements and the total number of + /// the meta data element. + igtlUint32 GetMetaDataSize(); + + /// Gets the size (length) of the byte array for the meta data header. + igtlUint16 GetMetaDataHeaderSize(); + + /// Gets the message ID + igtlUint32 GetMessageID(); + + /// Sets the message ID + void SetMessageID(igtlUint32 idValue); + + /// Add Meta data element + bool SetMetaDataElement(const std::string& key, IANA_ENCODING_TYPE encodingScheme, std::string value); + bool SetMetaDataElement(const std::string& key, igtl_uint8); + bool SetMetaDataElement(const std::string& key, igtl_int8); + bool SetMetaDataElement(const std::string& key, igtl_uint16); + bool SetMetaDataElement(const std::string& key, igtl_int16); + bool SetMetaDataElement(const std::string& key, igtl_uint32); + bool SetMetaDataElement(const std::string& key, igtl_int32); + bool SetMetaDataElement(const std::string& key, igtl_uint64); + bool SetMetaDataElement(const std::string& key, igtl_int64); + bool SetMetaDataElement(const std::string& key, float); + bool SetMetaDataElement(const std::string& key, double); + + /// Get meta data element + bool GetMetaDataElement(const std::string& key, std::string& value) const; + bool GetMetaDataElement(const std::string& key, IANA_ENCODING_TYPE& encoding, std::string& value) const; + + /// Get meta data map + const MetaDataMap& GetMetaData() const; + + /// Pack the extended header + bool PackExtendedHeader(); + + /// Pack the meta data + bool PackMetaData(); + + /// Unpack Extended header + /// When receiving a message, after the base header is unpacked, the extended header is read + /// Once read, the m_MetaDataHeader and m_MetaData members are populated as we now know the message structure + bool UnpackExtendedHeader(); + + /// Unpack Extended header and the meta data + bool UnpackMetaData(); +#endif + + /// Sets time of message creation. 'sec' and 'frac' are seconds and fractions of a second respectively. + int SetTimeStamp(unsigned int sec, unsigned int frac); + + /// Gets time of message creation. 'sec' and 'frac' are seconds and fractions of a second respectively. + int GetTimeStamp(unsigned int* sec, unsigned int* frac); + + /// Sets time of message creation. + void SetTimeStamp(igtl::TimeStamp::Pointer& ts); + + /// Gets time of message creation. + void GetTimeStamp(igtl::TimeStamp::Pointer& ts); + + /// Pack() serializes the header and body based on the member variables. + /// PackContent() must be implemented in the child class. + virtual int Pack(); + + /// Unpack() deserializes the header and/or body, extracting data from + /// the byte stream. If the header has already been deserilized, Unpack() + /// deserializes only the body part. UnpackBody() must be implemented to + /// deserialize the body part. Unpack() performs 64-bit CRC check, + /// when crccheck = 1. It returns: + /// + /// UNPACK_UNDEF : Nothing deserialized + /// UNPACK_HEADER : The header has been deserialized. + /// UNPACK_BODY : The body has been deserialized. + /// If CRC check fails, Unpack() doesn't + /// deserialize the body, thus it doesn't + /// return UNPACK_BODY flag. + /// UNPACK_HEADER|UNPACK_BODY: Both the header and body have been + /// deserialized + int Unpack(int crccheck = 0); + + /// Gets a pointer to the raw byte array for the serialized data including the header and the body. + void* GetBufferPointer(); + void* GetPackPointer() { return GetBufferPointer(); } + + /// Gets a pointer to the raw byte array for the serialized body data. + void* GetBufferBodyPointer(); + void* GetPackBodyPointer() { return GetBufferBodyPointer(); } + + /// Gets the size of the serialized message data. + igtl_uint64 GetBufferSize(); + igtl_uint64 GetPackSize() { return GetBufferSize(); } + + /// Gets the size of the serialized body data. + igtl_uint64 GetBufferBodySize(); + igtl_uint64 GetPackBodySize() { return GetBufferBodySize(); } + + /// Calculate the size of the received content data + /// Returns -1 if the extended header has not been properly initialized (meta data size, meta data header size, etc...) + /// Used when receiving data, not sending + igtl_uint64 CalculateReceiveContentSize(bool& isUnpacked); + + /// Gets the type of the body. + const char* GetBodyType(); + + /// Gets the message type. + std::string GetMessageType() const; + + /// AllocatePack() allocates memory for underlying buffer + /// If m_BodySizeToRead > 0, we are allocating for receiving a message + void AllocateBuffer(); + void AllocatePack() { AllocateBuffer(); } + + /// Call InitPack() before receive header. + /// This function simply resets the Unpacked flag for both + /// the header and body pack + /// Only allocate the original 58 byte header + void InitBuffer(); + void InitPack() { InitBuffer(); } + + /// Copy() copies contents from the specified Massage class. + /// If the type of the specified class is the same as this class, + /// general header and body are copied. + int Copy(const MessageBase* mb); + + /// Sets the message header. + virtual int SetMessageHeader(const MessageHeader* mb); + + /// GetBodySizeToRead() returns the size of the body to be read. This function must be called + /// after the message header is set. + igtl_uint64 GetBodySizeToRead(); + + protected: + MessageBase(); + ~MessageBase(); + + protected: + /// Gets the size of the serialized content. + virtual igtlUint64 CalculateContentBufferSize(); + + /// Packs (serialize) the content. Must be implemented in all child classes. + virtual int PackContent(); + /// Unpacks (deserialize) the content. Must be implemented in all child classes. + virtual int UnpackContent(); + + /// Allocates memory specifying the content size. + /// Implicitly allocates extended header, metadata header and metadata in addition to content + virtual void AllocateBuffer(igtlUint64 contentSize); + + /// Allocates memory specifying the unpack content size + /// Size of body to allocate is determined from v1 message header field 'body_size' + virtual void AllocateUnpack(igtl_uint64 bodySizeToRead); + + /// Copies the serialized body data + int CopyBody(const MessageBase* mb); + + /// Copies a header from given message + int CopyHeader(const MessageBase* mb); + + /// Unpack the first 58 bytes + void UnpackHeader(int& r); + + /// Unpack the body + /// If it's a v3 message, body is ext header + content + metadataheader + metadata + void UnpackBody(int crccheck, int& r); + + protected: + igtl_uint64 m_MessageSize; + + /// A pointer to the byte array for the serialized header. To prevent large + /// copy of the byte array in the Pack() function, header byte array is + /// concatenated to the byte array for the body. + unsigned char* m_Header; + + /// A pointer to the byte array for the serialized body. To prevent large + /// copy of the byte array in the Pack() function, header byte array is + /// concatenated to the byte array for the header. + unsigned char* m_Body; + + /// A pointer to the underlying content of a message + unsigned char* m_Content; + + /// The size of the body to be read. This function must be called + /// after the message header is set. + igtl_uint64 m_BodySizeToRead; + + /// A character string for the send device type (message type). + std::string m_SendMessageType; + + /// A character string for the device type (message type). This will be used when the header + /// is deserialized from a byte stream received from the network. + std::string m_ReceiveMessageType; + + /// An unsigned short for the message format version + unsigned short m_HeaderVersion; + + /// A character string for the device name (message name). + std::string m_DeviceName; + + /// A time stamp (second) for message creation. It consists of fields for seconds + /// (m_TimeStampSec)and fractions of a second (m_TimeStampSecFraction). + unsigned int m_TimeStampSec; + + /// A time stamp (second) for message creation. It consists of fields for seconds + /// (m_TimeStampSec)and fractions of a second (m_TimeStampSecFraction). + unsigned int m_TimeStampSecFraction; + + /// Unpacking (deserialization) status for the header + bool m_IsHeaderUnpacked; + + /// Unpacking (deserialization) status for the body + bool m_IsBodyUnpacked; + + /// Packing (serialization) status for the body + bool m_IsBodyPacked; + +#if OpenIGTLink_HEADER_VERSION >= 2 + protected: + /// A pointer to the serialized extended header. + unsigned char* m_ExtendedHeader; + + /// A flag to record the unpacked state of the extended header + bool m_IsExtendedHeaderUnpacked; + + /// A pointer to the meta data. + unsigned char* m_MetaData; + + /// A pointer to the meta data header. + unsigned char* m_MetaDataHeader; + + /// Message ID + igtlUint32 m_MessageId; + + /// Map storing the key value pairs + MetaDataMap m_MetaDataMap; + +#endif // if OpenIGTLink_HEADER_VERSION >= 2 + + }; + + /// A class for header-only message types, which are used for querying. + class IGTLCommon_EXPORT HeaderOnlyMessageBase: public MessageBase + { + public: + igtlTypeMacro(igtl::HeaderOnlyMessageBase, igtl::MessageBase); + igtlNewMacro(igtl::HeaderOnlyMessageBase); + + protected: + HeaderOnlyMessageBase() + { + this->m_SendMessageType = ""; + }; + ~HeaderOnlyMessageBase() {}; + + protected: + igtlUint64 CalculateContentBufferSize() override + { + return 0; + }; + int PackContent() override + { + AllocateBuffer(); + return 1; + }; + int UnpackContent() override + { + return 1; + }; + }; + + /// A macro to help defining a class for query message types + /// that do not have message bodies. + // TODO: Need test. +#define igtlCreateDefaultQueryMessageClass(name, msgtype) \ +class IGTLCommon_EXPORT name : public HeaderOnlyMessageBase\ +{ \ +public: \ +igtlTypeMacro(igtl::name, igtl::HeaderOnlyMessageBase); \ +igtlNewMacro(igtl::name); \ +\ +protected: \ +name() : HeaderOnlyMessageBase() { this->m_SendMessageType = msgtype; }; \ +~name() {}; \ +}; + +} // namespace igtl + +#endif // _igtlMessageBase_h + + diff --git a/openigtlink/repo/Source/igtlMessageDebugFunction.h b/openigtlink/repo/Source/igtlMessageDebugFunction.h new file mode 100644 index 0000000..668667c --- /dev/null +++ b/openigtlink/repo/Source/igtlMessageDebugFunction.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igltMessageDebugFunction_h +#define __igltMessageDebugFunction_h + +#define ABS_ERROR 1e-6 + +void TestDebugCharArrayCmp(void* inputPointer, unsigned char* inputArray, int size) +{ + for (int i = 0 ; i< size;++i) + { + std::cerr< +0.0f ? tol:-tol; + for(int i=0;i < 4; i++) + { + for(int j=0;j < 4; j++) + { + if((outMatrix[i][j] - inMatrix[i][j]) > tol || + (outMatrix[i][j] - inMatrix[i][j]) < -tol) + { + equal = false; + } + } + } + return equal; +} + +bool ArrayFloatComparison(float returnArray[], float inArray[], int size, float tol) +{ + bool equal = true; + tol = tol > +0.0f ? tol:-tol; + for(int j=0;j < size; j++) + { + if((returnArray[j] - inArray[j]) > tol || + (returnArray[j] - inArray[j]) < -tol) + { + equal = false; + } + } + return equal; +} +#endif // __igltOSUtil_h + + diff --git a/openigtlink/repo/Source/igtlMessageFactory.cxx b/openigtlink/repo/Source/igtlMessageFactory.cxx new file mode 100644 index 0000000..b003084 --- /dev/null +++ b/openigtlink/repo/Source/igtlMessageFactory.cxx @@ -0,0 +1,279 @@ +/*========================================================================= + +Program: The OpenIGTLink Library +Language: C++ +Web page: http://openigtlink.org/ + +Copyright (c) Insight Software Consortium. All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlMessageFactory.h" + +#include "igtlTransformMessage.h" +#include "igtlPositionMessage.h" +#include "igtlImageMessage.h" +#include "igtlClientSocket.h" +#include "igtlStatusMessage.h" +#include "igtlCapabilityMessage.h" + +#if OpenIGTLink_PROTOCOL_VERSION >= 2 +#include "igtlPointMessage.h" +#include "igtlPolyDataMessage.h" +#include "igtlQuaternionTrackingDataMessage.h" +#include "igtlStringMessage.h" +#include "igtlTrackingDataMessage.h" +#include "igtlTrajectoryMessage.h" +#include "igtlImageMetaMessage.h" +#include "igtlLabelMetaMessage.h" +#endif // OpenIGTLink_PROTOCOL_VERSION >= 2 + +#if OpenIGTLink_HEADER_VERSION >= 2 +#include "igtlCommandMessage.h" +#endif // OpenIGTLink_PROTOCOL_VERSION >= 3 + +#if defined(OpenIGTLink_ENABLE_VIDEOSTREAMING) +#include "igtlVideoMessage.h" +#endif + +#include "igtl_header.h" + +#include +#include +#include +#include +#include + +namespace igtl +{ + +//----------------------------------------------------------------------------- +MessageFactory::MessageFactory() +{ + this->AddMessageType("TRANSFORM", (PointerToMessageBaseNew)&igtl::TransformMessage::New); + this->AddMessageType("GET_TRANS", (PointerToMessageBaseNew)&igtl::GetTransformMessage::New); + this->AddMessageType("POSITION", (PointerToMessageBaseNew)&igtl::PositionMessage::New); + this->AddMessageType("IMAGE", (PointerToMessageBaseNew)&igtl::ImageMessage::New); + this->AddMessageType("GET_IMAGE", (PointerToMessageBaseNew)&igtl::GetImageMessage::New); + this->AddMessageType("STATUS", (PointerToMessageBaseNew)&igtl::StatusMessage::New); + this->AddMessageType("GET_STATUS", (PointerToMessageBaseNew)&igtl::GetStatusMessage::New); + this->AddMessageType("CAPABILITY", (PointerToMessageBaseNew)&igtl::CapabilityMessage::New); +#if OpenIGTLink_PROTOCOL_VERSION >= 2 + this->AddMessageType("POINT", (PointerToMessageBaseNew)&igtl::PointMessage::New); + this->AddMessageType("GET_POINT", (PointerToMessageBaseNew)&igtl::GetPointMessage::New); + this->AddMessageType("TRAJ", (PointerToMessageBaseNew)&igtl::TrajectoryMessage::New); + this->AddMessageType("GET_TRAJ", (PointerToMessageBaseNew)&igtl::GetTrajectoryMessage::New); + this->AddMessageType("STRING", (PointerToMessageBaseNew)&igtl::StringMessage::New); + this->AddMessageType("TDATA", (PointerToMessageBaseNew)&igtl::TrackingDataMessage::New); + this->AddMessageType("POLYDATA", (PointerToMessageBaseNew)&igtl::PolyDataMessage::New); + this->AddMessageType("GET_POLYDATA", (PointerToMessageBaseNew)&igtl::GetPolyDataMessage::New); + this->AddMessageType("RTS_POLYDATA", (PointerToMessageBaseNew)&igtl::RTSPolyDataMessage::New); + this->AddMessageType("STT_POLYDATA", (PointerToMessageBaseNew)&igtl::StartPolyDataMessage::New); + this->AddMessageType("STP_POLYDATA", (PointerToMessageBaseNew)&igtl::StopPolyDataMessage::New); + this->AddMessageType("RTS_TDATA", (PointerToMessageBaseNew)&igtl::RTSTrackingDataMessage::New); + this->AddMessageType("STT_TDATA", (PointerToMessageBaseNew)&igtl::StartTrackingDataMessage::New); + this->AddMessageType("STP_TDATA", (PointerToMessageBaseNew)&igtl::StopTrackingDataMessage::New); + this->AddMessageType("QTDATA", (PointerToMessageBaseNew)&igtl::QuaternionTrackingDataMessage::New); + this->AddMessageType("RTS_QTDATA", (PointerToMessageBaseNew)&igtl::RTSQuaternionTrackingDataMessage::New); + this->AddMessageType("STT_QTDATA", (PointerToMessageBaseNew)&igtl::StartQuaternionTrackingDataMessage::New); + this->AddMessageType("STP_QTDATA", (PointerToMessageBaseNew)&igtl::StopQuaternionTrackingDataMessage::New); + this->AddMessageType("GET_IMGMETA", (PointerToMessageBaseNew)&igtl::GetImageMetaMessage::New); + this->AddMessageType("IMGMETA", (PointerToMessageBaseNew)&igtl::ImageMetaMessage::New); + this->AddMessageType("GET_LBMETA", (PointerToMessageBaseNew)&igtl::GetLabelMetaMessage::New); + this->AddMessageType("LBMETA", (PointerToMessageBaseNew)&igtl::LabelMetaMessage::New); +#endif + +#if OpenIGTLink_PROTOCOL_VERSION >= 3 + this->AddMessageType("COMMAND", (PointerToMessageBaseNew)&igtl::CommandMessage::New); + this->AddMessageType("RTS_COMMAND", (PointerToMessageBaseNew)&igtl::RTSCommandMessage::New); +#endif + +#if defined(OpenIGTLink_ENABLE_VIDEOSTREAMING) + this->AddMessageType("VIDEO", (PointerToMessageBaseNew)&igtl::VideoMessage::New); +#endif +} + + +//----------------------------------------------------------------------------- +MessageFactory::~MessageFactory() +{ +} + +//----------------------------------------------------------------------------- +void MessageFactory::AddMessageType(const std::string& messageTypeName, MessageFactory::PointerToMessageBaseNew messageTypeNewPointer ) +{ + this->IgtlMessageTypes[messageTypeName] = messageTypeNewPointer; +} + +//---------------------------------------------------------------------------- +MessageFactory::PointerToMessageBaseNew MessageFactory::GetMessageTypeNewPointer(const std::string& messageTypeName) const +{ + if ( this->IgtlMessageTypes.find(messageTypeName) != this->IgtlMessageTypes.end() ) + { + return this->IgtlMessageTypes.find(messageTypeName)->second; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +bool MessageFactory::IsValid(igtl::MessageHeader::Pointer headerMsg) +{ + bool result = false; + +#if OpenIGTLink_HEADER_VERSION >= 2 + if (headerMsg.IsNotNull() && IgtlMessageTypes.find(headerMsg->GetMessageType()) != IgtlMessageTypes.end() ) +#else + if (headerMsg.IsNotNull() && IgtlMessageTypes.find(headerMsg->GetDeviceType()) != IgtlMessageTypes.end()) +#endif + { + result = true; + } + return result; +} + +//---------------------------------------------------------------------------- +bool MessageFactory::IsValid(igtl::MessageHeader::Pointer headerMsg) const +{ + bool result = false; + +#if OpenIGTLink_HEADER_VERSION >= 2 + if (headerMsg.IsNotNull() && IgtlMessageTypes.find(headerMsg->GetMessageType()) != IgtlMessageTypes.end() ) +#else + if (headerMsg.IsNotNull() && IgtlMessageTypes.find(headerMsg->GetDeviceType()) != IgtlMessageTypes.end()) +#endif + { + result = true; + } + return result; +} + +//----------------------------------------------------------------------------- +igtl::MessageBase::Pointer MessageFactory::GetMessage(igtl::MessageHeader::Pointer headerMsg) +{ + if (headerMsg.IsNull()) + { + return NULL; + } + +#if OpenIGTLink_HEADER_VERSION >= 2 + std::string messageType(headerMsg->GetMessageType()); +#else + std::string messageType(headerMsg->GetDeviceType()); +#endif + + if (!this->IsValid(headerMsg)) + { + return NULL; + } + + std::string messageTypeUpper(messageType); + std::transform(messageTypeUpper.begin(), messageTypeUpper.end(), messageTypeUpper.begin(), ::toupper); + + igtl::MessageBase::Pointer result = NULL; + if( GetMessageTypeNewPointer(messageTypeUpper) == NULL ) + { + return NULL; + } + result = GetMessageTypeNewPointer(messageTypeUpper)(); + + // Must have a valid message at this point, otherwise its a programming bug. + assert(result.IsNotNull()); + + result->SetMessageHeader(headerMsg); + result->InitBuffer(); + + return result; +} + +//---------------------------------------------------------------------------- +igtl::MessageHeader::Pointer MessageFactory::CreateHeaderMessage(int headerVersion) const +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->SetHeaderVersion(headerVersion); + headerMsg->InitBuffer(); + + return headerMsg; +} + +//---------------------------------------------------------------------------- +igtl::MessageBase::Pointer MessageFactory::CreateReceiveMessage(igtl::MessageHeader::Pointer headerMsg) const +{ + if (headerMsg.IsNull()) + { + return NULL; + } + +#if OpenIGTLink_HEADER_VERSION >= 2 + std::string messageType(headerMsg->GetMessageType()); +#else + std::string messageType(headerMsg->GetDeviceType()); +#endif + std::string messageTypeUpper(messageType); + std::transform(messageTypeUpper.begin(), messageTypeUpper.end(), messageTypeUpper.begin(), ::toupper); + + if (!this->IsValid(headerMsg)) + { + return NULL; + } + + igtl::MessageBase::Pointer result = NULL; + if( GetMessageTypeNewPointer(messageTypeUpper) == NULL ) + { + return NULL; + } + result = GetMessageTypeNewPointer(messageTypeUpper)(); + + // Must have a valid message at this point, otherwise its a programming bug. + assert(result.IsNotNull()); + + result->SetMessageHeader(headerMsg); + result->AllocateBuffer(); + + return result; +} + +//---------------------------------------------------------------------------- +igtl::MessageBase::Pointer MessageFactory::CreateSendMessage(const std::string& messageType, int headerVersion) const +{ + if (messageType.empty()) + { + return NULL; + } + + std::string messageTypeUpper(messageType); + std::transform(messageTypeUpper.begin(), messageTypeUpper.end(), messageTypeUpper.begin(), ::toupper); + + igtl::MessageBase::Pointer result = NULL; + if( GetMessageTypeNewPointer(messageTypeUpper) == NULL ) + { + return NULL; + } + result = GetMessageTypeNewPointer(messageTypeUpper)(); + + // Must have a valid message at this point, otherwise its a programming bug. + assert(result.IsNotNull()); + + result->SetDeviceType(messageTypeUpper); + result->SetHeaderVersion(headerVersion); + result->InitBuffer(); + return result; +} + +//---------------------------------------------------------------------------- +void MessageFactory::GetAvailableMessageTypes(std::vector& types) const +{ + types.clear(); + for( std::map::const_iterator it = IgtlMessageTypes.begin(); it != IgtlMessageTypes.end(); ++it ) + { + types.push_back(it->first); + } + + return; +} + +} // end namespace diff --git a/openigtlink/repo/Source/igtlMessageFactory.h b/openigtlink/repo/Source/igtlMessageFactory.h new file mode 100644 index 0000000..0bce6e9 --- /dev/null +++ b/openigtlink/repo/Source/igtlMessageFactory.h @@ -0,0 +1,93 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlMessageFactory_h +#define __igtlMessageFactory_h + +#include "igtlMacro.h" +#include "igtlMessageBase.h" +#include "igtlMessageHeader.h" +#include "igtlObject.h" +#include "igtl_header.h" + +#include + +namespace igtl +{ + +class IGTLCommon_EXPORT MessageFactory: public Object +{ +public: + igtlTypeMacro(MessageFactory, Object) + igtlNewMacro(MessageFactory); + + /*! Function pointer for storing New() static methods of igtl::MessageBase classes */ + typedef igtl::MessageBase::Pointer (*PointerToMessageBaseNew)(); + + /// Add message type name and pointer to IGTL message new function + /// Usage: AddMessageType( "IMAGE", (PointerToMessageBaseNew)&igtl::ImageMessage::New ); + /// \param messageTypeName The name of the message type + /// \param messageTypeNewPointer Function pointer to the message type new function (e.g. (PointerToMessageBaseNew)&igtl::ImageMessage::New ) + virtual void AddMessageType(const std::string& messageTypeName, MessageFactory::PointerToMessageBaseNew messageTypeNewPointer); + + /// Get pointer to message type new function, or NULL if the message type not registered + /// Usage: igtl::MessageBase::Pointer message = GetMessageTypeNewPointer("IMAGE")(); + /// Returns NULL if message type is not found + virtual MessageFactory::PointerToMessageBaseNew GetMessageTypeNewPointer(const std::string& messageTypeName) const; + + /// Checks that headerMsg is not null and the headerMsg->GetDeviceType() refers to a valid type, returning true if valid, and false otherwise. + bool IsValid(igtl::MessageHeader::Pointer headerMsg); + + /// Checks that headerMsg is not null and the headerMsg->GetDeviceType() refers to a valid type, returning true if valid, and false otherwise. + bool IsValid(igtl::MessageHeader::Pointer headerMsg) const; + + /// LEGACY method, use CreateReceiveMessage instead + /// Constructs a message from the given header. + /// Returns NULL if headerMsg is NULL. + /// Returns NULL if this->IsValid(headerMsg) returns false. + /// Creates message, sets header onto message and calls AllocateBuffer() on the message. + igtl::MessageBase::Pointer GetMessage(igtl::MessageHeader::Pointer headerMsg); + + /// Constructs a message header. + /// Returns NULL if headerMsg is NULL. + /// Returns NULL if this->IsValid(headerMsg) returns false. + /// Creates message, calls InitBuffer() + igtl::MessageHeader::Pointer CreateHeaderMessage(int headerVersion) const; + + /// Constructs a message from the given populated header. + /// Returns NULL if headerMsg is NULL. + /// Returns NULL if this->IsValid(headerMsg) returns false. + /// Creates message, sets header onto message and calls AllocatePack() on the message. + igtl::MessageBase::Pointer CreateReceiveMessage(igtl::MessageHeader::Pointer headerMsg) const; + + /// Constructs an empty message from the given message type. + /// Returns NULL if messageType is empty. + /// Creates message, sets header onto message and calls AllocatePack() on the message. + igtl::MessageBase::Pointer CreateSendMessage(const std::string& messageType, int headerVersion) const; + + /// Return the list of known message types + void GetAvailableMessageTypes(std::vector& types) const; + +protected: + MessageFactory(); + ~MessageFactory(); + +private: + /*! Map igt message types and the New() static methods of igtl::MessageBase classes */ + std::map IgtlMessageTypes; + +}; // end class + +} // end namespace + +#endif // __igtlMessageFactory_h diff --git a/openigtlink/repo/Source/igtlMessageHandler.h b/openigtlink/repo/Source/igtlMessageHandler.h new file mode 100644 index 0000000..399370c --- /dev/null +++ b/openigtlink/repo/Source/igtlMessageHandler.h @@ -0,0 +1,60 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: git@github.com:openigtlink/OpenIGTLink.git + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlMessageHandler_h +#define __igtlMessageHandler_h + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlSocket.h" +#include "igtlMessageBase.h" + +namespace igtl +{ + +class IGTLCommon_EXPORT MessageHandler: public Object +{ + public: + igtlTypeMacro(igtl::MessageHandler, igtl::Object) + igtlNewMacro(igtl::MessageHandler); + + public: + virtual const char* GetMessageType() { return ""; } +#if OpenIGTLink_HEADER_VERSION >= 2 + virtual std::string GetMessageType() const { return std::string(""); } +#endif + virtual igtl_uint64 ReceiveMessage(Socket*, MessageBase*, int) { return 0; }; + + void SetMessageBuffer(MessageBase* buffer) { this->m_Buffer = buffer; } + MessageBase * GetMessageBuffer() { return this->m_Buffer; } + + protected: + MessageHandler() {} + ~MessageHandler() {} + + + + protected: + MessageBase * m_Buffer; + +}; + +} // namespace igtl + +#endif // _igtlMessageHandler_h + + + + + diff --git a/openigtlink/repo/Source/igtlMessageHandlerMacro.h b/openigtlink/repo/Source/igtlMessageHandlerMacro.h new file mode 100644 index 0000000..a6c9b21 --- /dev/null +++ b/openigtlink/repo/Source/igtlMessageHandlerMacro.h @@ -0,0 +1,184 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: git@github.com:openigtlink/OpenIGTLink.git + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlMessageHandlerMacro_h +#define __igtlMessageHandlerMacro_h + +#include "igtlMessageHandler.h" + +// Description: +// The igtlMessageHandlerClassMacro() macro is to help developers to +// define message handler class. It generates a child class of igtl::MessageHandler. +// The developer only needs to implement ProcessMessage() after calling this macro. +// The following code shows how to define a handler that processes IMAGE message: +// +// igtlMessageHandlerClassMacro(igtl::ImageMessage, TestImageMessageHandler); +// void TestImageMessageHandler::Process(igtl::ImageMessage * message) +// { +// // do something +// } +using igtl::SmartPointer; +#if OpenIGTLink_PROTOCOL_VERSION >= 3 +#define igtlMessageHandlerClassMacro(messagetype, classname, datatype) \ + class classname : public ::igtl::MessageHandler \ + { \ + public: \ + igtlTypeMacro(classname, ::igtl::MessageHandler); \ + igtlNewMacro(classname); \ + public: \ + virtual const char* GetMessageType() \ + { \ + return this->m_Message->GetDeviceType(); \ + } \ + virtual int Process(messagetype*, datatype*); \ + igtl_uint64 ReceiveMessage(::igtl::Socket* socket, ::igtl::MessageBase* header, int pos) \ + { \ + if (pos == 0) /* New body */ \ + { \ + this->m_Message->SetMessageHeader(header); \ + this->m_Message->AllocateBuffer(); \ + } \ + bool timeout(false); \ + igtl_uint64 s = socket->Receive((void*)((char*)this->m_Message->GetBufferBodyPointer()+pos), \ + this->m_Message->GetBufferBodySize()-pos, timeout); \ + if (timeout) /* Time out */ \ + { \ + return pos; \ + } \ + if (s+pos >= this->m_Message->GetBufferBodySize()) \ + { \ + int r = this->m_Message->Unpack(this->m_CheckCRC); \ + if (r) \ + { \ + Process(this->m_Message, this->m_Data); \ + } \ + else \ + { \ + return -1; \ + } \ + } \ + return s + pos; /* return current position in the body */ \ + } \ + virtual void CheckCRC(int i) \ + { \ + if (i == 0) \ + { \ + this->m_CheckCRC = 0; \ + } \ + else \ + { \ + this->m_CheckCRC = 1; \ + } \ + } \ + void SetData(datatype* p) \ + { \ + this->m_Data = p; \ + } \ + datatype* GetData() \ + { \ + return this->m_Data; \ + } \ + protected: \ + classname() \ + { \ + this->m_Message = messagetype::New(); \ + this->m_CheckCRC = 1; \ + this->m_Data = NULL; \ + } \ + ~classname() {} \ + protected: \ + int m_CheckCRC; \ + messagetype::Pointer m_Message; \ + datatype* m_Data; \ + }; +#else + #define igtlMessageHandlerClassMacro(messagetype, classname, datatype) \ + class classname : public ::igtl::MessageHandler \ + { \ + public: \ + igtlTypeMacro(classname, ::igtl::MessageHandler); \ + igtlNewMacro(classname); \ + public: \ + virtual std::string GetMessageType() const \ + { \ + return this->m_Message->GetMessageType(); \ + } \ + virtual const char* GetMessageType() \ + { \ + return this->m_Message->GetDeviceType(); \ + } \ + virtual int Process(messagetype*, datatype*); \ + igtl_uint64 ReceiveMessage(::igtl::Socket* socket, ::igtl::MessageBase* header, int pos) \ + { \ + if (pos == 0) /* New body */ \ + { \ + this->m_Message->SetMessageHeader(header); \ + this->m_Message->AllocateBuffer(); \ + } \ + bool timeout(false); \ + igtl_uint64 s = socket->Receive((void*)((char*)this->m_Message->GetBufferBodyPointer()+pos), \ + this->m_Message->GetBufferBodySize()-pos, timeout); \ + if (timeout) /* Time out */ \ + { \ + return pos; \ + } \ + if (s+pos >= this->m_Message->GetBufferBodySize()) \ + { \ + int r = this->m_Message->Unpack(this->m_CheckCRC); \ + if (r) \ + { \ + Process(this->m_Message, this->m_Data); \ + } \ + else \ + { \ + return -1; \ + } \ + } \ + return s + pos; /* return current position in the body */ \ + } \ + virtual void CheckCRC(int i) \ + { \ + if (i == 0) \ + { \ + this->m_CheckCRC = 0; \ + } \ + else \ + { \ + this->m_CheckCRC = 1; \ + } \ + } \ + void SetData(datatype* p) \ + { \ + this->m_Data = p; \ + } \ + datatype* GetData() \ + { \ + return this->m_Data; \ + } \ + protected: \ + classname() \ + { \ + this->m_Message = messagetype::New(); \ + this->m_CheckCRC = 1; \ + this->m_Data = NULL; \ + } \ + ~classname() {} \ + protected: \ + int m_CheckCRC; \ + messagetype::Pointer m_Message; \ + datatype* m_Data; \ + }; +#endif + +#endif // __igtlMessageHandlerMacro_h diff --git a/openigtlink/repo/Source/igtlMessageHeader.h b/openigtlink/repo/Source/igtlMessageHeader.h new file mode 100644 index 0000000..86c9021 --- /dev/null +++ b/openigtlink/repo/Source/igtlMessageHeader.h @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlMessageHeader_h +#define __igtlMessageHeader_h + +namespace igtl +{ +/// The MessageHeader class is used to receive and parse general headers +/// to prepare for receiving body data. The class is currently just the alias +/// of MessageBase class. Please refer igtlMessageBase.h for more details and +/// the implementation of the class. +/// +/// The following is the typical unpacking (deserialization) procedures +/// using igtl::MessssageHeader class: +/// +/// // Create instance and set Device Name +/// igtl::MessageBase::Pointer headerMsg; +/// headerMsg = igtl::MessageBase::New(); +/// +/// // Initialize receive buffer +/// // Set up memory area to and receive the general header and unpack +/// headerMsg->InitPack(); +/// +/// socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize()); +/// headerMsg->Unpack(); +/// +/// // Check data type string +/// if (strcmp(headerMsg->GetDeviceType(), "TRANSFORM")) +/// { +/// igtl::TransformMessage::Pointer transMsg; +/// transMsg = igtl::TransformMessage::New(); +/// transMsg->SetMessageHeader(headerMsg); +/// transMsg->AllocatePack(); +/// +/// // Receive transform data from the socket// +/// socket->Receive(transMsg->GetPackBodyPointer(), transMsg->GetPackBodySize()); +/// +/// // Deserialize the transform data +/// transMsg->Unpack(); +/// +/// // Retrive the transform data +/// igtl::Matrix4x4 matrix; +/// transMsg->GetMatrix(matrix); +/// +/// .... +/// +/// } +/// else if (strcmp(headerMsg->GetDeviceType(), "IMAGE")) +/// { +/// igtl::ImageMessage::Pointer imageMsg; +/// imageMsg = igtl::ImageMessage::New(); +/// transMsg->SetMessageHeader(headerMsg); +/// imageMsg->AllocatePack(); +/// socket->Receive(imageMsg->GetPackBodyPointer(), imageMsg->GetPackBodySize()); +/// imageMsg->Unpack(); +/// } +/// else if (...) +/// { +/// ... +/// } + class MessageBase; + typedef class MessageBase MessageHeader; + +}; + +#include "igtlMessageBase.h" + + +#endif //__igtlMessageHeader_h diff --git a/openigtlink/repo/Source/igtlMessageRTPWrapper.cxx b/openigtlink/repo/Source/igtlMessageRTPWrapper.cxx new file mode 100755 index 0000000..ca67606 --- /dev/null +++ b/openigtlink/repo/Source/igtlMessageRTPWrapper.cxx @@ -0,0 +1,606 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlMessageRTPWrapper.h" +#include + + +namespace igtl { + + MessageRTPWrapper::MessageRTPWrapper():Object() + { + this->SeqNum = 0; + this->RTPPayloadLength = RTP_PAYLOAD_LENGTH; + this->AvailabeBytesNum = RTP_PAYLOAD_LENGTH; + this->numberOfDataFrag = 1; + this->numberOfDataFragToSent = 1; + this->packedMsg = NULL; + this->appSpecificFreq = 100; + this->status = PacketReady; + this->curMSGLocation = 0; + this->curPackedMSGLocation = 0; + this->fragmentNumber = 0; + this->MSGHeader= new igtl_uint8[IGTL_HEADER_SIZE + IGTL_EXTENDED_HEADER_SIZE]; + this->glock = igtl::SimpleMutexLock::New(); + this->incommingPackets = igtl::PacketBuffer(); + this->reorderBuffer = new igtl::ReorderBuffer(); + this->reorderBufferMap = std::map(); + this->fragmentNumberList=std::vector(); + this->PacketSendTimeStampList = std::vector(); + this->PacketBeforeSendTimeStampList = std::vector(); + this->PacketTotalLengthList = std::vector(); + this->wrapperTimer = igtl::TimeStamp::New(); + this->FCFS=true; + this->packetIntervalTime = 1; + this->SSRC = 0; + this->RTPPayloadType = 96; // https://tools.ietf.org/html/rfc3551#page-32 ,96 to 127 is for dynamic allocated type. + } + + MessageRTPWrapper::~MessageRTPWrapper() + { + glock->Lock(); + std::map::iterator itr = this->reorderBufferMap.begin(); + while (itr != this->reorderBufferMap.end()) + { + // found it - delete it + itr->second->~ReorderBuffer(); + this->reorderBufferMap.erase(itr); + if(this->reorderBufferMap.size()==0) + { + break; + } + itr++; + } + std::map::iterator itr2 = this->unWrappedMessages.begin(); + while (itr2 != this->unWrappedMessages.end()) + { + // found it - delete it + itr2->second->~UnWrappedMessage(); + this->unWrappedMessages.erase(itr2); + if(this->unWrappedMessages.size()==0) + { + break; + } + itr2++; + } + glock->Unlock(); + glock = NULL; + } + + + void MessageRTPWrapper::SetMSGHeader(igtl_uint8* header) + { + memcpy(this->MSGHeader, header, IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE); + ///Left shift the lower byte of the message ID by two bytes. and fill the last two byte with NoFragmentIndicator + /// only valid if the messageID is less than 2^16. + memcpy(this->MSGHeader+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-sizeof(messageID), this->MSGHeader+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-FragmentIndexBytes,FragmentIndexBytes); + igtl_uint16 temp = NoFragmentIndicator; + memcpy(this->MSGHeader+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-FragmentIndexBytes, (void*)(&temp), FragmentIndexBytes); + } + + + void MessageRTPWrapper::SetSSRC(igtl_uint32 identifier) + { + SSRC = identifier; + if(igtl_is_little_endian()) + { + SSRC = BYTE_SWAP_INT32(SSRC); + } + } + + void MessageRTPWrapper::SetCSRC(igtl_uint32 identifier) + { + CSRC = identifier; + if(igtl_is_little_endian()) + { + CSRC = BYTE_SWAP_INT32(CSRC); + } + } + + void MessageRTPWrapper::SetSeqNum(igtl_uint16 num) + { + SeqNum = num; + if(igtl_is_little_endian()) + { + SeqNum = BYTE_SWAP_INT16(num); + } + } + + int MessageRTPWrapper::PushDataIntoPacketBuffer(igtlUint8* UDPPacket, igtlUint16 PacketLen) + { + this->glock->Lock(); + if(this->incommingPackets.pPacketLengthInByte.size()>PacketMaximumBufferNum) + { + igtlUint16 firstMsgLen = this->incommingPackets.pPacketLengthInByte[0]; + this->incommingPackets.pPacketLengthInByte.erase(this->incommingPackets.pPacketLengthInByte.begin()); + this->incommingPackets.pBsBuf.erase(this->incommingPackets.pBsBuf.begin(), this->incommingPackets.pBsBuf.begin()+firstMsgLen); + this->incommingPackets.totalLength -= firstMsgLen; + } + this->incommingPackets.pPacketLengthInByte.push_back(PacketLen); + this->incommingPackets.pBsBuf.insert(this->incommingPackets.pBsBuf.end(), UDPPacket, UDPPacket+PacketLen); + this->incommingPackets.totalLength += PacketLen; + if (this->incommingPackets.totalLength == this->incommingPackets.pBsBuf.size()) + { + this->glock->Unlock(); + return 1; + + } + else + { + this->glock->Unlock(); + return 0; + } + } + + int MessageRTPWrapper::SendBufferedDataWithInterval(igtl::UDPServerSocket::Pointer &socket, int interval) //interval is in nanosecond + { + int totalMsgLen = this->outgoingPackets.totalLength; + int sendMsgLen = 0; + while (this->outgoingPackets.pPacketLengthInByte.size()) + { + igtlUint8 * UDPPacket; + igtlUint16 currentMsgLen; + this->glock->Lock(); + if(this->FCFS==true) + { + currentMsgLen = this->outgoingPackets.pPacketLengthInByte[0]; + UDPPacket = new igtlUint8[currentMsgLen]; + memcpy(UDPPacket, this->outgoingPackets.pBsBuf.data(), currentMsgLen); + this->outgoingPackets.pPacketLengthInByte.erase(this->outgoingPackets.pPacketLengthInByte.begin()); + this->outgoingPackets.pBsBuf.erase(this->outgoingPackets.pBsBuf.begin(), this->outgoingPackets.pBsBuf.begin()+currentMsgLen); + this->outgoingPackets.totalLength -= currentMsgLen; + } + else + { + int packetNum = outgoingPackets.pPacketLengthInByte.size(); + currentMsgLen = this->outgoingPackets.pPacketLengthInByte[packetNum-1]; + UDPPacket = new igtlUint8[currentMsgLen]; + memcpy(UDPPacket, this->outgoingPackets.pBsBuf.data() + this->outgoingPackets.pBsBuf.size()-currentMsgLen, currentMsgLen); + this->outgoingPackets.pPacketLengthInByte.erase(this->outgoingPackets.pPacketLengthInByte.end()-1); + this->outgoingPackets.pBsBuf.erase(this->outgoingPackets.pBsBuf.begin() + this->outgoingPackets.pBsBuf.size()-currentMsgLen, this->outgoingPackets.pBsBuf.end()); + this->outgoingPackets.totalLength -= currentMsgLen; + } + this->glock->Unlock(); + int numByteSent = socket->WriteSocket(UDPPacket, currentMsgLen); + sendMsgLen += numByteSent; + if (numByteSent != currentMsgLen) + { + return 0; + } + } + if (sendMsgLen == totalMsgLen) + { + return 1; + } + else + { + return 0; + } + } + + int MessageRTPWrapper::WrapMessageAndPushToBuffer(igtl_uint8* messagePackPointer, int msgtotalLen) + { + igtl_uint8* messageContentPointer = messagePackPointer+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE; + this->SetMSGHeader((igtl_uint8*)messagePackPointer); + int MSGContentLength = msgtotalLen - IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE; // this is the m_content size + meta data size + int leftMsgLen = MSGContentLength; + igtl_uint8* leftmessageContent = messageContentPointer; + this->PacketTotalLengthList.clear(); + do + { + status = this->WrapMessage(leftmessageContent, leftMsgLen); + if (status == igtl::MessageRTPWrapper::ProcessFragment || status == igtl::MessageRTPWrapper::PacketReady) + { + this->glock->Lock(); + if(this->outgoingPackets.pPacketLengthInByte.size()>PacketMaximumBufferNum) + { + igtlUint16 firstMsgLen = this->outgoingPackets.pPacketLengthInByte[0]; + this->outgoingPackets.pPacketLengthInByte.erase(this->outgoingPackets.pPacketLengthInByte.begin()); + this->outgoingPackets.pBsBuf.erase(this->outgoingPackets.pBsBuf.begin(), this->outgoingPackets.pBsBuf.begin()+firstMsgLen); + this->outgoingPackets.totalLength -= firstMsgLen; + } + this->outgoingPackets.pPacketLengthInByte.push_back(this->GetPackedMSGLocation()); + this->outgoingPackets.pBsBuf.insert(this->outgoingPackets.pBsBuf.end(), this->GetPackPointer(), this->GetPackPointer()+this->GetPackedMSGLocation()); + this->outgoingPackets.totalLength += this->GetPackedMSGLocation(); + this->PacketTotalLengthList.push_back(this->GetPackedMSGLocation()); + if (this->outgoingPackets.totalLength == this->outgoingPackets.pBsBuf.size()) + { + this->glock->Unlock(); + } + else + { + this->glock->Unlock(); + return 0; + } + } + leftmessageContent = messageContentPointer + this->GetCurMSGLocation(); + leftMsgLen = MSGContentLength - this->GetCurMSGLocation(); + }while(leftMsgLen>0 && status!=igtl::MessageRTPWrapper::PacketReady); // to do when bodyMsgLen + return 1; + } + + + int MessageRTPWrapper::UnWrapPacketWithTypeAndName(const char *deviceType, const char * deviceName) + { + if (this->incommingPackets.pPacketLengthInByte.size()) + { + this->glock->Lock(); + igtlUint8 * UDPPacket; + igtlUint16 totMsgLen; + if(this->FCFS==true) + { + totMsgLen = this->incommingPackets.pPacketLengthInByte[0]; + UDPPacket = new igtlUint8[totMsgLen]; + memcpy(UDPPacket, this->incommingPackets.pBsBuf.data(), totMsgLen); + this->incommingPackets.pPacketLengthInByte.erase(this->incommingPackets.pPacketLengthInByte.begin()); + this->incommingPackets.pBsBuf.erase(this->incommingPackets.pBsBuf.begin(), this->incommingPackets.pBsBuf.begin()+totMsgLen); + this->incommingPackets.totalLength -= totMsgLen; + } + else + { + int packetNum = incommingPackets.pPacketLengthInByte.size(); + totMsgLen = this->incommingPackets.pPacketLengthInByte[packetNum-1]; + UDPPacket = new igtlUint8[totMsgLen]; + memcpy(UDPPacket, this->incommingPackets.pBsBuf.data() + this->incommingPackets.pBsBuf.size()-totMsgLen, totMsgLen); + this->incommingPackets.pPacketLengthInByte.erase(this->incommingPackets.pPacketLengthInByte.end()-1); + this->incommingPackets.pBsBuf.erase(this->incommingPackets.pBsBuf.begin() + this->incommingPackets.pBsBuf.size()-totMsgLen, this->incommingPackets.pBsBuf.end()); + this->incommingPackets.totalLength -= totMsgLen; + } + this->glock->Unlock(); + // Set up the RTP header: + igtl_uint32 rtpProfileBytes, timeIncrement; + rtpProfileBytes = *((igtl_uint32*)UDPPacket); + //bool rtpMarkerBit = (rtpHdr&0x00800000) != 0; + timeIncrement = *(igtl_uint32*)(UDPPacket+sizeof(rtpProfileBytes)); + igtl_uint32 SSRC = *(igtl_uint32*)(UDPPacket+sizeof(rtpProfileBytes)+sizeof(timeIncrement)); + if(igtl_is_little_endian()) + { + rtpProfileBytes = BYTE_SWAP_INT32(rtpProfileBytes); + timeIncrement = BYTE_SWAP_INT32(timeIncrement); + SSRC = BYTE_SWAP_INT32(SSRC); + } + int curPackedMSGLocation = RTP_HEADER_LENGTH; + status = WaitingForAnotherPacket; + while(curPackedMSGLocationAllocatePack(); + memcpy(header->GetPackPointer(), UDPPacket + curPackedMSGLocation, IGTL_HEADER_SIZE); + igtl_uint16 fragmentField; + memcpy(&fragmentField, (void*)(UDPPacket + RTP_HEADER_LENGTH+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-FragmentIndexBytes),FragmentIndexBytes); + messageID = 0; + //fill the lower two bytes of message ID with the upper two byte from packet data. + memcpy((char*)(&messageID)+FragmentIndexBytes, (void*)(UDPPacket + RTP_HEADER_LENGTH+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-sizeof(messageID)), FragmentIndexBytes); + // Get rid of the fragment field number. + memcpy((void*)(UDPPacket + RTP_HEADER_LENGTH+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-sizeof(messageID)), &messageID, sizeof(messageID)); + if(igtl_is_little_endian()) + { + fragmentField = BYTE_SWAP_INT16(fragmentField); + } + //this->reorderBufferMap.erase(it); + if (reorderBufferMap.size()>ReorderBufferMaximumSize) // get rid of the first reoderBuffer when waiting for a long time + { + if(reorderBufferMap.begin()->first != messageID) + { + reorderBufferMap.erase(reorderBufferMap.begin()); + } + else + { + reorderBufferMap.erase(reorderBufferMap.begin()++); + } + } + std::map::iterator it = this->reorderBufferMap.find(messageID); + if (it == this->reorderBufferMap.end()) + { + this->reorderBufferMap.insert(std::pair(messageID,new igtl::ReorderBuffer())); + it = this->reorderBufferMap.find(messageID); + + } + this->reorderBuffer = it->second; + header->Unpack(); + if(fragmentField==NoFragmentIndicator) // fragment doesn't exist + { + if (strcmp(header->GetDeviceType(),deviceType)==0 && strcmp(header->GetDeviceName(),deviceName)==0) + { + memcpy(this->reorderBuffer->firstFragBuffer, UDPPacket + curPackedMSGLocation, header->GetBodySizeToRead()+IGTL_HEADER_SIZE); + this->reorderBuffer->filledPacketNum = 1; + reorderBuffer->receivedFirstFrag = true; + reorderBuffer->receivedLastFrag = true; + reorderBuffer->firstPacketLen = header->GetBodySizeToRead()+IGTL_HEADER_SIZE; + igtl::UnWrappedMessage* message = new igtl::UnWrappedMessage(); + message->messageDataLength = reorderBuffer->firstPacketLen; + memcpy(message->messagePackPointer, reorderBuffer->firstFragBuffer, reorderBuffer->firstPacketLen); + glock->Lock(); + unWrappedMessages.insert(std::pair(it->first,message)); + glock->Unlock(); + delete it->second; + it->second = NULL; + this->reorderBufferMap.erase(it); + status = MessageReady; + } + curPackedMSGLocation += header->GetBodySizeToRead()+IGTL_HEADER_SIZE; + } + else + { + if (strcmp(header->GetDeviceType(),deviceType)==0 && strcmp(header->GetDeviceName(),deviceName)==0) + { + int bodyMsgLength = (RTPPayloadLength-IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE);//this is the length of the body within a full fragment Packet + if(fragmentField==FragmentBeginIndicator)// To do, fix the issue when later fragment arrives earlier than the beginning fragment + { + *(UDPPacket + curPackedMSGLocation + IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-FragmentIndexBytes) = NoFragmentIndicator; // set the fragment no. to 0000 + memcpy(reorderBuffer->firstFragBuffer, UDPPacket + curPackedMSGLocation, totMsgLen-curPackedMSGLocation); + reorderBuffer->firstPacketLen = totMsgLen-curPackedMSGLocation; + curPackedMSGLocation = totMsgLen; + reorderBuffer->receivedFirstFrag = true; + status = WaitingForAnotherPacket; + } + else if(fragmentField>=FragmentEndIndicator)// this is the last fragment + { + reorderBuffer->totFragNumber = fragmentField - FragmentEndIndicator + 1; + memcpy(reorderBuffer->lastFragBuffer, UDPPacket + RTP_HEADER_LENGTH+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE, totMsgLen-(RTP_HEADER_LENGTH+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE)); + reorderBuffer->receivedLastFrag = true; + reorderBuffer->lastPacketLen = totMsgLen-(RTP_HEADER_LENGTH+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE); + curPackedMSGLocation = totMsgLen; + status = WaitingForAnotherPacket; + } + else if(fragmentField>FragmentBeginIndicator && fragmentFieldbuffer+(curFragNumber-1)*bodyMsgLength, UDPPacket + RTP_HEADER_LENGTH+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE, totMsgLen-(RTP_HEADER_LENGTH+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE)); + status = WaitingForAnotherPacket; + } + reorderBuffer->filledPacketNum++; + if(reorderBuffer->receivedFirstFrag == true && reorderBuffer->receivedLastFrag == true && reorderBuffer->filledPacketNum == reorderBuffer->totFragNumber) + { + igtl::UnWrappedMessage* message = new igtl::UnWrappedMessage(); + message->messageDataLength = reorderBuffer->lastPacketLen+reorderBuffer->firstPacketLen+ (reorderBuffer->totFragNumber-2)*(RTPPayloadLength-IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE); + memcpy(message->messagePackPointer, reorderBuffer->firstFragBuffer, reorderBuffer->firstPacketLen); + memcpy(message->messagePackPointer+reorderBuffer->firstPacketLen, reorderBuffer->buffer, (RTPPayloadLength-IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE)*(reorderBuffer->totFragNumber-2)); + memcpy(message->messagePackPointer+reorderBuffer->firstPacketLen+(RTPPayloadLength-IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE)*(reorderBuffer->totFragNumber-2), reorderBuffer->lastFragBuffer, reorderBuffer->lastPacketLen); + glock->Lock(); + unWrappedMessages.insert(std::pair(it->first,message)); + glock->Unlock(); + std::map::iterator it_forDelete= this->reorderBufferMap.begin(); + while(it_forDelete != this->reorderBufferMap.end()) + { + delete it_forDelete->second; + it_forDelete->second = NULL; + this->reorderBufferMap.erase(it_forDelete); + if (this->reorderBufferMap.size()) + { + if (it_forDelete->first == it->first) + { + break; + } + } + else + { + break; + } + it_forDelete = this->reorderBufferMap.begin(); + } + status = MessageReady; + } + } + else + { + curPackedMSGLocation = totMsgLen; + } + break; + } + } + delete[] UDPPacket; + return 1; + } + return 0; + } + + int MessageRTPWrapper::WrapMessageAndSend(igtl::UDPServerSocket::Pointer &socket, igtl_uint8* messagePackPointer, int msgtotalLen) + { + igtl_uint8* messageContentPointer = messagePackPointer+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE; + this->SetMSGHeader((igtl_uint8*)messagePackPointer); + int MSGContentLength = msgtotalLen- IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE; // this is the m_content size + meta data size + int leftMsgLen = MSGContentLength; + igtl_uint8* leftmessageContent = messageContentPointer; + this->fragmentNumberList.clear(); + this->PacketSendTimeStampList.clear(); + this->PacketBeforeSendTimeStampList.clear(); + this->PacketTotalLengthList.clear(); + do + { + status = this->WrapMessage(leftmessageContent, leftMsgLen); + if (status == igtl::MessageRTPWrapper::ProcessFragment || status == igtl::MessageRTPWrapper::PacketReady) + { + this->wrapperTimer->GetTime(); + this->PacketBeforeSendTimeStampList.push_back(this->wrapperTimer->GetTimeStampInNanoseconds()); + this->glock->Lock(); + int numByteSent = socket->WriteSocket(this->GetPackPointer(), this->GetPackedMSGLocation()); + this->glock->Unlock(); + this->fragmentNumberList.push_back(this->fragmentNumber); + this->wrapperTimer->GetTime(); + this->PacketSendTimeStampList.push_back(this->wrapperTimer->GetTimeStampInNanoseconds()); + this->PacketTotalLengthList.push_back(numByteSent); + } + this->SleepInNanoSecond(this->packetIntervalTime); + leftmessageContent = messageContentPointer + this->GetCurMSGLocation(); + leftMsgLen = MSGContentLength - this->GetCurMSGLocation(); + }while(leftMsgLen>0 && status!=igtl::MessageRTPWrapper::PacketReady); // to do when bodyMsgLen + return 1; + } + + void MessageRTPWrapper::SleepInNanoSecond(int nanoSecond) + { +#if defined(_WIN32) && !defined(__CYGWIN__) + + // Call Windows Native Sleep() function + //::Sleep(nanoSecond/1000); + +#else + + struct timespec req; + req.tv_sec = (int) nanoSecond/1000000000; + req.tv_nsec = nanoSecond % 1000000000; + + while ((nanosleep(&req, &req) == -1) && (errno == EINTR)) + { + continue; + } + +#endif + } + + // SSRC should be set only once before wraping the message in a transmission session. + // CSRC should be set when messages from different devices are packed into the same Packet. + // this special header is here for the compatiblity with standard RTP protocal. + // we have our own defined openigtlink header, which is 58 byte size. + // append the openigtlink header as the Extension header after CSRC. + int MessageRTPWrapper::WrapMessage(igtl_uint8* messageContent, int bodyMsgLen) + { + // Set up the RTP header: + igtl_uint32 rtpProfileBytes = 0x80000000; // RTP version 2; + rtpProfileBytes |= (RTPPayloadType<<16); + rtpProfileBytes |= SeqNum; // sequence number, increment the sequence number after sending the data + #if defined(WIN32) || defined(_WIN32) + + //LARGE_INTEGER tick; + // + //::QueryPerformanceCounter( &tick ); + // + //TimeStampType value = + // static_cast< TimeStampType >( (__int64)tick.QuadPart ) / + // this->m_WinFrequency; + // + //value += this->m_WinOrigin; + // + //double second = floor(value); + + clock_t time1 = clock(); + clock_t winOriginTime = time(NULL); + clock_t second = + (time1 - winOriginTime) / CLOCKS_PER_SEC; + clock_t microsecond = (time1 - winOriginTime) % CLOCKS_PER_SEC * (1e6 / CLOCKS_PER_SEC); + clock_t timeIncrement = appSpecificFreq*second; + timeIncrement += igtl_uint32(appSpecificFreq*(microsecond / 1.0e6) + 0.5); + #else + struct timeval timeNow; + gettimeofday(&timeNow, NULL); + igtl_uint32 timeIncrement = (appSpecificFreq*timeNow.tv_sec); //need to check the frequency of different application + timeIncrement += igtl_uint32(appSpecificFreq*(timeNow.tv_usec/1.0e6)+ 0.5); + #endif + //igtl_uint32 CSRC = 0x00000000; not used currently + if(igtl_is_little_endian()) + { + rtpProfileBytes = BYTE_SWAP_INT32(rtpProfileBytes); + timeIncrement = BYTE_SWAP_INT32(timeIncrement); + } + if (status == PacketReady) + { + delete packedMsg; + packedMsg = new unsigned char[RTPPayloadLength + RTP_HEADER_LENGTH]; + AvailabeBytesNum = RTPPayloadLength; + curMSGLocation = 0; + curPackedMSGLocation = 0; + fragmentNumber = -1; // -1 = 0XFFFF to indicate the message has no fragments + } + if (status != ProcessFragment) + { + this->fragmentTimeIncrement = timeIncrement; + memcpy(packedMsg, (void *)(&rtpProfileBytes), sizeof(rtpProfileBytes)); + memcpy(packedMsg+sizeof(rtpProfileBytes), (void *)(&timeIncrement), sizeof(timeIncrement)); + memcpy(packedMsg+sizeof(rtpProfileBytes)+sizeof(timeIncrement), (void *)(&SSRC), sizeof(SSRC)); // SSRC needs to set by different devices, collision should be avoided. + curPackedMSGLocation += RTP_HEADER_LENGTH; + if (bodyMsgLen <= (AvailabeBytesNum-IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE)) + { + igtl_uint16 temp = NoFragmentIndicator; + memcpy(this->MSGHeader+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-FragmentIndexBytes, (void*)&temp,FragmentIndexBytes);// no fragmented message here + memcpy(packedMsg+curPackedMSGLocation, this->MSGHeader, IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE); + curPackedMSGLocation += (IGTL_HEADER_SIZE + IGTL_EXTENDED_HEADER_SIZE); + memcpy(packedMsg + curPackedMSGLocation, (void *)(messageContent), bodyMsgLen); + AvailabeBytesNum -= (bodyMsgLen+IGTL_EXTENDED_HEADER_SIZE+IGTL_HEADER_SIZE); + curPackedMSGLocation += bodyMsgLen; + curMSGLocation += bodyMsgLen; + status = PacketReady;// now we send the Packet immediately, however, it is possible to send after the packt is full. + SeqNum++; + } + else if(bodyMsgLen > (AvailabeBytesNum-IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE)) + { + igtl_uint16 temp = FragmentBeginIndicator; + if(igtl_is_little_endian()) + { + temp = BYTE_SWAP_INT16(temp); + } + memcpy(this->MSGHeader+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-FragmentIndexBytes, (void*)&temp,FragmentIndexBytes);// no fragmented message here + // fragmented message exists, first bit indicate the existance, the second bit indicates if the current section is the ending fragment, the other 14 bits indicates the fragements' sequence number. + memcpy(packedMsg+curPackedMSGLocation, this->MSGHeader, IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE); + curPackedMSGLocation += (IGTL_HEADER_SIZE + IGTL_EXTENDED_HEADER_SIZE); + memcpy(packedMsg + curPackedMSGLocation, (void *)(messageContent), AvailabeBytesNum-IGTL_EXTENDED_HEADER_SIZE-IGTL_HEADER_SIZE); + status = ProcessFragment; + this->curPackedMSGLocation = RTPPayloadLength+RTP_HEADER_LENGTH; + this->curMSGLocation = AvailabeBytesNum-IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE; + AvailabeBytesNum = RTPPayloadLength; + SeqNum++; + fragmentNumber++; + } + } + else + { + memcpy(packedMsg, (void *)(&rtpProfileBytes), sizeof(rtpProfileBytes)); + memcpy(packedMsg+sizeof(rtpProfileBytes), (void *)(&this->fragmentTimeIncrement), sizeof(this->fragmentTimeIncrement)); + memcpy(packedMsg+sizeof(rtpProfileBytes)+sizeof(this->fragmentTimeIncrement), (void *)(&SSRC), sizeof(SSRC)); // SSRC needs to set by different devices, collision should be avoided. + curPackedMSGLocation = RTP_HEADER_LENGTH; + fragmentNumber++; + if (bodyMsgLen <= (AvailabeBytesNum-IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE)) + { + igtl_uint16 temp = FragmentEndIndicator+fragmentNumber; //set the seconde bit to be 1, indicates the end of fragmented msg.; + if(igtl_is_little_endian()) + { + temp = BYTE_SWAP_INT16(temp); + } + memcpy(this->MSGHeader+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-FragmentIndexBytes, (void*)&temp,FragmentIndexBytes); + // fragmented message exists, first bit indicate the existance, the second bit indicates if the current section is the ending fragment, the other 14 bits indicates the fragements' sequence number. + memcpy(packedMsg+curPackedMSGLocation, this->MSGHeader, IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE); + curPackedMSGLocation += (IGTL_HEADER_SIZE + IGTL_EXTENDED_HEADER_SIZE); + memcpy(packedMsg + curPackedMSGLocation, (void *)(messageContent), bodyMsgLen); + this->curPackedMSGLocation += bodyMsgLen; + // when it is packing the fragment, we want to sent the data ASAP, otherwize, we will wait for another message + this->curMSGLocation += bodyMsgLen; + status = PacketReady; + } + else if(bodyMsgLen > (AvailabeBytesNum-IGTL_HEADER_SIZE-IGTL_EXTENDED_HEADER_SIZE)) + { + igtl_uint16 temp = FragmentBeginIndicator+fragmentNumber; + if(igtl_is_little_endian()) + { + temp = BYTE_SWAP_INT16(temp); + } + memcpy(this->MSGHeader+IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE-FragmentIndexBytes, (void*)&temp,FragmentIndexBytes);//set the second bit to be 0, indicates more fragmented msg are comming. + memcpy(packedMsg+curPackedMSGLocation, MSGHeader, IGTL_HEADER_SIZE+IGTL_EXTENDED_HEADER_SIZE); + curPackedMSGLocation += (IGTL_HEADER_SIZE + IGTL_EXTENDED_HEADER_SIZE); + memcpy(packedMsg + curPackedMSGLocation, (void *)(messageContent), AvailabeBytesNum-IGTL_EXTENDED_HEADER_SIZE-IGTL_HEADER_SIZE); + status = ProcessFragment; + this->curMSGLocation += (AvailabeBytesNum-IGTL_EXTENDED_HEADER_SIZE-IGTL_HEADER_SIZE); + curPackedMSGLocation += (AvailabeBytesNum-IGTL_EXTENDED_HEADER_SIZE-IGTL_HEADER_SIZE); + } + AvailabeBytesNum = RTPPayloadLength; + SeqNum++; + } + return status; + } + + + igtl::MessageBase::Pointer MessageRTPWrapper::UnWrapMessage(igtl_uint8* messageContent, int bodyMsgLen) + { + return NULL; + } + +} // namespace igtl \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlMessageRTPWrapper.h b/openigtlink/repo/Source/igtlMessageRTPWrapper.h new file mode 100755 index 0000000..3230404 --- /dev/null +++ b/openigtlink/repo/Source/igtlMessageRTPWrapper.h @@ -0,0 +1,284 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#ifndef __igtlMessageRTPWrapper_h +#define __igtlMessageRTPWrapper_h + +#include + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlMessageFactory.h" +#include "igtlUDPServerSocket.h" +#include "igtlUDPClientSocket.h" +#include "igtlMutexLock.h" +#include "igtl_header.h" +#include "igtl_util.h" +#include "igtlTimeStamp.h" +#include "igtlOSUtil.h" + + +/// This number defines the maximum number for UDP packet buffering, to avoid overflow of the buffer, the first buffered packet will be +#define PacketMaximumBufferNum 1000 +#define ReorderBufferMaximumSize 200 +#define FragmentIndexBytes 2 +#define FragmentBeginIndicator 0X8000 +#define FragmentEndIndicator 0XE000 +#define NoFragmentIndicator 0X0000 + +namespace igtl +{ + /// The MessageRTPWrapper class is the class to fragment/assemble messages from all type classes + /// into UDP packets, as The message classes can be used + /// for wrapping V3 OpenIGTLink message byte streams into UDPPackets. + /// The class can also unwrapping the RTPPackets into OpenIGTLink messages. + /// + /// The typical wrapping or unwrapping procedures is demonstrated in the VideoStreamIGTLinkServer, VieoStreamIGTLinkReceiver and igtlMessageRTPWrapperTest + /// + /// Here, an V3 image message is used as an example. + /// Assume the length of image is 25000 with 57 byte of meta information, which is longer than the RTP Packet payload size 8900, + /// so the message is fragmented into several RTPPackets. + /// 0 58 70 142 25142 25160 25199 + /// + /// |____________|___________________|_______________|_____________________________|___________________|_____________| + /// m_Header m_ExtendedHeader m_ImageHeader m_Image m_MetaDataHeader m_MetaData + /// m_Body m_Content (old m_Body) + /// + /// All the fragments will be attached with a 12 bytes RTP Header, the RTP Header has the format: + /// 0-----------4------------8------------------------16-------------------------31 bit number + /// |Version|P|X| CC |M| Payload Type | Sequence Number | + /// ----------------------------------------------------------------------------- + /// | Time Stamp | + /// ----------------------------------------------------------------------------- + /// | Source Synchronization Identifier(SSRC) | + /// ----------------------------------------------------------------------------- + /// + /// Fragment 1, total length 8912: + /// 0 12 70 82 154 8912 + /// |__________|____________|___________________|_______________|________________________________________| + /// RTPHeader m_Header m_ExtendedHeader1 m_ImageHeader m_Image1 (section 1) + /// + /// + /// + /// Fragment 2, total length 8912: + /// 0 12 70 82 154 8912 + /// |__________|____________|___________________|_______________|________________________________________| + /// RTPHeader m_Header m_ExtendedHeader2 m_ImageHeader m_Image2 (section 2) + /// + /// + /// + /// Fragment 3, total length 7695, for the simplicity, M_Meta* here includs the m_MetaDataHeader and m_MetaData: + /// 0 12 70 82 154 7636 7695 + /// |__________|____________|___________________|_______________|_________________________|_________| + /// RTPHeader m_Header m_ExtendedHeader3 m_ImageHeader m_Image3 (section 3) M_Meta* + /// + /// + /// The m_image is fragmented into three parts: + /// 0 8758 17516 25000 + /// |________________________|_______________________|_________________| + /// m_Image1 m_Image2 m_Image3 + /// + /// + /// The last two bytes are used to reorder the packets if they arrive at different time points. + /// 0x8000 indicates the first RTP packet + /// m_ExtendedHeader1 + /// | 0xXXXX 0xXXXX..... 0xXXXX 0xXXXX |0x8000| + /// First 10 Bytes from m_ExtendedHeader + /// + /// The following RTP packet increments the field 0x8000 + /// m_ExtendedHeader2 + /// | 0xXXXX 0xXXXX..... 0xXXXX 0xXXXX |0x8000| + /// First 10 Bytes from m_ExtendedHeader + /// + /// 0xE000 indicates the last RTP packet + /// m_ExtendedHeader3 + /// | 0xXXXX 0xXXXX..... 0xXXXX 0xXXXX |0x8000| + /// First 10 Bytes from m_ExtendedHeader + + + class PacketBuffer { + public: + PacketBuffer(){pPacketLengthInByte.reserve(PacketMaximumBufferNum); totalLength= 0; pBsBuf.reserve(PacketMaximumBufferNum*(RTP_PAYLOAD_LENGTH+RTP_HEADER_LENGTH));}; + ~PacketBuffer(){pPacketLengthInByte.clear();pBsBuf.clear();}; + std::vector pPacketLengthInByte; ///< length of udp packet size in byte from 0 to number of packet - 1 + std::vector pBsBuf; ///< buffer of Packet contained + int totalLength; + }; + + + class ReorderBuffer + { + public: + ReorderBuffer(){firstPacketLen=0;lastPacketLen=0;filledPacketNum=0; totFragNumber = 0;receivedLastFrag=false;receivedFirstFrag=false;}; + ReorderBuffer(ReorderBuffer const &anotherBuffer){firstPacketLen=anotherBuffer.firstPacketLen;lastPacketLen=anotherBuffer.lastPacketLen;filledPacketNum=anotherBuffer.filledPacketNum;receivedLastFrag=anotherBuffer.receivedLastFrag;receivedFirstFrag=anotherBuffer.receivedFirstFrag;}; + ~ReorderBuffer(){}; + unsigned char buffer[RTP_PAYLOAD_LENGTH*(16384-2)]; // we use 14 bits for fragment number, 2^14 = 16384. maximum + unsigned char firstFragBuffer[RTP_PAYLOAD_LENGTH]; + unsigned char lastFragBuffer[RTP_PAYLOAD_LENGTH]; + igtl_uint32 firstPacketLen; + igtl_uint32 lastPacketLen; + igtl_uint32 filledPacketNum; + igtl_uint32 totFragNumber; + bool receivedLastFrag; + bool receivedFirstFrag; + }; + + class UnWrappedMessage + { + public: + UnWrappedMessage(){messageDataLength = 0; messagePackPointer = new unsigned char[RTP_PAYLOAD_LENGTH*(16384-2)];}; + UnWrappedMessage(UnWrappedMessage const &anotherMessage){}; + ~UnWrappedMessage(){ + if(messagePackPointer) + { + delete[] messagePackPointer; + messagePackPointer = NULL; + } + }; + unsigned char* messagePackPointer; // we use 14 bits for fragment number, 2^14 = 16384. maximum + igtl_uint32 messageDataLength; + }; + + class IGTLCommon_EXPORT MessageRTPWrapper: public Object + { + public: + igtlTypeMacro(igtl::MessageRTPWrapper, Object) + igtlNewMacro(igtl::MessageRTPWrapper); + + public: + enum PacketStatus + { + PacketReady, + WaitingForAnotherMSG, + ProcessFragment, + MessageReady, + ToUnpackAnotherMSG, + WaitingForAnotherPacket + }; + + igtl_uint32 messageID; + igtl_uint16 fragmentNumber; + + + /// The message get fragmented and sent in different packets. The packets sending should have some interval in the function + /// WrapMessageAndSend(), otherwize the network demanding would be too high to cause packet loss + /// This variable need to be set according to the network bandwidth and the RTPPayload size + int packetIntervalTime; + + std::vector PacketSendTimeStampList; + + std::vector PacketTotalLengthList; + + std::vector PacketBeforeSendTimeStampList; + + std::vector fragmentNumberList; + + /// Gets the number of fragments for the packed (serialized) data. Returns numberOfDataFrag + int GetNumberODataFragments() { return numberOfDataFrag; /* the data for transmission is too big for UDP transmission, so the data will be transmitted by multiple packets*/ }; + + /// Gets the number of fragments to be sent for the packed (serialized) data. Returns numberOfDataFragToSent + int GetNumberODataFragToSent() { return numberOfDataFragToSent; /* the data for transmission is too big for UDP transmission, so the data will be transmitted by multiple packets*/ }; + + void SetFCFS(bool isFCFS){FCFS = isFCFS;}; + + void SetRTPPayloadType(igtl_uint8 payLoadType){this->RTPPayloadType = payLoadType;}; + + igtl_uint8 GetRTPPayLoadType(){return this->RTPPayloadType;}; + + int WrapMessageAndPushToBuffer(igtl_uint8* messagePackPointer, int msgtotalLen); + + int SendBufferedDataWithInterval(igtl::UDPServerSocket::Pointer &socket, int interval); + + int WrapMessageAndSend(igtl::UDPServerSocket::Pointer &socket, igtl_uint8* messagePackPointer, int msgtotalLen); + + int PushDataIntoPacketBuffer(igtlUint8* UDPPacket, igtlUint16 PacketLen); + + int UnWrapPacketWithTypeAndName(const char *deviceType, const char * deviceName); + + igtl::MessageBase::Pointer UnWrapMessage(igtl_uint8* messageContent, int totMsgLen); + + ///Set the synchronization source identifier, different session has different SSRC + void SetSSRC(igtl_uint32 identifier); + + ///Set the Contributing source identifier. different device has different CSRC + void SetCSRC(igtl_uint32 identifier); + + ///Set the sequencen number at the rtp header + void SetSeqNum(igtl_uint16 num); + + ///Set the current msg header + void SetMSGHeader(igtl_uint8* header); + + ///Get the wrapped outgoing UDP packet + PacketBuffer GetOutGoingPackets(){return outgoingPackets;}; + + ///Get the incomming UDP packet + PacketBuffer GetInCommingPackets(){return incommingPackets;}; + + int GetCurMSGLocation(){return this->curMSGLocation;}; + + int GetPackedMSGLocation(){return this->curPackedMSGLocation;}; + + int GetRTPWrapperStatus(){return status;}; + + void SetRTPPayloadLength(unsigned int payloadLength){this->RTPPayloadLength = payloadLength;}; + + unsigned int GetRTPPayloadLength(){return this->RTPPayloadLength;}; + + std::map unWrappedMessages; + + igtl::SimpleMutexLock* glock; + + + protected: + MessageRTPWrapper(); + ~MessageRTPWrapper(); + + /// Gets a pointer to the scalar data (for fragmented pack support). + igtl_uint8* GetPackPointer(){return packedMsg;}; + + int WrapMessage(igtl_uint8* messageContent, int bodyMsgLen); + + + private: + unsigned int RTPPayloadLength; + igtl_uint8* packedMsg; + igtl_uint8* MSGHeader; + unsigned int curMSGLocation; + unsigned int curPackedMSGLocation; + unsigned int numberOfDataFrag; + unsigned int numberOfDataFragToSent; + igtl_uint8 RTPPayloadType; + igtl_uint16 AvailabeBytesNum; + igtl_uint16 SeqNum; + int status; + igtl_uint32 appSpecificFreq; + igtl_uint32 SSRC; + igtl_uint32 CSRC; + igtl_uint32 fragmentTimeIncrement; + igtl::ReorderBuffer* reorderBuffer; + std::map reorderBufferMap; + PacketBuffer incommingPackets; + PacketBuffer outgoingPackets; + igtl::TimeStamp::Pointer wrapperTimer; + bool FCFS; //first come first serve + void SleepInNanoSecond(int nanoSecond); + }; + + +} // namespace igtl + +#endif // _igtlMessageRTPWrapper_h \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlMultiThreader.cxx b/openigtlink/repo/Source/igtlMultiThreader.cxx new file mode 100644 index 0000000..b1a6c08 --- /dev/null +++ b/openigtlink/repo/Source/igtlMultiThreader.cxx @@ -0,0 +1,815 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkMultiThreader.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#ifdef _WIN32 +#pragma warning ( disable : 4786 ) +#include "igtlWindows.h" +#include +#endif + + +#include "igtlMultiThreader.h" +#include "igtlMutexLock.h" +#include "igtlObjectFactory.h" + +// These are the includes necessary for multithreaded rendering on an SGI +// using the sproc() call +#ifdef OpenIGTLink_USE_SPROC +#include +#include +#include +#include +#endif + +#ifdef OpenIGTLink_USE_PTHREADS +#include +#endif + + +// Need to define "igtlExternCThreadFunctionType" to avoid warning on some +// platforms about passing function pointer to an argument expecting an +// extern "C" function. Placing the typedef of the function pointer type +// inside an extern "C" block solves this problem. +#if defined(OpenIGTLink_USE_PTHREADS) || defined(OpenIGTLink_HP_PTHREADS) +#include +extern "C" { typedef void *(*igtlExternCThreadFunctionType)(void *); } +#else +//typedef igtlThreadFunctionType igtlExternCThreadFunctionType; +#endif + +#ifdef __APPLE__ +#include +#include +#endif + +namespace igtl { + +// Initialize static member that controls global maximum number of threads +static int MultiThreaderGlobalMaximumNumberOfThreads = 0; + +void MultiThreader::SetGlobalMaximumNumberOfThreads(int val) +{ + if (val == MultiThreaderGlobalMaximumNumberOfThreads) + { + return; + } + MultiThreaderGlobalMaximumNumberOfThreads = val; +} + +int MultiThreader::GetGlobalMaximumNumberOfThreads() +{ + return MultiThreaderGlobalMaximumNumberOfThreads; +} + +// 0 => Not initialized. +static int MultiThreaderGlobalDefaultNumberOfThreads = 0; + +void MultiThreader::SetGlobalDefaultNumberOfThreads(int val) +{ + if (val == MultiThreaderGlobalDefaultNumberOfThreads) + { + return; + } + MultiThreaderGlobalDefaultNumberOfThreads = val; +} + +int MultiThreader::GetGlobalDefaultNumberOfThreads() +{ + if (MultiThreaderGlobalDefaultNumberOfThreads == 0) + { + int num = 1; // default is 1 +#ifdef OpenIGTLink_USE_SPROC + // Default the number of threads to be the number of available + // processors if we are using sproc() + num = prctl( PR_MAXPPROCS ); +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + // Default the number of threads to be the number of available + // processors if we are using pthreads() +#ifdef _SC_NPROCESSORS_ONLN + num = sysconf( _SC_NPROCESSORS_ONLN ); +#elif defined(_SC_NPROC_ONLN) + num = sysconf( _SC_NPROC_ONLN ); +#endif +#if defined(__SVR4) && defined(sun) && defined(PTHREAD_MUTEX_NORMAL) + pthread_setconcurrency(num); +#endif +#endif + +#ifdef __APPLE__ + // Use sysctl() to determine the number of CPUs. This is prefered + // over MPProcessors() because it doesn't require CoreServices + // (which is only available in 32bit on Mac OS X 10.4) + int mib[2] = {CTL_HW, HW_NCPU}; + size_t dataLen = sizeof(int); // 'num' is an 'int' + int result = sysctl(mib, 2, &num, &dataLen, NULL, 0); + if (result == -1) + { + num = 1; + } +#endif + +#ifdef _WIN32 + { + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + num = sysInfo.dwNumberOfProcessors; + } +#endif + +#ifndef OpenIGTLink_USE_WIN32_THREADS +#ifndef OpenIGTLink_USE_SPROC +#ifndef OpenIGTLink_USE_PTHREADS + // If we are not multithreading, the number of threads should + // always be 1 + num = 1; +#endif +#endif +#endif + + // Lets limit the number of threads to IGTL_MAX_THREADS + if (num > IGTL_MAX_THREADS) + { + num = IGTL_MAX_THREADS; + } + + MultiThreaderGlobalDefaultNumberOfThreads = num; + } + + + return MultiThreaderGlobalDefaultNumberOfThreads; +} + +// Constructor. Default all the methods to NULL. Since the +// ThreadInfoArray is static, the ThreadIDs can be initialized here +// and will not change. +MultiThreader::MultiThreader() +{ + int i; + + for ( i = 0; i < IGTL_MAX_THREADS; i++ ) + { + this->m_ThreadInfoArray[i].ThreadID = i; + this->m_ThreadInfoArray[i].ActiveFlag = NULL; + this->m_ThreadInfoArray[i].ActiveFlagLock = NULL; + this->m_MultipleMethod[i] = NULL; + this->m_SpawnedThreadActiveFlag[i] = 0; + this->m_SpawnedThreadActiveFlagLock[i] = NULL; + this->m_SpawnedThreadInfoArray[i].ThreadID = i; + } + + this->m_SingleMethod = NULL; + this->m_NumberOfThreads = + MultiThreader::GetGlobalDefaultNumberOfThreads(); + +} + +// Destructor. Nothing allocated so nothing needs to be done here. +MultiThreader::~MultiThreader() +{ +} + +//---------------------------------------------------------------------------- +int MultiThreader::GetNumberOfThreads() +{ + int num = this->m_NumberOfThreads; + if(MultiThreaderGlobalMaximumNumberOfThreads > 0 && + num > MultiThreaderGlobalMaximumNumberOfThreads) + { + num = MultiThreaderGlobalMaximumNumberOfThreads; + } + return num; +} + +// Set the user defined method that will be run on NumberOfThreads threads +// when m_SingleMethodExecute is called. +void MultiThreader::SetSingleMethod( ThreadFunctionType f, + void *data ) +{ + this->m_SingleMethod = f; + this->m_SingleData = data; +} + +// Set one of the user defined methods that will be run on NumberOfThreads +// threads when m_MultipleMethodExecute is called. This method should be +// called with index = 0, 1, .., NumberOfThreads-1 to set up all the +// required user defined methods +void MultiThreader::SetMultipleMethod( int index, + ThreadFunctionType f, void *data ) +{ + // You can only set the method for 0 through NumberOfThreads-1 + if ( index >= this->m_NumberOfThreads ) + { + igtlErrorMacro( << "Can't set method " << index << + " with a thread count of " << this->m_NumberOfThreads ); + } + else + { + this->m_MultipleMethod[index] = f; + this->m_MultipleData[index] = data; + } +} + +// Execute the method set as the SingleMethod on NumberOfThreads threads. +void MultiThreader::SingleMethodExecute() +{ + int thread_loop = 0; + +#ifdef OpenIGTLink_USE_WIN32_THREADS + DWORD threadId; + HANDLE process_id[IGTL_MAX_THREADS]; +#endif + +#ifdef OpenIGTLink_USE_SPROC + siginfo_t info_ptr; + int process_id[IGTL_MAX_THREADS]; +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + pthread_t process_id[IGTL_MAX_THREADS]; +#endif + + if ( !this->m_SingleMethod ) + { + igtlErrorMacro( << "No single method set!" ); + return; + } + + // obey the global maximum number of threads limit + if (MultiThreaderGlobalMaximumNumberOfThreads && + this->m_NumberOfThreads > MultiThreaderGlobalMaximumNumberOfThreads) + { + this->m_NumberOfThreads = MultiThreaderGlobalMaximumNumberOfThreads; + } + + + // We are using sproc (on SGIs), pthreads(on Suns), or a single thread + // (the default) + +#ifdef OpenIGTLink_USE_WIN32_THREADS + // Using CreateThread on a PC + // + // We want to use CreateThread to start this->m_NumberOfThreads - 1 + // additional threads which will be used to call this->SingleMethod(). + // The parent thread will also call this routine. When it is done, + // it will wait for all the children to finish. + // + // First, start up the this->m_NumberOfThreads-1 processes. Keep track + // of their process ids for use later in the waitid call + for (thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + this->m_ThreadInfoArray[thread_loop].UserData = this->m_SingleData; + this->m_ThreadInfoArray[thread_loop].NumberOfThreads = this->m_NumberOfThreads; + process_id[thread_loop] = + CreateThread(NULL, 0, this->m_SingleMethod, + ((void *)(&this->m_ThreadInfoArray[thread_loop])), 0, &threadId); + if (process_id[thread_loop] == NULL) + { + igtlErrorMacro("Error in thread creation !!!"); + } + } + + // Now, the parent thread calls this->SingleMethod() itself + this->m_ThreadInfoArray[0].UserData = this->m_SingleData; + this->m_ThreadInfoArray[0].NumberOfThreads = this->m_NumberOfThreads; + this->m_SingleMethod((void *)(&this->m_ThreadInfoArray[0])); + + // The parent thread has finished this->SingleMethod() - so now it + // waits for each of the other processes to exit + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + WaitForSingleObject(process_id[thread_loop], INFINITE); + } + + // close the threads + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + CloseHandle(process_id[thread_loop]); + } +#endif + +#ifdef OpenIGTLink_USE_SPROC + // Using sproc() on an SGI + // + // We want to use sproc to start this->m_NumberOfThreads - 1 additional + // threads which will be used to call this->SingleMethod(). The + // parent thread will also call this routine. When it is done, + // it will wait for all the children to finish. + // + // First, start up the this->m_NumberOfThreads-1 processes. Keep track + // of their process ids for use later in the waitid call + + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + this->m_ThreadInfoArray[thread_loop].UserData = this->m_SingleData; + this->m_ThreadInfoArray[thread_loop].NumberOfThreads = this->m_NumberOfThreads; + process_id[thread_loop] = + sproc( this->m_SingleMethod, PR_SADDR, + ( (void *)(&this->m_ThreadInfoArray[thread_loop]) ) ); + if ( process_id[thread_loop] == -1) + { + igtlErrorMacro("sproc call failed. Code: " << errno << endl); + } + } + + // Now, the parent thread calls this->m_SingleMethod() itself + this->m_ThreadInfoArray[0].UserData = this->m_SingleData; + this->m_ThreadInfoArray[0].NumberOfThreads = this->m_NumberOfThreads; + this->m_SingleMethod((void *)(&this->m_ThreadInfoArray[0]) ); + + // The parent thread has finished this->m_SingleMethod() - so now it + // waits for each of the other processes to exit + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + waitid( P_PID, (id_t) process_id[thread_loop], &info_ptr, WEXITED ); + } +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + // Using POSIX threads + // + // We want to use pthread_create to start this->m_NumberOfThreads-1 additional + // threads which will be used to call this->m_SingleMethod(). The + // parent thread will also call this routine. When it is done, + // it will wait for all the children to finish. + // + // First, start up the this->m_NumberOfThreads-1 processes. Keep track + // of their process ids for use later in the pthread_join call + + pthread_attr_t attr; + +#ifdef OpenIGTLink_HP_PTHREADS + pthread_attr_create( &attr ); +#else + pthread_attr_init(&attr); +#if !defined(__CYGWIN__) + pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS); +#endif +#endif + + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + this->m_ThreadInfoArray[thread_loop].UserData = this->m_SingleData; + this->m_ThreadInfoArray[thread_loop].NumberOfThreads = this->m_NumberOfThreads; + +#ifdef OpenIGTLink_HP_PTHREADS + pthread_create( &(process_id[thread_loop]), + attr, this->m_SingleMethod, + ( (void *)(&this->m_ThreadInfoArray[thread_loop]) ) ); +#else + int threadError; + threadError = + pthread_create( &(process_id[thread_loop]), &attr, + reinterpret_cast( + this->m_SingleMethod), + ( (void *)(&this->m_ThreadInfoArray[thread_loop]) ) ); + if (threadError != 0) + { + igtlErrorMacro(<< "Unable to create a thread. pthread_create() returned " + << threadError); + } +#endif + } + + // Now, the parent thread calls this->m_SingleMethod() itself + this->m_ThreadInfoArray[0].UserData = this->m_SingleData; + this->m_ThreadInfoArray[0].NumberOfThreads = this->m_NumberOfThreads; + this->m_SingleMethod((void *)(&this->m_ThreadInfoArray[0]) ); + + // The parent thread has finished this->m_SingleMethod() - so now it + // waits for each of the other processes to exit + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + pthread_join( process_id[thread_loop], NULL ); + } +#endif + +#ifndef OpenIGTLink_USE_WIN32_THREADS +#ifndef OpenIGTLink_USE_SPROC +#ifndef OpenIGTLink_USE_PTHREADS + // There is no multi threading, so there is only one thread. + this->m_ThreadInfoArray[0].UserData = this->m_SingleData; + this->m_ThreadInfoArray[0].NumberOfThreads = this->m_NumberOfThreads; + this->m_SingleMethod( (void *)(&this->m_ThreadInfoArray[0]) ); +#endif +#endif +#endif +} + +void MultiThreader::MultipleMethodExecute() +{ + int thread_loop; + +#ifdef OpenIGTLink_USE_WIN32_THREADS + DWORD threadId; + HANDLE process_id[IGTL_MAX_THREADS]; +#endif + +#ifdef OpenIGTLink_USE_SPROC + siginfo_t info_ptr; + int process_id[IGTL_MAX_THREADS]; +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + pthread_t process_id[IGTL_MAX_THREADS]; +#endif + + + // obey the global maximum number of threads limit + if (MultiThreaderGlobalMaximumNumberOfThreads && + this->m_NumberOfThreads > MultiThreaderGlobalMaximumNumberOfThreads) + { + this->m_NumberOfThreads = MultiThreaderGlobalMaximumNumberOfThreads; + } + + for ( thread_loop = 0; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + if ( this->m_MultipleMethod[thread_loop] == (ThreadFunctionType)NULL) + { + igtlErrorMacro( << "No multiple method set for: " << thread_loop ); + return; + } + } + + // We are using sproc (on SGIs), pthreads(on Suns), CreateThread + // on a PC or a single thread (the default) + +#ifdef OpenIGTLink_USE_WIN32_THREADS + // Using CreateThread on a PC + // + // We want to use CreateThread to start this->m_NumberOfThreads - 1 + // additional threads which will be used to call the m_NumberOfThreads-1 + // methods defined in this->m_MultipleMethods[](). The parent thread + // will call this->m_MultipleMethods[m_NumberOfThreads-1](). When it is done, + // it will wait for all the children to finish. + // + // First, start up the this->m_NumberOfThreads-1 processes. Keep track + // of their process ids for use later in the waitid call + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + this->m_ThreadInfoArray[thread_loop].UserData = + this->m_MultipleData[thread_loop]; + this->m_ThreadInfoArray[thread_loop].NumberOfThreads = this->m_NumberOfThreads; + process_id[thread_loop] = + CreateThread(NULL, 0, this->m_MultipleMethod[thread_loop], + ((void *)(&this->m_ThreadInfoArray[thread_loop])), 0, &threadId); + if (process_id[thread_loop] == NULL) + { + igtlErrorMacro("Error in thread creation !!!"); + } + } + + // Now, the parent thread calls the last method itself + this->m_ThreadInfoArray[0].UserData = this->m_MultipleData[0]; + this->m_ThreadInfoArray[0].NumberOfThreads = this->m_NumberOfThreads; + (this->m_MultipleMethod[0])((void *)(&this->m_ThreadInfoArray[0]) ); + + // The parent thread has finished its method - so now it + // waits for each of the other processes (created with sproc) to + // exit + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + WaitForSingleObject(process_id[thread_loop], INFINITE); + } + + // close the threads + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + CloseHandle(process_id[thread_loop]); + } +#endif + +#ifdef OpenIGTLink_USE_SPROC + // Using sproc() on an SGI + // + // We want to use sproc to start this->m_NumberOfThreads - 1 additional + // threads which will be used to call the m_NumberOfThreads-1 methods + // defined in this->m_MultipleMethods[](). The parent thread + // will call this->m_MultipleMethods[m_NumberOfThreads-1](). When it is done, + // it will wait for all the children to finish. + // + // First, start up the this->m_NumberOfThreads-1 processes. Keep track + // of their process ids for use later in the waitid call + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + this->m_ThreadInfoArray[thread_loop].UserData = + this->m_MultipleData[thread_loop]; + this->m_ThreadInfoArray[thread_loop].NumberOfThreads = this->m_NumberOfThreads; + process_id[thread_loop] = + sproc( this->m_MultipleMethod[thread_loop], PR_SADDR, + ( (void *)(&this->m_ThreadInfoArray[thread_loop]) ) ); + } + + // Now, the parent thread calls the last method itself + this->m_ThreadInfoArray[0].UserData = this->m_MultipleData[0]; + this->m_ThreadInfoArray[0].NumberOfThreads = this->m_NumberOfThreads; + (this->m_MultipleMethod[0])((void *)(&this->m_ThreadInfoArray[0]) ); + + // The parent thread has finished its method - so now it + // waits for each of the other processes (created with sproc) to + // exit + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + waitid( P_PID, (id_t) process_id[thread_loop], &info_ptr, WEXITED ); + } +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + // Using POSIX threads + // + // We want to use pthread_create to start this->m_NumberOfThreads - 1 + // additional + // threads which will be used to call the NumberOfThreads-1 methods + // defined in this->m_MultipleMethods[](). The parent thread + // will call this->m_MultipleMethods[NumberOfThreads-1](). When it is done, + // it will wait for all the children to finish. + // + // First, start up the this->m_NumberOfThreads-1 processes. Keep track + // of their process ids for use later in the pthread_join call + + pthread_attr_t attr; + +#ifdef OpenIGTLink_HP_PTHREADS + pthread_attr_create( &attr ); +#else + pthread_attr_init(&attr); +#ifndef __CYGWIN__ + pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS); +#endif +#endif + + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + this->m_ThreadInfoArray[thread_loop].UserData = + this->m_MultipleData[thread_loop]; + this->m_ThreadInfoArray[thread_loop].NumberOfThreads = this->m_NumberOfThreads; +#ifdef OpenIGTLink_HP_PTHREADS + pthread_create( &(process_id[thread_loop]), + attr, this->m_MultipleMethod[thread_loop], + ( (void *)(&this->m_ThreadInfoArray[thread_loop]) ) ); +#else + pthread_create( &(process_id[thread_loop]), + &attr, + reinterpret_cast( + this->m_MultipleMethod[thread_loop]), + ( (void *)(&this->m_ThreadInfoArray[thread_loop]) ) ); +#endif + } + + // Now, the parent thread calls the last method itself + this->m_ThreadInfoArray[0].UserData = this->m_MultipleData[0]; + this->m_ThreadInfoArray[0].NumberOfThreads = this->m_NumberOfThreads; + (this->m_MultipleMethod[0])((void *)(&this->m_ThreadInfoArray[0]) ); + + // The parent thread has finished its method - so now it + // waits for each of the other processes to exit + for ( thread_loop = 1; thread_loop < this->m_NumberOfThreads; thread_loop++ ) + { + pthread_join( process_id[thread_loop], NULL ); + } +#endif + +#ifndef OpenIGTLink_USE_WIN32_THREADS +#ifndef OpenIGTLink_USE_SPROC +#ifndef OpenIGTLink_USE_PTHREADS + // There is no multi threading, so there is only one thread. + this->m_ThreadInfoArray[0].UserData = this->m_MultipleData[0]; + this->m_ThreadInfoArray[0].NumberOfThreads = this->m_NumberOfThreads; + (this->m_MultipleMethod[0])( (void *)(&this->m_ThreadInfoArray[0]) ); +#endif +#endif +#endif +} + +int MultiThreader::SpawnThread( ThreadFunctionType f, void *userdata ) +{ + int id = 0; + +#ifdef OpenIGTLink_USE_WIN32_THREADS + DWORD threadId; +#endif + + for ( id = 0; id < IGTL_MAX_THREADS; id++ ) + { + if ( ! this->m_SpawnedThreadActiveFlagLock[id] ) + { + this->m_SpawnedThreadActiveFlagLock[id] = MutexLock::New(); + } + this->m_SpawnedThreadActiveFlagLock[id]->Lock(); + if (this->m_SpawnedThreadActiveFlag[id] == 0) + { + // We've got a useable thread id, so grab it + this->m_SpawnedThreadActiveFlag[id] = 1; + this->m_SpawnedThreadActiveFlagLock[id]->Unlock(); + break; + } + this->m_SpawnedThreadActiveFlagLock[id]->Unlock(); + } + + if ( id >= IGTL_MAX_THREADS ) + { + igtlErrorMacro( << "You have too many active threads!" ); + return -1; + } + + this->m_SpawnedThreadInfoArray[id].UserData = userdata; + this->m_SpawnedThreadInfoArray[id].NumberOfThreads = 1; + this->m_SpawnedThreadInfoArray[id].ActiveFlag = + &this->m_SpawnedThreadActiveFlag[id]; + this->m_SpawnedThreadInfoArray[id].ActiveFlagLock = + this->m_SpawnedThreadActiveFlagLock[id]; + + // We are using sproc (on SGIs), pthreads(on Suns or HPs), + // CreateThread (on win32), or generating an error + +#ifdef OpenIGTLink_USE_WIN32_THREADS + // Using CreateThread on a PC + // + this->m_SpawnedThreadProcessID[id] = + CreateThread(NULL, 0, f, + ((void *)(&this->m_SpawnedThreadInfoArray[id])), 0, &threadId); + if (this->m_SpawnedThreadProcessID[id] == NULL) + { + igtlErrorMacro("Error in thread creation !!!"); + } +#endif + +#ifdef OpenIGTLink_USE_SPROC + // Using sproc() on an SGI + // + this->m_SpawnedThreadProcessID[id] = + sproc( f, PR_SADDR, ( (void *)(&this->m_SpawnedThreadInfoArray[id]) ) ); + +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + // Using POSIX threads + // + pthread_attr_t attr; + +#ifdef OpenIGTLink_HP_PTHREADS + pthread_attr_create( &attr ); +#else + pthread_attr_init(&attr); +#ifndef __CYGWIN__ + pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS); +#endif +#endif + +#ifdef OpenIGTLink_HP_PTHREADS + pthread_create( &(this->m_SpawnedThreadProcessID[id]), + attr, f, + ( (void *)(&this->m_SpawnedThreadInfoArray[id]) ) ); +#else + + pthread_create( &(this->m_SpawnedThreadProcessID[id]), + &attr, + reinterpret_cast(f), + ( (void *)(&this->m_SpawnedThreadInfoArray[id]) ) ); +#endif + +#endif + +#ifndef OpenIGTLink_USE_WIN32_THREADS +#ifndef OpenIGTLink_USE_SPROC +#ifndef OpenIGTLink_USE_PTHREADS + // There is no multi threading, so there is only one thread. + // This won't work - so give an error message. + igtlErrorMacro( << "Cannot spawn thread in a single threaded environment!" ); + this->m_SpawnedThreadActiveFlagLock[id] = 0; + id = -1; +#endif +#endif +#endif + + return id; +} + +void MultiThreader::TerminateThread( int threadID ) +{ + + if ( !this->m_SpawnedThreadActiveFlag[threadID] ) + { + return; + } + + this->m_SpawnedThreadActiveFlagLock[threadID]->Lock(); + this->m_SpawnedThreadActiveFlag[threadID] = 0; + this->m_SpawnedThreadActiveFlagLock[threadID]->Unlock(); + +#ifdef OpenIGTLink_USE_WIN32_THREADS + WaitForSingleObject(this->m_SpawnedThreadProcessID[threadID], INFINITE); + CloseHandle(this->m_SpawnedThreadProcessID[threadID]); +#endif + +#ifdef OpenIGTLink_USE_SPROC + siginfo_t info_ptr; + + waitid( P_PID, (id_t) this->m_SpawnedThreadProcessID[threadID], + &info_ptr, WEXITED ); +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + pthread_join( this->m_SpawnedThreadProcessID[threadID], NULL ); +#endif + +#ifndef OpenIGTLink_USE_WIN32_THREADS +#ifndef OpenIGTLink_USE_SPROC +#ifndef OpenIGTLink_USE_PTHREADS + // There is no multi threading, so there is only one thread. + // This won't work - so give an error message. + igtlErrorMacro(<< "Cannot terminate thread in single threaded environment!"); +#endif +#endif +#endif + + this->m_SpawnedThreadActiveFlagLock[threadID] = 0; + this->m_SpawnedThreadActiveFlagLock[threadID] = NULL; + +} + +//---------------------------------------------------------------------------- +MultiThreaderIDType MultiThreader::GetCurrentThreadID() +{ +#if defined(OpenIGTLink_USE_PTHREADS) + return pthread_self(); +#elif defined(OpenIGTLink_USE_WIN32_THREADS) + return GetCurrentThreadId(); +#elif defined(OpenIGTLink_USE_SPROC) + return getpid(); +#else + // No threading implementation. Assume all callers are in the same + // thread. + return 0; +#endif +} + +//---------------------------------------------------------------------------- +int MultiThreader::ThreadsEqual(MultiThreaderIDType t1, + MultiThreaderIDType t2) +{ +#if defined(OpenIGTLink_USE_PTHREADS) + return pthread_equal(t1, t2) != 0; +#elif defined(OpenIGTLink_USE_WIN32_THREADS) + return t1 == t2; +#elif defined(OpenIGTLink_USE_SPROC) + return t1 == t2; +#else + // No threading implementation. Assume all callers are in the same + // thread. + return 1; +#endif +} + +// Print method for the multithreader +void MultiThreader::PrintSelf(std::ostream& os) const +{ + this->Superclass::PrintSelf(os); + + const char* indent = " "; + os << indent << "Thread Count: " << this->m_NumberOfThreads << "\n"; + os << indent << "Global Maximum Number Of Threads: " << + MultiThreaderGlobalMaximumNumberOfThreads << std::endl; + os << "Thread system used: " << +#ifdef OpenIGTLink_USE_PTHREADS + "PTHREADS" +#elif defined OpenIGTLink_USE_SPROC + "SPROC" +#elif defined OpenIGTLink_USE_WIN32_THREADS + "WIN32 Threads" +#elif defined OpenIGTLink_HP_PTHREADS + "HP PThreads" +#else + "NO THREADS SUPPORT" +#endif + << std::endl; +} + + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlMultiThreader.h b/openigtlink/repo/Source/igtlMultiThreader.h new file mode 100644 index 0000000..c4d64cd --- /dev/null +++ b/openigtlink/repo/Source/igtlMultiThreader.h @@ -0,0 +1,274 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkMultiThreader.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME igtlMultiThreader - A class for performing multithreaded execution +// .SECTION Description +// igtlMultithreader is a class that provides support for multithreaded +// execution using sproc() on an SGI, or pthread_create on any platform +// supporting POSIX threads. This class can be used to execute a single +// method on multiple threads, or to specify a method per thread. + +#ifndef __igtlMultiThreader_h +#define __igtlMultiThreader_h + +#include "igtlObject.h" +#include "igtlObjectFactory.h" +#include "igtlMacro.h" +#include "igtlMutexLock.h" + + +#ifdef OpenIGTLink_USE_SPROC +#include // Needed for unix implementation of sproc +#include // Needed for unix implementation of sproc +#endif + +#if defined(OpenIGTLink_USE_PTHREAD) || defined(OpenIGTLink_HP_PTHREAD) +#include // Needed for PTHREAD implementation of mutex +#include // Needed for unix implementation of pthreads +#include // Needed for unix implementation of pthreads +#endif + +namespace igtl +{ + +// If OpenIGTLink_USE_SPROC is defined, then sproc() will be used to create +// multiple threads on an SGI. If OpenIGTLink_USE_PTHREAD is defined, then +// pthread_create() will be used to create multiple threads (on +// a sun, for example) + +// Defined in igtlSystemIncludes.h: +// IGTL_MAX_THREADS + +// If OpenIGTLink_USE_PTHREADS is defined, then the multithreaded +// function is of type void *, and returns NULL +// Otherwise the type is void which is correct for WIN32 +// and SPROC +//BTX + +// The maximum number of threads allowed +#ifdef OpenIGTLink_USE_SPROC +#define IGTL_MAX_THREADS 128 +#endif + +#ifdef OpenIGTLink_USE_PTHREADS +#define IGTL_MAX_THREADS 128 +#endif + +#ifdef OpenIGTLink_USE_WIN32_THREADS +#define IGTL_MAX_THREADS 128 +#endif + +// cygwin threads are unreliable +#ifdef __CYGWIN__ +#undef IGTL_MAX_THREADS +#define IGTL_MAX_THREADS 128 +#endif + +// mingw threads cause crashes so limit to 1 +#if defined(__MINGW32__) +#undef IGTL_MAX_THREADS +#define IGTL_MAX_THREADS 1 +#endif + +// On some sgi machines, threads and stl don't mix so limit to 1 +#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 +#undef IGTL_MAX_THREADS +#define IGTL_MAX_THREADS 1 +#endif + +#ifndef IGTL_MAX_THREADS +#define IGTL_MAX_THREADS 1 +#endif + +#ifdef OpenIGTLink_USE_SPROC +typedef int ThreadProcessIDType; +typedef int MultiThreaderIDType; +#endif + +#ifdef OpenIGTLink_USE_PTHREADS +typedef void *(*ThreadFunctionType)(void *); +typedef pthread_t ThreadProcessIDType; +typedef pthread_t MultiThreaderIDType; +#endif + +#ifdef OpenIGTLink_USE_WIN32_THREADS +typedef igtlWindowsLPTHREAD_START_ROUTINE ThreadFunctionType; +typedef igtlWindowsHANDLE ThreadProcessIDType; +typedef igtlWindowsDWORD MultiThreaderIDType; +#endif + +#if !defined(OpenIGTLink_USE_PTHREADS) && !defined(OpenIGTLink_USE_WIN32_THREADS) +typedef void (*ThreadFunctionType)(void *); +typedef int ThreadProcessIDType; +typedef int MultiThreaderIDType; +#endif +//ETX + + +class IGTLCommon_EXPORT MultiThreader : public Object +{ +public: + igtlTypeMacro(MultiThreader, Object); + igtlNewMacro(Self); + + // Description: + // This is the structure that is passed to the thread that is + // created from the SingleMethodExecute, MultipleMethodExecute or + // the SpawnThread method. It is passed in as a void *, and it is + // up to the method to cast correctly and extract the information. + // The ThreadID is a number between 0 and NumberOfThreads-1 that indicates + // the id of this thread. The NumberOfThreads is this->NumberOfThreads for + // threads created from SingleMethodExecute or MultipleMethodExecute, + // and it is 1 for threads created from SpawnThread. + // The UserData is the (void *)arg passed into the SetSingleMethod, + // SetMultipleMethod, or SpawnThread method. + + //BTX +#define ThreadInfoStruct MultiThreader::ThreadInfo + class ThreadInfo + { + public: + int ThreadID; + int NumberOfThreads; + int *ActiveFlag; + MutexLock::Pointer ActiveFlagLock; + void *UserData; + }; + //ETX + + // Description: + // Get/Set the number of threads to create. It will be clamped to the range + // 1 - IGTL_MAX_THREADS, so the caller of this method should check that the + // requested number of threads was accepted. + igtlSetClampMacro( NumberOfThreads, int, 1, IGTL_MAX_THREADS ); + virtual int GetNumberOfThreads(); + + // Description: + // Set/Get the maximum number of threads to use when multithreading. + // This limits and overrides any other settings for multithreading. + // A value of zero indicates no limit. + static void SetGlobalMaximumNumberOfThreads(int val); + static int GetGlobalMaximumNumberOfThreads(); + + // Description: + // Set/Get the value which is used to initialize the NumberOfThreads + // in the constructor. Initially this default is set to the number of + // processors or IGTL_MAX_THREADS (which ever is less). + static void SetGlobalDefaultNumberOfThreads(int val); + static int GetGlobalDefaultNumberOfThreads(); + + // These methods are excluded from Tcl wrapping 1) because the + // wrapper gives up on them and 2) because they really shouldn't be + // called from a script anyway. + //BTX + + // Description: + // Execute the SingleMethod (as define by SetSingleMethod) using + // this->NumberOfThreads threads. + void SingleMethodExecute(); + + // Description: + // Execute the MultipleMethods (as define by calling SetMultipleMethod + // for each of the required this->NumberOfThreads methods) using + // this->NumberOfThreads threads. + void MultipleMethodExecute(); + + // Description: + // Set the SingleMethod to f() and the UserData field of the + // ThreadInfo that is passed to it will be data. + // This method (and all the methods passed to SetMultipleMethod) + // must be of type ThreadFunctionType and must take a single argument of + // type void *. + void SetSingleMethod(ThreadFunctionType, void *data ); + + // Description: + // Set the MultipleMethod at the given index to f() and the UserData + // field of the ThreadInfo that is passed to it will be data. + void SetMultipleMethod( int index, ThreadFunctionType, void *data ); + + // Description: + // Create a new thread for the given function. Return a thread id + // which is a number between 0 and IGTL_MAX_THREADS - 1. This id should + // be used to kill the thread at a later time. + int SpawnThread( ThreadFunctionType, void *data ); + + // Description: + // Terminate the thread that was created with a SpawnThreadExecute() + void TerminateThread( int thread_id ); + + // Description: + // Get the thread identifier of the calling thread. + static MultiThreaderIDType GetCurrentThreadID(); + + // Description: + // Check whether two thread identifiers refer to the same thread. + static int ThreadsEqual(MultiThreaderIDType t1, + MultiThreaderIDType t2); + +protected: + MultiThreader(); + ~MultiThreader(); + + void PrintSelf(std::ostream& os) const override; + + // The number of threads to use + int m_NumberOfThreads; + + // An array of thread info containing a thread id + // (0, 1, 2, .. IGTL_MAX_THREADS-1), the thread count, and a pointer + // to void so that user data can be passed to each thread + ThreadInfo m_ThreadInfoArray[IGTL_MAX_THREADS]; + + // The methods + ThreadFunctionType m_SingleMethod; + ThreadFunctionType m_MultipleMethod[IGTL_MAX_THREADS]; + + // Storage of MutexFunctions and ints used to control spawned + // threads and the spawned thread ids + int m_SpawnedThreadActiveFlag[IGTL_MAX_THREADS]; + MutexLock::Pointer m_SpawnedThreadActiveFlagLock[IGTL_MAX_THREADS]; + ThreadProcessIDType m_SpawnedThreadProcessID[IGTL_MAX_THREADS]; + ThreadInfo m_SpawnedThreadInfoArray[IGTL_MAX_THREADS]; + +//ETX + + // Internal storage of the data + void *m_SingleData; + void *m_MultipleData[IGTL_MAX_THREADS]; + +private: + MultiThreader(const MultiThreader&); // Not implemented. + void operator=(const MultiThreader&); // Not implemented. +}; + +} // namespace igtl +#endif + + + + + diff --git a/openigtlink/repo/Source/igtlMutexLock.cxx b/openigtlink/repo/Source/igtlMutexLock.cxx new file mode 100644 index 0000000..8cf7aa7 --- /dev/null +++ b/openigtlink/repo/Source/igtlMutexLock.cxx @@ -0,0 +1,115 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkMutexLock.cxx,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "igtlMutexLock.h" + +namespace igtl +{ + + +// New for the SimpleMutex +SimpleMutexLock *SimpleMutexLock::New() +{ + return new SimpleMutexLock; +} + +// Construct a new MutexLock +SimpleMutexLock::SimpleMutexLock() +{ +#ifdef OpenIGTLink_USE_SPROC + init_lock( &m_MutexLock ); +#endif + +#ifdef OpenIGTLink_USE_WIN32_THREADS + m_MutexLock = CreateMutex( NULL, FALSE, NULL ); +#endif + +#ifdef OpenIGTLink_USE_PTHREADS +#ifdef OpenIGTLink_HP_PTHREADS + pthread_mutex_init(&m_MutexLock, pthread_mutexattr_default); +#else + pthread_mutex_init(&m_MutexLock, NULL); +#endif +#endif + +} + +// Destruct the MutexVariable +SimpleMutexLock::~SimpleMutexLock() +{ +#ifdef OpenIGTLink_USE_WIN32_THREADS + CloseHandle(m_MutexLock); +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + pthread_mutex_destroy( &m_MutexLock); +#endif +} + +// Lock the MutexLock +void SimpleMutexLock::Lock() +{ +#ifdef OpenIGTLink_USE_SPROC + spin_lock( &m_MutexLock ); +#endif + +#ifdef OpenIGTLink_USE_WIN32_THREADS + WaitForSingleObject( m_MutexLock, INFINITE ); +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + pthread_mutex_lock( &m_MutexLock); +#endif +} + +// Unlock the MutexLock +void SimpleMutexLock::Unlock() +{ +#ifdef OpenIGTLink_USE_SPROC + release_lock( &m_MutexLock ); +#endif + +#ifdef OpenIGTLink_USE_WIN32_THREADS + ReleaseMutex( m_MutexLock ); +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + pthread_mutex_unlock( &m_MutexLock); +#endif +} + +void MutexLock::PrintSelf(std::ostream& os) const +{ + Superclass::PrintSelf(os); +} + +}//end namespace igtl diff --git a/openigtlink/repo/Source/igtlMutexLock.h b/openigtlink/repo/Source/igtlMutexLock.h new file mode 100644 index 0000000..0e61749 --- /dev/null +++ b/openigtlink/repo/Source/igtlMutexLock.h @@ -0,0 +1,169 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkMutexLock.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlMutexLock_h +#define __igtlMutexLock_h + +#include "igtlObject.h" +#include "igtlObjectFactory.h" + +#ifdef OpenIGTLink_USE_SPROC +#include +#endif + +#ifdef OpenIGTLink_USE_PTHREADS +#include +#endif + +#ifdef OpenIGTLink_USE_WIN32_THREADS +#include "igtlWindows.h" +#endif + +namespace igtl +{ + +#ifdef OpenIGTLink_USE_SPROC +typedef abilock_t MutexType; +#endif + +#ifdef OpenIGTLink_USE_PTHREADS +typedef pthread_mutex_t MutexType; +#endif + +#ifdef OpenIGTLink_USE_WIN32_THREADS +typedef HANDLE MutexType; +#endif + +#ifndef OpenIGTLink_USE_SPROC +#ifndef OpenIGTLink_USE_PTHREADS +#ifndef OpenIGTLink_USE_WIN32_THREADS +typedef int MutexType; +#endif +#endif +#endif + +/** \class SimpleMutexLock + * \brief Simple mutual exclusion locking class. + + * SimpleMutexLock allows the locking of variables which are accessed + * through different threads. This header file also defines + * SimpleMutexLock which is not a subclass of Object. + * + * \ingroup OSSystemObjects + */ +class IGTLCommon_EXPORT SimpleMutexLock +{ +public: + /** Standard class typedefs. */ + typedef SimpleMutexLock Self; + + /** Constructor and destructor left public purposely. */ + SimpleMutexLock(); + virtual ~SimpleMutexLock(); + + /** Methods for creation and destruction through the object factory. */ + static SimpleMutexLock *New(); + //void Delete() {delete this;} + + /** Used for debugging and other run-time purposes. */ + virtual const char *GetNameOfClass() {return "igtlSimpleMutexLock";}; + + /** Lock the MutexLock. */ + void Lock( void ); + + /** Unlock the MutexLock. */ + void Unlock( void ); + + /** Access the MutexType member variable from outside this class */ + MutexType& GetMutexLock() + { + return m_MutexLock; + } + const MutexType GetMutexLock() const + { + return m_MutexLock; + } + +protected: + MutexType m_MutexLock; +}; + +/** \class MutexLock + * \brief Mutual exclusion locking class. + * + * MutexLock allows the locking of variables which are accessed + * through different threads. This header file also defines + * SimpleMutexLock which is not a subclass of igtlObject. + * + * \ingroup OSSystemObjects + */ +class IGTLCommon_EXPORT MutexLock : public Object +{ +public: + /** Run-time information. */ + igtlTypeMacro(MutexLock,Object); + + /** Method for creation. */ + igtlNewMacro(Self); + + /** Lock the igtlMutexLock. */ + void Lock( void ); + + /** Unlock the MutexLock. */ + void Unlock( void ); + +protected: + MutexLock() {} + ~MutexLock() {} + + SimpleMutexLock m_SimpleMutexLock; + void PrintSelf(std::ostream& os) const override; + +private: + MutexLock(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented +}; + + +inline void MutexLock::Lock( void ) +{ + m_SimpleMutexLock.Lock(); +} + +inline void MutexLock::Unlock( void ) +{ + m_SimpleMutexLock.Unlock(); +} + + +}//end igtl namespace +#endif diff --git a/openigtlink/repo/Source/igtlNDArrayMessage.cxx b/openigtlink/repo/Source/igtlNDArrayMessage.cxx new file mode 100644 index 0000000..b261e9c --- /dev/null +++ b/openigtlink/repo/Source/igtlNDArrayMessage.cxx @@ -0,0 +1,292 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlNDArrayMessage.h" + +#include "igtlTypes.h" + +#include "igtl_header.h" +#include "igtl_ndarray.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include + +namespace igtl { + + +ArrayBase::ArrayBase() +{ + this->m_ByteArray = NULL; + this->m_Size.clear(); +} + + +ArrayBase::~ArrayBase() +{ + + if (this->m_ByteArray) + { + delete (igtlUint8 *) this->m_ByteArray; + } +} + +int ArrayBase::SetSize(IndexType size) +{ + + if (this->m_Size == size) + { + // If the size of the array is same as specified, + // do nothing + return 1; + } + + if (this->m_ByteArray != NULL) + { + delete (igtlUint8 *) this->m_ByteArray; + } + this->m_Size = size; + + this->m_ByteArray = (void *) new igtlUint8[GetRawArraySize()]; + + if (this->m_ByteArray) + { + return 1; + } + else + { + this->m_Size.clear(); + return 0; + } +} + + +int ArrayBase::SetArray(void * array) +{ + if (this->m_ByteArray) + { + memcpy(this->m_ByteArray, array, GetRawArraySize()); + return 1; + } + else + { + return 0; + } +}; + + +igtlUint64 ArrayBase::GetRawArraySize() +{ + return (igtlUint64) GetNumberOfElements() * (igtlUint64) GetElementSize(); +} + + +igtlUint32 ArrayBase::GetNumberOfElements() +{ + igtlUint32 len = 1; + IndexType::iterator iter; + for (iter = this->m_Size.begin(); iter != this->m_Size.end(); iter ++) + { + len *= *iter; + } + return len; +} + + +igtlUint32 ArrayBase::Get1DIndex(IndexType index) +{ + igtlUint32 p; + igtlUint32 step; + igtlUint16 dim = this->m_Size.size(); + + if (this->m_Size.size() != index.size()) + { + // TODO: how to pass the error to the caller? + return 0; + } + + p = 0; + step = 1; + IndexType::iterator iter; + for (int i = dim-1; i >= 0; i --) + { + p += index[i] * step; + step *= this->m_Size[i]; + } + igtlUint32 m = GetNumberOfElements(); + if (p <= m) + { + return p; + } + else + { + // TODO: how to pass the error to the caller? + return m; + } +} + + +NDArrayMessage::NDArrayMessage(): + MessageBase() +{ + this->m_SendMessageType = "NDARRAY"; + this->m_Array = NULL; + this->m_Type = 0; +} + + +NDArrayMessage::~NDArrayMessage() +{ +} + + +int NDArrayMessage::SetArray(int type, ArrayBase * a) +{ + m_IsBodyPacked = false; + // Check if type is valid + if (type < 2 || type > 13 || + type == 8 || type == 9 || type == 12) + { + return 0; + } + this->m_Type = type; + + if (a) + { + this->m_Array = a; + return 1; + } + else + { + return 0; + } +} + + +igtlUint64 NDArrayMessage::CalculateContentBufferSize() +{ + igtlUint64 dataSize; + int dim; + if (this->m_Array == NULL) + { + return 0; + } + dim = this->m_Array->GetDimension(); + dataSize = sizeof(igtlUint8) * 2 + sizeof(igtlUint16) * (igtl_uint64) dim + + this->m_Array->GetRawArraySize(); + + return dataSize; +} + + +int NDArrayMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + if (this->m_Array == NULL) + { + return 0; + } + + igtl_ndarray_info info; + + igtl_ndarray_init_info(&info); + info.dim = this->m_Array->GetDimension(); + info.type = this->m_Type; + + ArrayBase::IndexType size = this->m_Array->GetSize(); + + igtl_uint16 * s = new igtl_uint16[info.dim]; + for (int i = 0; i < info.dim; i ++) + { + s[i] = size[i]; + } + int r = igtl_ndarray_alloc_info(&info, s); + delete [] s; + + if (r == 0) + { + return 0; + } + +// size.data() doesn't work for some environtments (MacOS X 10.5 and Win32, as far as I know) +// if (igtl_ndarray_alloc_info(&info, size.data()) == 0) +// { +// return 0; +// } + + memcpy(info.array, this->m_Array->GetRawArray(), this->m_Array->GetRawArraySize()); + igtl_ndarray_pack(&info, this->m_Content, IGTL_TYPE_PREFIX_NONE); + + return 1; +} + + +int NDArrayMessage::UnpackContent() +{ + igtl_ndarray_info info; + bool isUnpacked(true); + igtl_ndarray_unpack(IGTL_TYPE_PREFIX_NONE, this->m_Content, &info, this->CalculateReceiveContentSize(isUnpacked)); + + this->m_Type = info.type; + ArrayBase::IndexType size; + size.resize(info.dim); + for (int i = 0; i < info.dim; i ++) + { + size[i] = info.size[i]; + } + + switch (this->m_Type) + { + case TYPE_INT8: + this->m_Array = new Array; + break; + case TYPE_UINT8: + this->m_Array = new Array; + break; + case TYPE_INT16: + this->m_Array = new Array; + break; + case TYPE_UINT16: + this->m_Array = new Array; + break; + case TYPE_INT32: + this->m_Array = new Array; + break; + case TYPE_UINT32: + this->m_Array = new Array; + break; + case TYPE_FLOAT32: + this->m_Array = new Array; + break; + case TYPE_FLOAT64: + this->m_Array = new Array; + break; + case TYPE_COMPLEX: + this->m_Array = new Array; + break; + default: + return 0; + break; + } + + this->m_Array->SetSize(size); + memcpy(this->m_Array->GetRawArray(), info.array, this->m_Array->GetRawArraySize()); + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlNDArrayMessage.h b/openigtlink/repo/Source/igtlNDArrayMessage.h new file mode 100644 index 0000000..fb8ee75 --- /dev/null +++ b/openigtlink/repo/Source/igtlNDArrayMessage.h @@ -0,0 +1,177 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlNDArrayMessage_h +#define __igtlNDArrayMessage_h + +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +#define IGTL_STRING_MESSAGE_DEFAULT_ENCODING 3 /* Default encoding -- ANSI-X3.5-1968 */ + +namespace igtl +{ + +class IGTLCommon_EXPORT ArrayBase +{ +public: + + /// Vector type for an index of N-D array + typedef std::vector IndexType; + +protected: + ArrayBase(); + ~ArrayBase(); + +public: + + /// Sets the size of the N-D array. Returns non-zero value, if success. + int SetSize(IndexType size); + + /// Gets the size of the N-D array. + IndexType GetSize() { return this->m_Size; }; + + /// Gets the dimension of the N-D array. + int GetDimension() { return this->m_Size.size(); }; + + /// Sets an array from a byte array. Size and dimension must be specified prior to + /// calling the SetArray() function. + int SetArray(void * array); + + /// Gets the size of the raw byte array stored in the class. + igtlUint64 GetRawArraySize(); + + /// Gets the raw byte array stored in the class. + void * GetRawArray() { return this->m_ByteArray; }; + +protected: + + /// Gets the size of a element of the array. + virtual int GetElementSize() = 0; + + /// Gets the number of elements in the array. + igtlUint32 GetNumberOfElements(); + + /// Returns the 1-D index of the element specified by 'index'. + /// This function is used to calculate the index of the element in + /// the raw array. + igtlUint32 Get1DIndex(IndexType index); + +private: + + /// A vector representing the size of the N-D array. + IndexType m_Size; + + /// A pointer to the byte array data. + void * m_ByteArray; + +}; + + +template +class IGTLCommon_EXPORT Array : public ArrayBase +{ +public: + /// Sets a value of the element specified by 'index' + int SetValue(IndexType index, T value) + { + if (Get1DIndex(index) <= GetNumberOfElements()) { + T* TypeArray = reinterpret_cast(GetRawArray()); + TypeArray[Get1DIndex(index)] = value; + return 1; + } else { + return 0; + } + } + + /// Gets a value of the element specified by 'index' + int GetValue(IndexType index, T & value) + { + if (Get1DIndex(index) <= GetNumberOfElements()) { + T* TypeArray = reinterpret_cast(GetRawArray()); + value = TypeArray[Get1DIndex(index)]; + return 1; + } else { + return 0; + } + } + +protected: + + /// Gets the size of elements (e.g. 1 byte in case of 8-bit integer) + virtual int GetElementSize() { return sizeof(T); }; +}; + + +class IGTLCommon_EXPORT NDArrayMessage: public MessageBase +{ +public: + + /// Types of elements + enum { + TYPE_INT8 = 2, + TYPE_UINT8 = 3, + TYPE_INT16 = 4, + TYPE_UINT16 = 5, + TYPE_INT32 = 6, + TYPE_UINT32 = 7, + TYPE_FLOAT32 = 10, + TYPE_FLOAT64 = 11, + TYPE_COMPLEX = 13, + }; + +public: + igtlTypeMacro(igtl::NDArrayMessage, igtl::MessageBase); + igtlNewMacro(igtl::NDArrayMessage); + +public: + + /// Sets an array with an element type. + int SetArray(int type, ArrayBase * a); + + /// Gets a pointer to the array. + ArrayBase * GetArray() { return this->m_Array; }; + + /// Gets the type of elements of the array. (e.g. TYPE_INT8) + int GetType() { return this->m_Type; } ; + +protected: + NDArrayMessage(); + ~NDArrayMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// A pointer to the N-D array. + ArrayBase * m_Array; + + /// A variable for the type of the N-D array. + int m_Type; + +}; + + +} // namespace igtl + +#endif // _igtlNDArrayMessage_h + + + diff --git a/openigtlink/repo/Source/igtlOSUtil.cxx b/openigtlink/repo/Source/igtlOSUtil.cxx new file mode 100644 index 0000000..de4fd71 --- /dev/null +++ b/openigtlink/repo/Source/igtlOSUtil.cxx @@ -0,0 +1,70 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlOSUtil.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) + #include +#else + #include + #include +#endif + +#include + +namespace igtl +{ + +void Sleep(int milliseconds) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + + // Call Windows Native Sleep() function + ::Sleep(milliseconds); + +#else + + struct timespec req; + req.tv_sec = (int) milliseconds / 1000; + req.tv_nsec = (milliseconds % 1000) * 1000000; + + while ((nanosleep(&req, &req) == -1) && (errno == EINTR)) + { + continue; + } + +#endif +} + + + +// strnlen(), if not defined +#ifndef OpenIGTLink_HAVE_STRNLEN +size_t Strnlen(const char* s, size_t maxlen) +{ + + size_t i; + + for(i = 0; i < maxlen; i++) + { + if(s[i] == '\0') return i; + } + + return maxlen; + +} +#endif + + +} diff --git a/openigtlink/repo/Source/igtlOSUtil.h b/openigtlink/repo/Source/igtlOSUtil.h new file mode 100644 index 0000000..4b8f7d1 --- /dev/null +++ b/openigtlink/repo/Source/igtlOSUtil.h @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igltOSUtil_h +#define __igltOSUtil_h + +#include + +#include "igtlWin32Header.h" +namespace igtl +{ + + /** Stop the program for the duration specified in millisecond + * The maximum dulation is + * */ + void IGTLCommon_EXPORT Sleep(int millisecond); + + /** Just in case strnlen() is not defined (e.g. Mac OS X Snow Leopard) */ +#ifndef OpenIGTLink_HAVE_STRNLEN + size_t IGTLCommon_EXPORT Strnlen(const char* s, size_t maxlen); +#else + inline size_t IGTLCommon_EXPORT Strnlen(const char* s, size_t maxlen) + { return strnlen(s, maxlen); } +#endif + +} + +#endif // __igltOSUtil_h + + diff --git a/openigtlink/repo/Source/igtlObject.cxx b/openigtlink/repo/Source/igtlObject.cxx new file mode 100644 index 0000000..7da04a4 --- /dev/null +++ b/openigtlink/repo/Source/igtlObject.cxx @@ -0,0 +1,588 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkObject.cxx,v $ + Language: C++ + Date: $Date: 2009-11-12 23:48:21 -0500 (Thu, 12 Nov 2009) $ + Version: $Revision: 5332 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "igtlObject.h" +#include "igtlObjectFactory.h" +#include "igtlMacro.h" + +namespace igtl +{ +/** + * Initialize static member that controls warning display. + */ +bool Object::m_GlobalWarningDisplay = true; + +//class Observer +//{ +//public: +// Observer(Command* c, +// const EventObject * event, +// unsigned long tag) :m_Command(c), +// m_Event(event), +// m_Tag(tag) +// { } +// virtual ~Observer() +// { delete m_Event; } +// Command::Pointer m_Command; +// const EventObject * m_Event; +// unsigned long m_Tag; +//}; + + +//class SubjectImplementation +//{ +//public: +// SubjectImplementation() {m_Count = 0;} +// ~SubjectImplementation(); +//// unsigned long AddObserver(const EventObject & event, Command* cmd); +//// unsigned long AddObserver(const EventObject & event, Command* cmd) const; +//// void RemoveObserver(unsigned long tag); +//// void RemoveAllObservers(); +//// void InvokeEvent( const EventObject & event, Object* self); +//// void InvokeEvent( const EventObject & event, const Object* self); +//// Command *GetCommand(unsigned long tag); +// // bool HasObserver(const EventObject & event) const; +// // bool PrintObservers(std::ostream& os) const; +//private: +// //std::list m_Observers; +// unsigned long m_Count; +//}; + +//SubjectImplementation:: +//~SubjectImplementation() +//{ +//// for(std::list::iterator i = m_Observers.begin(); +//// i != m_Observers.end(); ++i) +//// { +//// delete (*i); +//// } +//} + + +//unsigned long +//SubjectImplementation:: +//AddObserver(const EventObject & event, +// Command* cmd) +//{ +// Observer* ptr = new Observer(cmd, event.MakeObject(), m_Count); +// m_Observers.push_back(ptr); +// m_Count++; +// return ptr->m_Tag; +//} + + +//unsigned long +//SubjectImplementation:: +//AddObserver(const EventObject & event, +// Command* cmd) const +//{ +// Observer* ptr = new Observer(cmd, event.MakeObject(), m_Count); +// SubjectImplementation * me = const_cast( this ); +// me->m_Observers.push_back(ptr); +// me->m_Count++; +// return ptr->m_Tag; +//} + + +//void +//SubjectImplementation:: +//RemoveObserver(unsigned long tag) +//{ +// for(std::list::iterator i = m_Observers.begin(); +// i != m_Observers.end(); ++i) +// { +// if((*i)->m_Tag == tag) +// { +// delete (*i); +// m_Observers.erase(i); +// return; +// } +// } +//} + + +//void +//SubjectImplementation:: +//RemoveAllObservers() +//{ +// for(std::list::iterator i = m_Observers.begin(); +// i != m_Observers.end(); ++i) +// { +// delete (*i); +// } +// m_Observers.clear(); +//} +// +// +//void +//SubjectImplementation:: +//InvokeEvent( const EventObject & event, +// Object* self) +//{ +// for(std::list::iterator i = m_Observers.begin(); +// i != m_Observers.end(); ++i) +// { +// const EventObject * e = (*i)->m_Event; +// if(e->CheckEvent(&event)) +// { +// (*i)->m_Command->Execute(self, event); +// } +// } +//} +// +//void +//SubjectImplementation:: +//InvokeEvent( const EventObject & event, +// const Object* self) +//{ +// for(std::list::iterator i = m_Observers.begin(); +// i != m_Observers.end(); ++i) +// { +// const EventObject * e = (*i)->m_Event; +// if(e->CheckEvent(&event)) +// { +// (*i)->m_Command->Execute(self, event); +// } +// } +//} + + +//Command* +//SubjectImplementation:: +//GetCommand(unsigned long tag) +//{ +// for(std::list::iterator i = m_Observers.begin(); +// i != m_Observers.end(); ++i) +// { +// if ( (*i)->m_Tag == tag) +// { +// return (*i)->m_Command; +// } +// } +// return 0; +//} + +//bool +//SubjectImplementation:: +//HasObserver(const EventObject & event) const +//{ +// for(std::list::const_iterator i = m_Observers.begin(); +// i != m_Observers.end(); ++i) +// { +// const EventObject * e = (*i)->m_Event; +// if(e->CheckEvent(&event)) +// { +// return true; +// } +// } +// return false; +//} + +//bool +//SubjectImplementation:: +//PrintObservers(std::ostream& os) const +//{ +// if(m_Observers.empty()) +// { +// return false; +// } +// +// for(std::list::const_iterator i = m_Observers.begin(); +// i != m_Observers.end(); ++i) +// { +// const EventObject * e = (*i)->m_Event; +// const Command* c = (*i)->m_Command; +// os << " " << e->GetEventName() << "(" << c->GetNameOfClass() << ")\n"; +// } +// return true; +//} + +Object::Pointer +Object::New() +{ + Pointer smartPtr; + Object *rawPtr = ::igtl::ObjectFactory::Create(); + if(rawPtr == NULL) + { + rawPtr = new Object; + } + smartPtr = rawPtr; + rawPtr->UnRegister(); + return smartPtr; +} + +LightObject::Pointer +Object::CreateAnother() const +{ + return Object::New().GetPointer(); +} + + +/** + * Turn debugging output on. + */ +void +Object +::DebugOn() const +{ + m_Debug = true; +} + + +/** + * Turn debugging output off. + */ +void +Object +::DebugOff() const +{ + m_Debug = false; +} + + +/** + * Get the value of the debug flag. + */ +bool +Object +::GetDebug() const +{ + return m_Debug; +} + + +/** + * Set the value of the debug flag. A non-zero value turns debugging on. + */ +void +Object +::SetDebug(bool debugFlag) const +{ + m_Debug = debugFlag; +} + + +///** +// * Return the modification for this object. +// */ +//unsigned long +//Object +//::GetMTime() const +//{ +// return m_MTime.GetMTime(); +//} + + +///** +// * Make sure this object's modified time is greater than all others. +// */ +//void +//Object +//::Modified() const +//{ +// m_MTime.Modified(); +// //InvokeEvent( ModifiedEvent() ); +//} + + +/** + * Increase the reference count (mark as used by another object). + */ +void +Object +::Register() const +{ + igtlDebugMacro(<< "Registered, " + << "ReferenceCount = " << (m_ReferenceCount+1)); + + // call the parent + Superclass::Register(); +} + + +/** + * Decrease the reference count (release by another object). + */ +void +Object +::UnRegister() const +{ + // call the parent + igtlDebugMacro(<< "UnRegistered, " + << "ReferenceCount = " << (m_ReferenceCount-1)); + + if ( (m_ReferenceCount-1) <= 0) + { + /** + * If there is a delete method, invoke it. + */ + //this->InvokeEvent(DeleteEvent()); + } + + Superclass::UnRegister(); +} + + +/** + * Sets the reference count (use with care) + */ +void +Object +::SetReferenceCount(int ref) +{ + igtlDebugMacro(<< "Reference Count set to " << ref); + + // ReferenceCount in now unlocked. We may have a race condition to + // to delete the object. + if( ref <= 0 ) + { + /** + * If there is a delete method, invoke it. + */ + //this->InvokeEvent(DeleteEvent()); + } + + Superclass::SetReferenceCount(ref); +} + + +/** + * Set the value of the global debug output control flag. + */ +void +Object +::SetGlobalWarningDisplay(bool val) +{ + m_GlobalWarningDisplay = val; +} + + +/** + * Get the value of the global debug output control flag. + */ +bool +Object +::GetGlobalWarningDisplay() +{ + return m_GlobalWarningDisplay; +} + + +//unsigned long +//Object +//::AddObserver(const EventObject & event, Command *cmd) +//{ +// if (!this->m_SubjectImplementation) +// { +// this->m_SubjectImplementation = new SubjectImplementation; +// } +// return this->m_SubjectImplementation->AddObserver(event,cmd); +//} + + +//unsigned long +//Object +//::AddObserver(const EventObject & event, Command *cmd) const +//{ +// if (!this->m_SubjectImplementation) +// { +// Self * me = const_cast( this ); +// me->m_SubjectImplementation = new SubjectImplementation; +// } +// return this->m_SubjectImplementation->AddObserver(event,cmd); +//} + + +//Command* +//Object +//::GetCommand(unsigned long tag) +//{ +// if (this->m_SubjectImplementation) +// { +// return this->m_SubjectImplementation->GetCommand(tag); +// } +// return NULL; +//} + +//void +//Object +//::RemoveObserver(unsigned long tag) +//{ +// if (this->m_SubjectImplementation) +// { +// this->m_SubjectImplementation->RemoveObserver(tag); +// } +//} + +//void +//Object +//::RemoveAllObservers() +//{ +// if (this->m_SubjectImplementation) +// { +// this->m_SubjectImplementation->RemoveAllObservers(); +// } +//} + + +//void +//Object +//::InvokeEvent( const EventObject & event ) +//{ +// if (this->m_SubjectImplementation) +// { +// this->m_SubjectImplementation->InvokeEvent(event,this); +// } +//} + + +//void +//Object +//::InvokeEvent( const EventObject & event ) const +//{ +// if (this->m_SubjectImplementation) +// { +// this->m_SubjectImplementation->InvokeEvent(event,this); +// } +//} +// +// +// +// +//bool +//Object +//::HasObserver( const EventObject & event ) const +//{ +// if (this->m_SubjectImplementation) +// { +// return this->m_SubjectImplementation->HasObserver(event); +// } +// return false; +//} +// +// +// +//bool +//Object +//::PrintObservers(std::ostream& os) const +//{ +// if (this->m_SubjectImplementation) +// { +// return this->m_SubjectImplementation->PrintObservers(os); +// } +// return false; +//} + + + +/** + * Create an object with Debug turned off and modified time initialized + * to the most recently modified object. + */ +Object +::Object(): + LightObject(), + m_Debug(false)/*, + m_SubjectImplementation(NULL), + m_MetaDataDictionary(NULL) + */ +{ + // this->Modified(); +} + + +Object +::~Object() +{ + igtlDebugMacro(<< "Destructing!"); + //delete m_SubjectImplementation; + //delete m_MetaDataDictionary;//Deleting a NULL pointer does nothing. +} + + +/** + * Chaining method to print an object's instance variables, as well as + * its superclasses. + */ +void +Object +::PrintSelf(std::ostream& os) const +{ + Superclass::PrintSelf(os); + + const char* indent = " "; + + // os << indent << "Modified Time: " << this->GetMTime() << std::endl; + os << indent << "Debug: " << (m_Debug ? "On\n" : "Off\n"); + os << indent << "Observers: \n"; + /* + if(!this->PrintObservers(os)) + { + os << " " << "none\n"; + } + */ +} + +//MetaDataDictionary & +//Object +//::GetMetaDataDictionary(void) +//{ +// if(m_MetaDataDictionary==NULL) +// { +// m_MetaDataDictionary=new MetaDataDictionary; +// } +// return *m_MetaDataDictionary; +//} + +//const MetaDataDictionary & +//Object +//::GetMetaDataDictionary(void) const +//{ +// if(m_MetaDataDictionary==NULL) +// { +// m_MetaDataDictionary=new MetaDataDictionary; +// } +// return *m_MetaDataDictionary; +//} + +//void +//Object +//::SetMetaDataDictionary(const MetaDataDictionary & rhs) +//{ +// if(m_MetaDataDictionary==NULL) +// { +// m_MetaDataDictionary=new MetaDataDictionary; +// } +// *m_MetaDataDictionary=rhs; +//} + +} // end namespace igtl diff --git a/openigtlink/repo/Source/igtlObject.h b/openigtlink/repo/Source/igtlObject.h new file mode 100644 index 0000000..8e9529c --- /dev/null +++ b/openigtlink/repo/Source/igtlObject.h @@ -0,0 +1,206 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkObject.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlObject_h +#define __igtlObject_h + +#include "igtlLightObject.h" +//#include "igtlTimeStamp.h" +//#include "igtlEventObject.h" +//#include "igtlMetaDataDictionary.h" + +#include "igtlConfigure.h" + +namespace igtl +{ + //class SubjectImplementation; + //class Command; + +/** \class Object + * \brief Base class for most igtl classes. + * + * Object is the second-highest level base class for most igtl objects. + * It extends the base object functionality of LightObject by + * implementing callbacks (via object/observer), debug flags/methods, + * and modification time tracking. Most IGTL classes should be a subclas + * of Object due to the need to keep track of modified time. + * + * \ingroup IGTLSystemObjects + * \ingroup DataRepresentation + */ +class IGTLCommon_EXPORT Object: public LightObject +{ +public: + + /** Standard part of all igtl objects. */ + igtlTypeMacro(Object, LightObject); + + /** Method for creation through the object factory. */ + static Pointer New(); + + /** Create an object from an instance, potentially deferring to a + * factory. This method allows you to create an instance of an + * object that is exactly the same type as the referring object. + * This is useful in cases where an object has been cast back to a + * base class. */ + LightObject::Pointer CreateAnother() const override; + + /** Turn debugging output on. */ + virtual void DebugOn() const; + + /** Turn debugging output off. */ + virtual void DebugOff() const; + + /** Get the value of the debug flag. */ + bool GetDebug() const; + + /** Set the value of the debug flag. A non-zero value turns debugging on. */ + void SetDebug(bool debugFlag) const; + + /** Return this objects modified time. */ + // virtual unsigned long GetMTime() const; + + /** Update the modification time for this object. Many filters rely on the + * modification time to determine if they need to recompute their data. */ + // virtual void Modified() const; + + /** Increase the reference count (mark as used by another object). */ + void Register() const override; + + /** Decrease the reference count (release by another object). */ + void UnRegister() const override; + + /** Sets the reference count (use with care) */ + void SetReferenceCount(int) override; + + /** This is a global flag that controls whether any debug, warning + * or error messages are displayed. */ + static void SetGlobalWarningDisplay(bool flag); + static bool GetGlobalWarningDisplay(); + static void GlobalWarningDisplayOn() + { Object::SetGlobalWarningDisplay(true); } + static void GlobalWarningDisplayOff() + { Object::SetGlobalWarningDisplay(false); } + + /** Allow people to add/remove/invoke observers (callbacks) to any IGTL + * object. This is an implementation of the subject/observer design + * pattern. An observer is added by specifying an event to respond to + * and an igtl::Command to execute. It returns an unsigned long tag + * which can be used later to remove the event or retrieve the + * command. The memory for the Command becomes the responsibility of + * this object, so don't pass the same instance of a command to two + * different objects */ +// unsigned long AddObserver(const EventObject & event, Command *); +// unsigned long AddObserver(const EventObject & event, Command *) const; + + /** Get the command associated with the given tag. NOTE: This returns + * a pointer to a Command, but it is safe to asign this to a + * Command::Pointer. Since Command inherits from LightObject, at this + * point in the code, only a pointer or a reference to the Command can + * be used. */ + //Command* GetCommand(unsigned long tag); + + /** Call Execute on all the Commands observing this event id. */ + //void InvokeEvent( const EventObject & ); + + /** Call Execute on all the Commands observing this event id. + * The actions triggered by this call doesn't modify this object. */ + //void InvokeEvent( const EventObject & ) const; + + /** Remove the observer with this tag value. */ + //void RemoveObserver(unsigned long tag); + + /** Remove all observers . */ + //void RemoveAllObservers(); + + /** Return true if an observer is registered for this event. */ + //bool HasObserver( const EventObject & event ) const; + + /** + * \return A reference to this objects MetaDataDictionary. + * \warning This reference may be changed. + */ + //MetaDataDictionary & GetMetaDataDictionary(void); + + /** + * \return A constant reference to this objects MetaDataDictionary. + */ + //const MetaDataDictionary & GetMetaDataDictionary(void) const; + + /** + * \return Set the MetaDataDictionary + */ + //void SetMetaDataDictionary(const MetaDataDictionary & rhs); + + +protected: + Object(); + virtual ~Object(); + + /** Methods invoked by Print() to print information about the object + * including superclasses. Typically not called by the user (use Print() + * instead) but used in the hierarchical print process to combine the + * output of several classes. */ + virtual void PrintSelf(std::ostream& os) const override; + + //bool PrintObservers(std::ostream& os) const; + +private: + Object(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** Enable/Disable debug messages. */ + mutable bool m_Debug; + + /** Keep track of modification time. */ + // mutable TimeStamp m_MTime; + + /** Global object debug flag. */ + static bool m_GlobalWarningDisplay; + + /** Implementation class for Subject/Observer Pattern. + * This is only allocated if used. */ + //SubjectImplementation* m_SubjectImplementation; + /** + * Implementation for holding Object MetaData + * @see igtl::MetaDataDictionary + * @see igtl::MetaDataObjectBase + * @see igtl::MetaDataObject + * This is only allocated if used. + */ + //mutable MetaDataDictionary * m_MetaDataDictionary; +}; + +} // end namespace igtl + +#endif + diff --git a/openigtlink/repo/Source/igtlObjectFactory.h b/openigtlink/repo/Source/igtlObjectFactory.h new file mode 100644 index 0000000..d8ef306 --- /dev/null +++ b/openigtlink/repo/Source/igtlObjectFactory.h @@ -0,0 +1,75 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkObjectFactory.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlObjectFactory_h +#define __igtlObjectFactory_h + +#include "igtlObjectFactoryBase.h" + +namespace igtl +{ + +/** \class ObjectFactory + * \brief Create instances of a class. + * + * ObjectFactory is a helper class used to created instances of a + * class. Object factories are used for instantiation because they allow + * run-time replacement of a class with a user-supplied version. For + * example, if you wished to replace an algorithm with your own custom + * version, or with a hardware-accelerated version, ObjectFactory + * can be used to do this. + * + * This implementation of the object factory is templated and uses RTTI + * (Run-Time Type Information) to create the name of the class it is to + * instantiate. (The name may include template type parameters, depending + * on the class definition.) + * + * \ingroup IGTLSystemObjects + */ + +template +class ObjectFactory : public ObjectFactoryBase +{ +public: + static typename T::Pointer Create() + { + LightObject::Pointer ret = ObjectFactory::CreateInstance(typeid(T).name()); + return dynamic_cast(ret.GetPointer()); + } +}; + +} // end namespace igtl + +#endif + + + diff --git a/openigtlink/repo/Source/igtlObjectFactoryBase.cxx b/openigtlink/repo/Source/igtlObjectFactoryBase.cxx new file mode 100644 index 0000000..aaaec3b --- /dev/null +++ b/openigtlink/repo/Source/igtlObjectFactoryBase.cxx @@ -0,0 +1,732 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkObjectFactoryBase.cxx,v $ + Language: C++ + Date: $Date: 2010-06-09 16:16:36 -0400 (Wed, 09 Jun 2010) $ + Version: $Revision: 6525 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#if defined(_MSC_VER) +#pragma warning ( disable : 4786 ) +#endif + +#include "igtlObjectFactoryBase.h" +//#include "igtlDynamicLoader.h" +//#include "igtlDirectory.h" +//#include "igtlVersion.h" +#include +#include +#include +#include + +namespace +{ + +class CleanUpObjectFactory +{ +public: + inline void Use() + { + } + ~CleanUpObjectFactory() + { + igtl::ObjectFactoryBase::UnRegisterAllFactories(); + } +}; +static CleanUpObjectFactory CleanUpObjectFactoryGlobal; +} + +namespace igtl +{ + +/** + * Add this for the SGI compiler which does not seem + * to provide a default implementation as it should. + */ +bool operator==(const ObjectFactoryBase::OverrideInformation& rhs, + const ObjectFactoryBase::OverrideInformation& lhs) +{ + return (rhs.m_Description == lhs.m_Description + && rhs.m_OverrideWithName == lhs.m_OverrideWithName); +} + +/** + * Add this for the SGI compiler which does not seem + * to provide a default implementation as it should. + */ +bool operator<(const ObjectFactoryBase::OverrideInformation& rhs, + const ObjectFactoryBase::OverrideInformation& lhs) +{ + return (rhs.m_Description < lhs.m_Description + && rhs.m_OverrideWithName < lhs.m_OverrideWithName); +} + + +/** \class StringOverMap + * \brief Internal implementation class for ObjectFactorBase. + * + * Create a sub class to shrink the size of the symbols + * Also, so a forward reference can be put in ObjectFactoryBase.h + * and a pointer member can be used. This avoids other + * classes including and getting long symbol warnings. + */ +typedef std::multimap +StringOverMapType; + +/** \class OverRideMap + * \brief Internal implementation class for ObjectFactorBase. + */ +class OverRideMap : public StringOverMapType +{ +public: +}; + +/** + * Initialize static list of factories. + */ +std::list* +ObjectFactoryBase::m_RegisteredFactories = 0; + + +/** + * Create an instance of a named igtl object using the loaded + * factories + */ +LightObject::Pointer +ObjectFactoryBase +::CreateInstance(const char* igtlclassname) +{ + if ( !ObjectFactoryBase::m_RegisteredFactories ) + { + ObjectFactoryBase::Initialize(); + } + + for ( std::list::iterator + i = m_RegisteredFactories->begin(); + i != m_RegisteredFactories->end(); ++i ) + { + LightObject::Pointer newobject = (*i)->CreateObject(igtlclassname); + if(newobject) + { + newobject->Register(); + return newobject; + } + } + return 0; +} + + +std::list +ObjectFactoryBase +::CreateAllInstance(const char* igtlclassname) +{ + if ( !ObjectFactoryBase::m_RegisteredFactories ) + { + ObjectFactoryBase::Initialize(); + } + std::list created; + for ( std::list::iterator + i = m_RegisteredFactories->begin(); + i != m_RegisteredFactories->end(); ++i ) + { + LightObject::Pointer newobject = (*i)->CreateObject(igtlclassname); + if(newobject) + { + created.push_back(newobject); + } + } + return created; +} + + +/** + * A one time initialization method. + */ +void +ObjectFactoryBase +::Initialize() +{ + CleanUpObjectFactoryGlobal.Use(); + /** + * Don't do anything if we are already initialized + */ + if ( ObjectFactoryBase::m_RegisteredFactories ) + { + return; + } + + ObjectFactoryBase::m_RegisteredFactories = + new std::list; + ObjectFactoryBase::RegisterDefaults(); + // ObjectFactoryBase::LoadDynamicFactories(); +} + + +/** + * Register any factories that are always present in IGTL like + * the OpenGL factory, currently this is not done. + */ +void +ObjectFactoryBase +::RegisterDefaults() +{ +} + +///** +// * Load all libraries in IGTL_AUTOLOAD_PATH +// */ +//void +//ObjectFactoryBase +//::LoadDynamicFactories() +//{ +// /** +// * follow PATH conventions +// */ +//#ifdef _WIN32 +// char PathSeparator = ';'; +//#else +// char PathSeparator = ':'; +//#endif +// +// std::string LoadPath; +// if (getenv("IGTL_AUTOLOAD_PATH")) +// { +// LoadPath = getenv("IGTL_AUTOLOAD_PATH"); +// } +// else +// { +// return; +// } +// +// if(LoadPath.size() == 0) +// { +// return; +// } +// std::string::size_type EndSeparatorPosition = 0; +// std::string::size_type StartSeparatorPosition = 0; +// +// while ( StartSeparatorPosition != std::string::npos ) +// { +// StartSeparatorPosition = EndSeparatorPosition; +// +// /** +// * find PathSeparator in LoadPath +// */ +// EndSeparatorPosition = LoadPath.find(PathSeparator, +// StartSeparatorPosition); +// if(EndSeparatorPosition == std::string::npos) +// { +// EndSeparatorPosition = LoadPath.size() + 1; // Add 1 to simulate +// // having a separator +// } +// std::string CurrentPath = +// LoadPath.substr(StartSeparatorPosition, +// EndSeparatorPosition - StartSeparatorPosition); +// +// ObjectFactoryBase::LoadLibrariesInPath(CurrentPath.c_str()); +// +// /** +// * Move past separator +// */ +// if(EndSeparatorPosition > LoadPath.size()) +// { +// StartSeparatorPosition = std::string::npos; +// } +// else +// { +// EndSeparatorPosition++; // Skip the separator +// } +// } +//} + + +/** + * A file scope helper function to concat path and file into + * a full path + */ + +//static std::string +//CreateFullPath(const char* path, const char* file) +//{ +// std::string ret; +//#ifdef _WIN32 +// const char sep = '\\'; +//#else +// const char sep = '/'; +//#endif +// /** +// * make sure the end of path is a separator +// */ +// ret = path; +// if ( !ret.empty() && ret[ret.size()-1] != sep ) +// { +// ret += sep; +// } +// ret += file; +// return ret; +//} + + +/** + * A file scope typedef to make the cast code to the load + * function cleaner to read. + */ +typedef ObjectFactoryBase* (* IGTL_LOAD_FUNCTION)(); + + +///** +// * A file scoped function to determine if a file has +// * the shared library extension in its name, this converts name to lower +// * case before the compare, DynamicLoader always uses +// * lower case for LibExtension values. +// */ +//inline bool +//NameIsSharedLibrary(const char* name) +//{ +// std::string extension = igtlsys::DynamicLoader::LibExtension(); +// +//#ifdef __APPLE__ +// // possible bug: CMake generated build file on the Mac makes +// // libraries with a .dylib extension. kwsys guesses the extension +// // should be ".so" +// extension = ".dylib"; +//#endif +// +// std::string sname = name; +// if ( sname.rfind(extension) == sname.size() - extension.size() ) +// { +// return true; +// } +// return false; +//} + +///** +// * +// */ +//void +//ObjectFactoryBase +//::LoadLibrariesInPath(const char* path) +//{ +// Directory::Pointer dir = Directory::New(); +// if ( !dir->Load(path) ) +// { +// return; +// } +// +// /** +// * Attempt to load each file in the directory as a shared library +// */ +// for ( unsigned int i = 0; i < dir->GetNumberOfFiles(); i++ ) +// { +// const char* file = dir->GetFile(i); +// /** +// * try to make sure the file has at least the extension +// * for a shared library in it. +// */ +// if ( NameIsSharedLibrary(file) ) +// { +// std::string fullpath = CreateFullPath(path, file); +// LibHandle lib = DynamicLoader::OpenLibrary(fullpath.c_str()); +// if ( lib ) +// { +// /** +// * Look for the symbol igtlLoad in the library +// */ +// IGTL_LOAD_FUNCTION loadfunction +// = (IGTL_LOAD_FUNCTION)DynamicLoader::GetSymbolAddress(lib, "igtlLoad"); +// /** +// * if the symbol is found call it to create the factory +// * from the library +// */ +// if ( loadfunction ) +// { +// ObjectFactoryBase* newfactory = (*loadfunction)(); +// +// /** +// * initialize class members if load worked +// */ +// newfactory->m_LibraryHandle = (void*)lib; +// newfactory->m_LibraryPath = fullpath; +// newfactory->m_LibraryDate = 0; // unused for now... +// ObjectFactoryBase::RegisterFactory(newfactory); +// } +// else +// { +// // We would really like to close the lib if it does not +// // contain the igtlLoad symbol. Unfortuantely, it seems that +// // some systems crash on the call +// // DynamicLoader::CloseLibrary(lib) if the lib has symbols +// // that the current executable is using. +// } +// } +// } +// } +//} + + +/** + * Recheck the IGTL_AUTOLOAD_PATH for new libraries + */ +void +ObjectFactoryBase +::ReHash() +{ + ObjectFactoryBase::UnRegisterAllFactories(); + ObjectFactoryBase::Initialize(); +} + + +/** + * initialize class members + */ +ObjectFactoryBase::ObjectFactoryBase() +{ + m_LibraryHandle = 0; + m_LibraryDate = 0; + m_OverrideMap = new OverRideMap; +} + + +/** + * Unload the library and free the path string + */ +ObjectFactoryBase +::~ObjectFactoryBase() +{ + m_OverrideMap->erase(m_OverrideMap->begin(), m_OverrideMap->end()); + delete m_OverrideMap; +} + + +/** + * Add a factory to the registered list + */ +void +ObjectFactoryBase +::RegisterFactory(ObjectFactoryBase* factory) +{ + if ( factory->m_LibraryHandle == 0 ) + { + const char nonDynamicName[] = "Non-Dynamicaly loaded factory"; + factory->m_LibraryPath = nonDynamicName; + } +// if ( strcmp(factory->GetIGTLSourceVersion(), +// Version::GetIGTLSourceVersion()) != 0 ) +// { +// igtlGenericOutputMacro(<< "Possible incompatible factory load:" +// << "\nRunning igtl version :\n" << Version::GetIGTLSourceVersion() +// << "\nLoaded factory version:\n" << factory->GetIGTLSourceVersion() +// << "\nLoading factory:\n" << factory->m_LibraryPath << "\n"); +// } + + ObjectFactoryBase::Initialize(); + ObjectFactoryBase::m_RegisteredFactories->push_back(factory); + factory->Register(); +} + + +/** + * + */ +void +ObjectFactoryBase +::PrintSelf(std::ostream& os) const +{ + Superclass::PrintSelf(os); + + const char* indent = " "; + + os << indent << "Factory DLL path: " << m_LibraryPath.c_str() << "\n"; + os << indent << "Factory description: " << this->GetDescription() << std::endl; + + int num = static_cast( m_OverrideMap->size() ); + os << indent << "Factory overides " << num << " classes:" << std::endl; + + //indent = indent.GetNextIndent(); + for(OverRideMap::iterator i = m_OverrideMap->begin(); + i != m_OverrideMap->end(); ++i) + { + os << indent << "Class : " << (*i).first.c_str() << "\n"; + os << indent << "Overridden with: " << (*i).second.m_OverrideWithName.c_str() + << std::endl; + os << indent << "Enable flag: " << (*i).second.m_EnabledFlag + << std::endl; + os << indent << "Create object: " << (*i).second.m_CreateObject + << std::endl; + os << std::endl; + } +} + + +/** + * + */ +void +ObjectFactoryBase +::UnRegisterFactory(ObjectFactoryBase* factory) +{ + for ( std::list::iterator i = + m_RegisteredFactories->begin(); + i != m_RegisteredFactories->end(); ++i ) + { + if ( factory == *i ) + { + factory->UnRegister(); + m_RegisteredFactories->remove(factory); + return; + } + } +} + + +/** + * unregister all factories and delete the RegisteredFactories list + */ +void +ObjectFactoryBase +::UnRegisterAllFactories() +{ + + if ( ObjectFactoryBase::m_RegisteredFactories ) + { + // Collect up all the library handles so they can be closed + // AFTER the factory has been deleted. + std::list libs; + for ( std::list::iterator i + = m_RegisteredFactories->begin(); + i != m_RegisteredFactories->end(); ++i ) + { + libs.push_back(static_cast((*i)->m_LibraryHandle)); + } + // Unregister each factory + for ( std::list::iterator f + = m_RegisteredFactories->begin(); + f != m_RegisteredFactories->end(); ++f ) + { + (*f)->UnRegister(); + } +// // And delete the library handles all at once +// for ( std::list::iterator lib = libs.begin(); +// lib != libs.end(); +// ++lib) +// { +// if((*lib)) +// { +// DynamicLoader::CloseLibrary(static_cast(*lib)); +// } +// } + delete ObjectFactoryBase::m_RegisteredFactories; + ObjectFactoryBase::m_RegisteredFactories = 0; + } +} + + +/** + * + */ +void +ObjectFactoryBase +::RegisterOverride(const char* classOverride, + const char* subclass, + const char* description, + bool enableFlag, + CreateObjectFunctionBase* + createFunction) +{ + ObjectFactoryBase::OverrideInformation info; + info.m_Description = description; + info.m_OverrideWithName = subclass; + info.m_EnabledFlag = enableFlag; + info.m_CreateObject = createFunction; + + m_OverrideMap->insert(OverRideMap::value_type(classOverride, info)); +} + + +LightObject::Pointer +ObjectFactoryBase +::CreateObject(const char* igtlclassname) +{ + OverRideMap::iterator start = m_OverrideMap->lower_bound(igtlclassname); + OverRideMap::iterator end = m_OverrideMap->upper_bound(igtlclassname); + + for ( OverRideMap::iterator i = start; i != end; ++i ) + { + if ( i != m_OverrideMap->end() && (*i).second.m_EnabledFlag) + { + return (*i).second.m_CreateObject->CreateObject(); + } + } + return 0; +} + + +/** + * + */ +void +ObjectFactoryBase +::SetEnableFlag(bool flag, + const char* className, + const char* subclassName) +{ + OverRideMap::iterator start = m_OverrideMap->lower_bound(className); + OverRideMap::iterator end = m_OverrideMap->upper_bound(className); + for ( OverRideMap::iterator i = start; i != end; ++i ) + { + if ( (*i).second.m_OverrideWithName == subclassName ) + { + (*i).second.m_EnabledFlag = flag; + } + } +} + + +/** + * + */ +bool +ObjectFactoryBase +::GetEnableFlag(const char* className, const char* subclassName) +{ + OverRideMap::iterator start = m_OverrideMap->lower_bound(className); + OverRideMap::iterator end = m_OverrideMap->upper_bound(className); + for ( OverRideMap::iterator i = start; i != end; ++i ) + { + if ( (*i).second.m_OverrideWithName == subclassName ) + { + return (*i).second.m_EnabledFlag; + } + } + return 0; +} + + +/** + * + */ +void +ObjectFactoryBase +::Disable(const char* className) +{ + OverRideMap::iterator start = m_OverrideMap->lower_bound(className); + OverRideMap::iterator end = m_OverrideMap->upper_bound(className); + for ( OverRideMap::iterator i = start; i != end; ++i ) + { + (*i).second.m_EnabledFlag = 0; + } +} + + +/** + * + */ +std::list +ObjectFactoryBase +::GetRegisteredFactories() +{ + return *ObjectFactoryBase::m_RegisteredFactories; +} + + +/** + * Return a list of classes that this factory overrides. + */ +std::list +ObjectFactoryBase +::GetClassOverrideNames() +{ + std::list ret; + for ( OverRideMap::iterator i = m_OverrideMap->begin(); + i != m_OverrideMap->end(); ++i ) + { + ret.push_back((*i).first); + } + return ret; +} + + +/** + * Return a list of the names of classes that override classes. + */ +std::list +ObjectFactoryBase +::GetClassOverrideWithNames() +{ + std::list ret; + for ( OverRideMap::iterator i = m_OverrideMap->begin(); + i != m_OverrideMap->end(); ++i ) + { + ret.push_back((*i).second.m_OverrideWithName); + } + return ret; +} + + +/** + * Retrun a list of descriptions for class overrides + */ +std::list +ObjectFactoryBase +::GetClassOverrideDescriptions() +{ + std::list ret; + for ( OverRideMap::iterator i = m_OverrideMap->begin(); + i != m_OverrideMap->end(); ++i ) + { + ret.push_back((*i).second.m_Description); + } + return ret; +} + + +/** + * Return a list of enable flags + */ +std::list +ObjectFactoryBase +::GetEnableFlags() +{ + std::list ret; + for( OverRideMap::iterator i = m_OverrideMap->begin(); + i != m_OverrideMap->end(); ++i) + { + ret.push_back((*i).second.m_EnabledFlag); + } + return ret; +} + +/** + * Return the path to a dynamically loaded factory. */ +const char * +ObjectFactoryBase +::GetLibraryPath() +{ + return m_LibraryPath.c_str(); +} + +} // end namespace igtl diff --git a/openigtlink/repo/Source/igtlObjectFactoryBase.h b/openigtlink/repo/Source/igtlObjectFactoryBase.h new file mode 100644 index 0000000..415cb89 --- /dev/null +++ b/openigtlink/repo/Source/igtlObjectFactoryBase.h @@ -0,0 +1,197 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkObjectFactoryBase.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlObjectFactoryBase_h +#define __igtlObjectFactoryBase_h + +#include "igtlObject.h" +#include "igtlCreateObjectFunction.h" +#include +#include + +namespace igtl +{ +/** \class ObjectFactoryBase + * \brief Create instances of classes using an object factory. + * + * ObjectFactoryBase is used to create igtl objects. The base class + * ObjectFactoryBase contains a static method CreateInstance() that is + * used to create igtl objects from the list of registerd ObjectFactoryBase + * sub-classes. The first time CreateInstance() is called, all dll's or + * shared libraries in the environment variable IGTL_AUTOLOAD_PATH are loaded + * into the current process. The C function igtlLoad is called on each dll. + * igtlLoad should return an instance of the factory sub-class implemented in + * the shared library. IGTL_AUTOLOAD_PATH is an environment variable + * containing a colon separated (semi-colon on win32) list of paths. + * + * This can be use to overide the creation of any object in IGTL. + * + * \ingroup IGTLSystemObjects + */ + +class OverRideMap; + +class IGTLCommon_EXPORT ObjectFactoryBase : public Object +{ +public: + /** Run-time type information (and related methods). */ + igtlTypeMacro(ObjectFactoryBase, Object); + + /** Create and return an instance of the named igtl object. + * Each loaded ObjectFactoryBase will be asked in the order + * the factory was in the IGTL_AUTOLOAD_PATH. After the + * first factory returns the object no other factories are asked. */ + static LightObject::Pointer CreateInstance(const char* igtlclassname); + + /** Create and return all possible instances of the named igtl object. + * Each loaded ObjectFactoryBase will be asked in the order + * the factory was in the IGTL_AUTOLOAD_PATH. All created objects + * will be returned in the list. */ + static std::list + CreateAllInstance(const char* igtlclassname); + + /** Re-check the IGTL_AUTOLOAD_PATH for new factory libraries. + * This calls UnRegisterAll before re-loading. */ + static void ReHash(); + + /** Register a factory so it can be used to create igtl objects. */ + static void RegisterFactory(ObjectFactoryBase* ); + + /** Remove a factory from the list of registered factories. */ + static void UnRegisterFactory(ObjectFactoryBase*); + + /** Unregister all factories. */ + static void UnRegisterAllFactories(); + + /** Return the list of all registered factories. This is NOT a copy, + * do not remove items from this list! */ + static std::list GetRegisteredFactories(); + + /** All sub-classes of ObjectFactoryBase should must return the version of + * IGTL they were built with. This should be implemented with the macro + * IGTL_SOURCE_VERSION and NOT a call to Version::GetIGTLSourceVersion. + * As the version needs to be compiled into the file as a string constant. + * This is critical to determine possible incompatible dynamic factory loads. */ + virtual const char* GetIGTLSourceVersion(void) const = 0; + + /** Return a descriptive string describing the factory. */ + virtual const char* GetDescription(void) const = 0; + + /** Return a list of classes that this factory overrides. */ + virtual std::list GetClassOverrideNames(); + + /** Return a list of the names of classes that override classes. */ + virtual std::list GetClassOverrideWithNames(); + + /** Return a list of descriptions for class overrides. */ + virtual std::list GetClassOverrideDescriptions(); + + /** Return a list of enable flags. */ + virtual std::list GetEnableFlags(); + + /** Set the Enable flag for the specific override of className. */ + virtual void SetEnableFlag(bool flag, + const char* className, + const char* subclassName); + + /** Get the Enable flag for the specific override of className. */ + virtual bool GetEnableFlag(const char* className, + const char* subclassName); + + /** Set all enable flags for the given class to 0. This will + * mean that the factory will stop producing class with the given + * name. */ + virtual void Disable(const char* className); + + /** This returns the path to a dynamically loaded factory. */ + const char* GetLibraryPath(); + + /** \class OverrideInformation + * \brief Internal implementation class for ObjectFactorBase. */ + struct OverrideInformation + { + std::string m_Description; + std::string m_OverrideWithName; + bool m_EnabledFlag; + CreateObjectFunctionBase::Pointer m_CreateObject; + }; + +protected: + void PrintSelf(std::ostream& os) const override; + + /** Register object creation information with the factory. */ + void RegisterOverride(const char* classOverride, + const char* overrideClassName, + const char* description, + bool enableFlag, + CreateObjectFunctionBase* createFunction); + + /** This method is provided by sub-classes of ObjectFactoryBase. + * It should create the named igtl object or return 0 if that object + * is not supported by the factory implementation. */ + virtual LightObject::Pointer CreateObject(const char* igtlclassname ); + + ObjectFactoryBase(); + virtual ~ObjectFactoryBase(); + +private: + OverRideMap* m_OverrideMap; + + ObjectFactoryBase(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** Initialize the static members of ObjectFactoryBase. RegisterDefaults + * is called here. */ + static void Initialize(); + + /** Register default factories which are not loaded at run time. */ + static void RegisterDefaults(); + +// /** Load dynamic factories from the IGTL_AUTOLOAD_PATH */ +// static void LoadDynamicFactories(); +// +// /** Load all dynamic libraries in the given path */ +// static void LoadLibrariesInPath( const char*); +// + /** list of registered factories */ + static std::list* m_RegisteredFactories; + + /** Member variables for a factory set by the base class + * at load or register time */ + void* m_LibraryHandle; + unsigned long m_LibraryDate; + std::string m_LibraryPath; +}; + +} // end namespace igtl + +#endif diff --git a/openigtlink/repo/Source/igtlPointMessage.cxx b/openigtlink/repo/Source/igtlPointMessage.cxx new file mode 100644 index 0000000..444045f --- /dev/null +++ b/openigtlink/repo/Source/igtlPointMessage.cxx @@ -0,0 +1,301 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlPointMessage.h" + +#include "igtl_header.h" +#include "igtl_point.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include +#include + +namespace igtl { + + +//---------------------------------------------------------------------- +// igtl::PointElement class + +PointElement::PointElement() : Object() +{ + this->m_Name = ""; + this->m_GroupName = ""; + this->m_RGBA[0] = 0; + this->m_RGBA[1] = 0; + this->m_RGBA[2] = 0; + this->m_RGBA[3] = 0; + this->m_Position[0] = 0.0; + this->m_Position[1] = 0.0; + this->m_Position[2] = 0.0; + this->m_Radius = 0.0; + this->m_Owner = ""; +} + + +PointElement::~PointElement() +{ +} + + +int PointElement::SetName(const char* name) +{ + if (name != NULL && strlen(name) <= IGTL_POINT_LEN_NAME) + { + this->m_Name = name; + return 1; + } + else + { + return 0; + } +} + + +int PointElement::SetGroupName(const char* grpname) +{ + if (grpname != NULL && strlen(grpname) <= IGTL_POINT_LEN_GROUP_NAME) + { + this->m_GroupName = grpname; + return 1; + } + else + { + return 0; + } +} + + +void PointElement::SetRGBA(igtlUint8 rgba[4]) +{ + this->m_RGBA[0] = rgba[0]; + this->m_RGBA[1] = rgba[1]; + this->m_RGBA[2] = rgba[2]; + this->m_RGBA[3] = rgba[3]; +} + + +void PointElement::SetRGBA(igtlUint8 r, igtlUint8 g, igtlUint8 b, igtlUint8 a) +{ + this->m_RGBA[0] = r; + this->m_RGBA[1] = g; + this->m_RGBA[2] = b; + this->m_RGBA[3] = a; +} + + +void PointElement::GetRGBA(igtlUint8* rgba) +{ + rgba[0] = this->m_RGBA[0]; + rgba[1] = this->m_RGBA[1]; + rgba[2] = this->m_RGBA[2]; + rgba[3] = this->m_RGBA[3]; +} + + + +void PointElement::GetRGBA(igtlUint8& r, igtlUint8& g, igtlUint8& b, igtlUint8& a) +{ + r = this->m_RGBA[0]; + g = this->m_RGBA[1]; + b = this->m_RGBA[2]; + a = this->m_RGBA[3]; +} + +void PointElement::SetPosition(igtlFloat32 position[3]) +{ + this->m_Position[0] = position[0]; + this->m_Position[1] = position[1]; + this->m_Position[2] = position[2]; +} + + +void PointElement::SetPosition(igtlFloat32 x, igtlFloat32 y, igtlFloat32 z) +{ + this->m_Position[0] = x; + this->m_Position[1] = y; + this->m_Position[2] = z; +} + + +void PointElement::GetPosition(igtlFloat32* position) +{ + position[0] = this->m_Position[0]; + position[1] = this->m_Position[1]; + position[2] = this->m_Position[2]; +} + + +void PointElement::GetPosition(igtlFloat32& x, igtlFloat32& y, igtlFloat32& z) +{ + x = this->m_Position[0]; + y = this->m_Position[1]; + z = this->m_Position[2]; +} + +int PointElement::SetOwner(const char* owner) +{ + if (owner != NULL && strlen(owner) <= IGTL_POINT_LEN_OWNER) + { + this->m_Owner = owner; + return 1; + } + else + { + return 0; + } +} + + +//---------------------------------------------------------------------- +// igtl::PointMessage class + +PointMessage::PointMessage() +{ + this->m_SendMessageType = "POINT"; + this->m_PointList.clear(); +} + + +PointMessage::~PointMessage() +{ +} + + +int PointMessage::AddPointElement(PointElement::Pointer& elem) +{ + m_IsBodyPacked = false; + this->m_PointList.push_back(elem); + return this->m_PointList.size(); +} + + +void PointMessage::ClearPointElement() +{ + this->m_PointList.clear(); +} + + +int PointMessage::GetNumberOfPointElement() +{ + return this->m_PointList.size(); +} + + +void PointMessage::GetPointElement(int index, PointElement::Pointer& elem) +{ + if (index >= 0 && index < (int)this->m_PointList.size()) + { + elem = this->m_PointList[index]; + } +} + + +igtlUint64 PointMessage::CalculateContentBufferSize() +{ + // The content size is the sum of the header size and status message size. + return IGTL_POINT_ELEMENT_SIZE * this->m_PointList.size(); +} + + +int PointMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + igtl_point_element* element; + element = (igtl_point_element*)(this->m_Content); + + igtl_point_element* elementHolder = element; + std::vector::iterator iter; + for (iter = this->m_PointList.begin(); iter != this->m_PointList.end(); iter ++) + { + strncpy((char*)element->name, (*iter)->GetName(), IGTL_POINT_LEN_NAME); + strncpy((char*)element->group_name, (*iter)->GetGroupName(), IGTL_POINT_LEN_GROUP_NAME); + + igtlUint8 rgba[4]; + (*iter)->GetRGBA(rgba); + element->rgba[0] = rgba[0]; + element->rgba[1] = rgba[1]; + element->rgba[2] = rgba[2]; + element->rgba[3] = rgba[3]; + + igtlFloat32 position[3]; + (*iter)->GetPosition(position); + element->position[0] = position[0]; + element->position[1] = position[1]; + element->position[2] = position[2]; + + element->radius = (*iter)->GetRadius(); + + strncpy((char*)element->owner, (*iter)->GetOwner(), IGTL_POINT_LEN_OWNER); + + element ++; + } + + igtl_point_convert_byte_order(elementHolder, this->m_PointList.size()); + + return 1; +} + + +int PointMessage::UnpackContent() +{ + this->m_PointList.clear(); + igtl_point_element* element = NULL; + int nElement = 0; +#if OpenIGTLink_HEADER_VERSION >= 2 + element = (igtl_point_element*) (this->m_Content); + bool isUnpacked(true); + nElement = igtl_point_get_data_n(CalculateReceiveContentSize(isUnpacked)); +#elif OpenIGTLink_PROTOCOL_VERSION <=2 + element = (igtl_point_element*) this->m_Body; + nElement = igtl_point_get_data_n(this->m_BodySizeToRead); +#endif + + igtl_point_convert_byte_order(element, nElement); + + char strbuf[128]; + for (int i = 0; i < nElement; i ++) + { + PointElement::Pointer elemClass = PointElement::New(); + + // Add '\n' at the end of each string + // (necessary for a case, where a string reaches the maximum length.) + strbuf[IGTL_POINT_LEN_NAME] = '\n'; + strncpy(strbuf, (char*)element->name, IGTL_POINT_LEN_NAME); + elemClass->SetName((const char*)strbuf); + + strbuf[IGTL_POINT_LEN_GROUP_NAME] = '\n'; + strncpy(strbuf, (char*)element->group_name, IGTL_POINT_LEN_GROUP_NAME); + elemClass->SetGroupName(strbuf); + + elemClass->SetRGBA(element->rgba); + elemClass->SetPosition(element->position); + elemClass->SetRadius(element->radius); + + strbuf[IGTL_POINT_LEN_OWNER] = '\n'; + strncpy(strbuf, (char*)element->owner, IGTL_POINT_LEN_OWNER); + elemClass->SetOwner(strbuf); + + this->m_PointList.push_back(elemClass); + + element ++; + } + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlPointMessage.h b/openigtlink/repo/Source/igtlPointMessage.h new file mode 100644 index 0000000..1e0e4df --- /dev/null +++ b/openigtlink/repo/Source/igtlPointMessage.h @@ -0,0 +1,173 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlPointMessage_h +#define __igtlPointMessage_h + +#include +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +#include "igtlImageMessage.h" + +namespace igtl +{ + + +/// A class to manage point information. +class IGTLCommon_EXPORT PointElement: public Object +{ +public: + igtlTypeMacro(igtl::PointElement, igtl::Object); + igtlNewMacro(igtl::PointElement); + +public: + + /// Sets the name/description of the point. The string 'name' must not exceed 64 characters. + int SetName(const char* name); + + /// Gets the name/description of the point. + const char* GetName() { return this->m_Name.c_str(); }; + + /// Sets the group name e.g. "Labeled Point", "Landmark", "Fiducial", etc. + int SetGroupName(const char* grpname); + + /// Gets the group name + const char* GetGroupName() { return this->m_GroupName.c_str(); }; + + /// Sets the color of the point specified by an array of R, G, B and A. + void SetRGBA(igtlUint8 rgba[4]); + + /// Sets the color of the point specified by values of R, G, B and A. + void SetRGBA(igtlUint8 r, igtlUint8 g, igtlUint8 b, igtlUint8 a); + + /// Gets the color of the point using an array of R, G, B and A. + void GetRGBA(igtlUint8* rgba); + + /// Gets the color of the point using values of R, G, B and A. + void GetRGBA(igtlUint8& r, igtlUint8& g, igtlUint8& b, igtlUint8& a); + + /// Sets the position of the point by an array of x, y and z coordinates. + void SetPosition(igtlFloat32 position[3]); + + /// Sets the position of the point by x, y and z coordinates. + void SetPosition(igtlFloat32 x, igtlFloat32 y, igtlFloat32 z); + + /// Gets the position of the point using an array of x, y and z coordinates. + void GetPosition(igtlFloat32* position); + + /// Gets the position of the point using x, y and z coordinates. + void GetPosition(igtlFloat32& x, igtlFloat32& y, igtlFloat32& z); + + /// Sets the radius of the point. + void SetRadius(igtlFloat32 radius) { this->m_Radius = radius; }; + + /// Gets the radius of the point. + igtlFloat32 GetRadius() { return this->m_Radius; }; + + /// Sets the name of the image that owns this label map. + int SetOwner(const char* owner); + + /// Gets the name of the image that owns this label map. + const char* GetOwner() { return this->m_Owner.c_str(); }; + +protected: + PointElement(); + ~PointElement(); + +protected: + + /// name / description (< 64 bytes) + std::string m_Name; + + /// Can be "Labeled Point", "Landmark", Fiducial", ... + std::string m_GroupName; + + /// Color in R/G/B/A + igtlUint8 m_RGBA[4]; + + /// Position + igtlFloat32 m_Position[3]; + + /// Radius of the point. Can be 0. + igtlFloat32 m_Radius; + + /// Device name of the ower image + std::string m_Owner; +}; + +/// A class for the GET_POINT message type. +class IGTLCommon_EXPORT GetPointMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::GetPointMessage, igtl::MessageBase); + igtlNewMacro(igtl::GetPointMessage); + +protected: + GetPointMessage() : MessageBase() { this->m_SendMessageType = "GET_POINT"; }; + ~GetPointMessage() override {}; +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; +}; + + +/// A class for the POINT message type. +/// The POINT message type is designed to transfer information about fiducials, which are often used in surgical planning and navigation in the image-guided therapy. +class IGTLCommon_EXPORT PointMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::PointMessage, igtl::MessageBase); + igtlNewMacro(igtl::PointMessage); + +public: + + /// Adds a point to the list. It returns the number of points in the list after + /// adding the point. + int AddPointElement(PointElement::Pointer& elem); + + /// Clears the points in the list. + void ClearPointElement(); + + /// Gets the number of points in the list. + int GetNumberOfPointElement(); + + /// Gets a pointer to the point specified by 'index'. + void GetPointElement(int index, PointElement::Pointer& elem); + + +protected: + PointMessage(); + ~PointMessage() override; + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// A list of pointers to the points. + std::vector m_PointList; + +}; + + +} // namespace igtl + +#endif // _igtlPointMessage_h \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlPolyDataMessage.cxx b/openigtlink/repo/Source/igtlPolyDataMessage.cxx new file mode 100644 index 0000000..d005759 --- /dev/null +++ b/openigtlink/repo/Source/igtlPolyDataMessage.cxx @@ -0,0 +1,1055 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlPolyDataMessage.h" + +#include "igtlTypes.h" + +#include "igtl_header.h" +#include "igtl_polydata.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include +#include + +namespace igtl { + + +// Description: +// PolyDataPointArray class +PolyDataPointArray::PolyDataPointArray() + : Object() +{ + Clear(); +} + +PolyDataPointArray::~PolyDataPointArray() +{ +} + +void PolyDataPointArray::Clear() +{ + this->m_Data.clear(); +} + +void PolyDataPointArray::SetNumberOfPoints(int n) +{ + this->m_Data.resize(n); + + std::vector< Point >::iterator iter; + for (iter = this->m_Data.begin(); iter != this->m_Data.end(); iter ++) + { + iter->resize(3); + } +} + +int PolyDataPointArray::GetNumberOfPoints() +{ + return this->m_Data.size(); +} + +int PolyDataPointArray::SetPoint(unsigned int id, igtlFloat32 * point) +{ + if (id >= this->m_Data.size()) + { + return 0; + } + Point & dst = this->m_Data[id]; + dst[0] = point[0]; + dst[1] = point[1]; + dst[2] = point[2]; + return 1; +} + +int PolyDataPointArray::SetPoint(unsigned int id, igtlFloat32 x, igtlFloat32 y, igtlFloat32 z) +{ + if (id >= this->m_Data.size()) + { + return 0; + } + Point & dst = this->m_Data[id]; + dst[0] = x; + dst[1] = y; + dst[2] = z; + return 1; +} + +int PolyDataPointArray::AddPoint(igtlFloat32 * point) +{ + Point newPoint; + newPoint.resize(3); + newPoint[0] = point[0]; + newPoint[1] = point[1]; + newPoint[2] = point[2]; + this->m_Data.push_back(newPoint); + + return 1; +} + +int PolyDataPointArray::AddPoint(igtlFloat32 x, igtlFloat32 y, igtlFloat32 z) +{ + Point newPoint; + newPoint.resize(3); + newPoint[0] = x; + newPoint[1] = y; + newPoint[2] = z; + this->m_Data.push_back(newPoint); + + return 1; +} + +int PolyDataPointArray::GetPoint(unsigned int id, igtlFloat32 & x, igtlFloat32 & y, igtlFloat32 & z) +{ + if (id >= this->m_Data.size()) + { + return 0; + } + Point & dst = this->m_Data[id]; + x = dst[0]; + y = dst[1]; + z = dst[2]; + return 1; +} + +int PolyDataPointArray::GetPoint(unsigned int id, igtlFloat32 * point) +{ + if (id >= this->m_Data.size()) + { + return 0; + } + Point & dst = this->m_Data[id]; + point[0] = dst[0]; + point[1] = dst[1]; + point[2] = dst[2]; + return 1; +} + +/// Implement support for C++11 ranged for loops +igtlRangeBasedForBodyMacro(PolyDataPointArray, std::vector, m_Data); + +// Description: +// PolyDataCellArray class to pass vertices, lines, polygons, and triangle strips +PolyDataCellArray::PolyDataCellArray() + : Object() +{ + Clear(); +} + +PolyDataCellArray::~PolyDataCellArray() +{} + +void PolyDataCellArray::Clear() +{ + this->m_Data.clear(); +} + +igtlUint32 PolyDataCellArray::GetNumberOfCells() +{ + return this->m_Data.size(); +} + +void PolyDataCellArray::AddCell(int n, igtlUint32 * cell) +{ + std::list newCell; + for (int i = 0; i < n; i ++) + { + newCell.push_back(cell[i]); + } + if (n > 0) + { + this->m_Data.push_back(newCell); + } +} + +void PolyDataCellArray::AddCell(const Cell& cell) +{ + this->m_Data.push_back(cell); +} + +igtlUint32 PolyDataCellArray::GetCellSize(unsigned int id) +{ + if (id >= this->m_Data.size()) + { + return 0; + } + return this->m_Data[id].size(); +} + +igtlUint32 PolyDataCellArray::GetTotalSize() +{ + igtlUint32 size; + + size = 0; + std::vector< std::list >::iterator iter; + for (iter = this->m_Data.begin(); iter != this->m_Data.end(); iter ++) + { + size += ((*iter).size() + 1); + } + + return size * sizeof(igtlUint32); +} + +int PolyDataCellArray::GetCell(unsigned int id, igtlUint32 * cell) +{ + if (id >= this->m_Data.size()) + { + return 0; + } + std::list & src = this->m_Data[id]; + std::list::iterator iter; + + for (iter = src.begin(); iter != src.end(); iter ++) + { + *cell = *iter; + cell ++; + } + return 1; +} + + +int PolyDataCellArray::GetCell(unsigned int id, std::list& cell) +{ + if (id >= this->m_Data.size()) + { + return 0; + } + std::list & src = this->m_Data[id]; + cell.resize(src.size()); + + std::list::iterator srcIter; + std::list::iterator dstIter = cell.begin(); + + for (srcIter = src.begin(); srcIter != src.end(); srcIter ++) + { + *dstIter = *srcIter; + dstIter ++; + } + return 1; +} + +/// Implement support for C++11 ranged for loops +igtlRangeBasedForBodyMacro(PolyDataCellArray, std::vector, m_Data); + +// Description: +// Attribute class used for passing attribute data +PolyDataAttribute::PolyDataAttribute() + : Object() +{ + Clear(); +} + +PolyDataAttribute::~PolyDataAttribute() +{ +} + +void PolyDataAttribute::Clear() +{ + this->m_Type = POINT_SCALAR; + this->m_NComponents = 1; + this->m_Name = ""; + this->m_Data.clear(); + this->m_Size = 0; +} + +int PolyDataAttribute::SetType(int t, int n) +{ + int valid = 0; + + switch(t) + { + case POINT_SCALAR: + case CELL_SCALAR: + if (n > 0 && n < 128) + { + valid = 1; + this->m_NComponents = n; + } + break; + case POINT_TCOORDS: + case CELL_TCOORDS: + case POINT_VECTOR: + case CELL_VECTOR: + case POINT_NORMAL: + case CELL_NORMAL: + valid = 1; + this->m_NComponents = 3; + break; + case POINT_TENSOR: + case CELL_TENSOR: + valid = 1; + this->m_NComponents = 9; + break; + case POINT_RGBA: + case CELL_RGBA: + valid = 1; + this->m_NComponents = 4; + break; + default: + break; + } + if (valid) + { + this->m_Type = t; + unsigned int n = this->m_Size * this->m_NComponents; + if (n != this->m_Data.size()) + { + // TODO: this may cause unnecessary memory allocation, + // unless m_Size == 0. + // Memory should be reallocate just before use. + this->m_Data.resize(n); + } + return t; + } + else + { + return -1; + } +} + + +igtlUint32 PolyDataAttribute::GetNumberOfComponents() +{ + return this->m_NComponents; +} + +igtlUint32 PolyDataAttribute::SetSize(igtlUint32 size) +{ + this->m_Size = size; + + unsigned int n = this->m_Size * this->m_NComponents; + if (n != this->m_Data.size()) + { + // TODO: this may cause unnecessary memory allocation. + // Memory should be reallocate just before use. + this->m_Data.resize(n); + } + + this->m_Data.resize(size*this->m_NComponents); + return this->m_Size; +} + +igtlUint32 PolyDataAttribute::GetSize() +{ + return this->m_Size; +} + +void PolyDataAttribute::SetName(const char * name) +{ + this->m_Name = name; +} + +int PolyDataAttribute::SetData(igtlFloat32 * data) +{ + if (!data) + { + return 0; + } + + std::vector::iterator iter; + for (iter = this->m_Data.begin(); iter != this->m_Data.end(); iter ++) + { + *iter = *data; + data ++; + } + + return 1; +} + +int PolyDataAttribute::GetData(igtlFloat32 * data) +{ + if (!data) + { + return 0; + } + + std::vector::iterator iter; + for (iter = this->m_Data.begin(); iter != this->m_Data.end(); iter ++) + { + *data = *iter; + data ++; + } + return 1; +} + +int PolyDataAttribute::SetNthData(unsigned int n, igtlFloat32 * data) +{ + if (n >= this->m_Size) + { + return 0; + } + + std::vector::iterator iter; + iter = this->m_Data.begin() + n*this->m_NComponents; + for (unsigned int i = 0; i < this->m_NComponents; i ++) + { + *iter = *data; + iter ++; + data ++; + } + return 1; +} + +int PolyDataAttribute::GetNthData(unsigned int n, igtlFloat32 * data) +{ + if (n >= this->m_Size) + { + return 0; + } + + std::vector::iterator iter; + iter = this->m_Data.begin() + n*this->m_NComponents; + for (unsigned int i = 0; i < this->m_NComponents; i ++) + { + *data = *iter; + iter ++; + data ++; + } + + return 1; +} + +int PolyDataAttribute::GetNthData(unsigned int n, std::vector& data) +{ + if (n >= this->m_Size) + { + return 0; + } + + data.clear(); + std::vector::iterator iter; + iter = this->m_Data.begin() + n*this->m_NComponents; + for (unsigned int i = 0; i < this->m_NComponents; i++) + { + data.push_back(*iter); + iter++; + } + + return 1; +} + +/// Implement support for C++11 ranged for loops +std::vector::iterator PolyDataAttribute::begin() +{ + return m_Data.begin(); +} +std::vector::iterator PolyDataAttribute::end() +{ + return m_Data.end(); +} +std::vector::const_iterator PolyDataAttribute::begin() const +{ + return m_Data.begin(); +} +std::vector::const_iterator PolyDataAttribute::end() const +{ + return m_Data.end(); +} + +std::vector::reverse_iterator PolyDataAttribute::rbegin() +{ + return m_Data.rbegin(); +} +std::vector::reverse_iterator PolyDataAttribute::rend() +{ + return m_Data.rend(); +} +std::vector::const_reverse_iterator PolyDataAttribute::rbegin() const +{ + return m_Data.rbegin(); +} +std::vector::const_reverse_iterator PolyDataAttribute::rend() const +{ + return m_Data.rend(); +} + +/// Implement support for C++11 ranged for loops +std::vector::iterator begin(PolyDataAttribute& list) +{ + return list.begin(); +} +std::vector::iterator end(PolyDataAttribute& list) +{ + return list.end(); +} +std::vector::const_iterator begin(const PolyDataAttribute& list) +{ + return list.begin(); +} +std::vector::const_iterator end(const PolyDataAttribute& list) +{ + return list.end(); +} + +std::vector::reverse_iterator rbegin(PolyDataAttribute& list) +{ + return list.rbegin(); +} +std::vector::reverse_iterator rend(PolyDataAttribute& list) +{ + return list.rend(); +} +std::vector::const_reverse_iterator rbegin(const PolyDataAttribute& list) +{ + return list.rbegin(); +} +std::vector::const_reverse_iterator rend(const PolyDataAttribute& list) +{ + return list.rend(); +} + +// Description: +// PolyDataMessage class implementation +PolyDataMessage::PolyDataMessage() +{ + this->m_SendMessageType = "POLYDATA"; + Clear(); +} + + +PolyDataMessage::~PolyDataMessage() +{ +} + + +void IGTLCommon_EXPORT SetPolyDataInfo(igtl_polydata_info * info, PolyDataMessage * pdm) +{ + + igtl_polydata_init_info(info); + + if (pdm->GetPoints()) + { + info->header.npoints = pdm->GetPoints()->GetNumberOfPoints(); + } + else + { + info->header.npoints = 0; + } + + if (pdm->GetVertices()) + { + info->header.nvertices = pdm->GetVertices()->GetNumberOfCells(); + info->header.size_vertices = pdm->GetVertices()->GetTotalSize(); + } + else + { + info->header.nvertices = 0; + info->header.size_vertices = 0; + } + + if (pdm->GetLines()) + { + info->header.nlines = pdm->GetLines()->GetNumberOfCells(); + info->header.size_lines = pdm->GetLines()->GetTotalSize(); + } + else + { + info->header.nlines = 0; + info->header.size_lines = 0; + } + + if (pdm->GetPolygons()) + { + info->header.npolygons = pdm->GetPolygons()->GetNumberOfCells(); + info->header.size_polygons = pdm->GetPolygons()->GetTotalSize(); + } + else + { + info->header.npolygons = 0; + info->header.size_polygons = 0; + } + + if (pdm->GetTriangleStrips()) + { + info->header.ntriangle_strips = pdm->GetTriangleStrips()->GetNumberOfCells(); + info->header.size_triangle_strips = pdm->GetTriangleStrips()->GetTotalSize(); + } + else + { + info->header.ntriangle_strips = 0; + info->header.size_triangle_strips = 0; + } + + info->header.nattributes = pdm->GetNumberOfAttributes(); + +} + + +void IGTLCommon_EXPORT SetPolyDataInfoAttribute(igtl_polydata_info * info, PolyDataMessage * pdm) +{ + + igtl_polydata_attribute * attr = info->attributes; + for (unsigned int i = 0; i < info->header.nattributes; i ++) + { + PolyDataAttribute * src = pdm->GetAttribute(static_cast(i)); + if (src) + { + attr->type = src->GetType(); + attr->ncomponents = src->GetNumberOfComponents(); + attr->n = src->GetSize(); + //attr->name = const_cast(src->GetName()); + // TODO: aloways allocating memory isn't a good approach... + if (attr->name) + { + free(attr->name); + } + attr->name = (char *) malloc(strlen(src->GetName())+1); + if (attr->name) + { + strcpy(attr->name, src->GetName()); + } + if (attr->data) + { + free(attr->data); + } + igtlUint32 size = attr->ncomponents * attr->n; + attr->data = (igtlFloat32*)malloc((size_t)size*sizeof(igtlFloat32)); + if (attr->data) + { + src->GetData(attr->data); + } + attr ++; + } + } +} + + +void IGTLCommon_EXPORT UnSetPolyDataInfoAttribute(igtl_polydata_info * info) +{ + + igtl_polydata_attribute * attr = info->attributes; + for (unsigned int i = 0; i < info->header.nattributes; i ++) + { + attr->type = 0; + attr->ncomponents = 0; + attr->n = 0; + if (attr->name) + { + free(attr->name); + attr->name = NULL; + } + if (attr->data) + { + free(attr->data); + attr->data = NULL; + } + attr ++; + } +} + + +igtlUint64 PolyDataMessage::CalculateContentBufferSize() +{ + // TODO: The current implementation of GetBodyPackSize() allocates + // igtl_polydata_info and the array of igtl_polydata_attribute to calculate + // the size of pack. However, this approach is not efficient because + // it causes unnecessary memory allocation. + + int dataSize; + igtl_polydata_info info; + + SetPolyDataInfo(&info, this); + + // Instead of calling igtl_polydata_alloc_info(), we only allocate + // memory for the attribute array, since igtl_polydata_alloc_info() + // allocates also allocates the memory area for actual points and + // cell data, which is not necessary to calculate polydata size. + + info.attributes = new igtl_polydata_attribute[info.header.nattributes]; + + if (!info.attributes) + { + //ERROR + return 0; + } + + // init attributes + igtl_polydata_attribute * attr = info.attributes; + for (unsigned int i = 0; i < info.header.nattributes; i ++) + { + attr->type = 0; + attr->ncomponents = 0; + attr->n = 0; + attr->name = NULL; + attr->data = NULL; + attr ++; + } + + SetPolyDataInfoAttribute(&info, this); + + dataSize = igtl_polydata_get_size(&info, IGTL_TYPE_PREFIX_NONE); + + UnSetPolyDataInfoAttribute(&info); + + //delete [] (info.attributes); + delete [] info.attributes; + + return dataSize; +} + + +int PolyDataMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + igtl_polydata_info info; + + SetPolyDataInfo(&info, this); + + if (igtl_polydata_alloc_info(&info) == 0) + { + return 0; + } + + //SetPolyDataInfoAttribute(&info, this); + + // Points + if (info.points) + { + igtlFloat32 * ptr_f = info.points; + for (int i = 0; i < this->m_Points->GetNumberOfPoints(); i ++) + { + igtlFloat32 points[3]; + this->m_Points->GetPoint(i, points); + *(ptr_f++) = points[0]; + *(ptr_f++) = points[1]; + *(ptr_f++) = points[2]; + } + } + + //Vertices + if (info.vertices) + { + igtlUint32 * ptr_i = info.vertices; + for (unsigned int i = 0; i < this->m_Vertices->GetNumberOfCells(); i ++) + { + *ptr_i = this->m_Vertices->GetCellSize(i); + ptr_i ++; + this->m_Vertices->GetCell(i, ptr_i); + ptr_i += this->m_Vertices->GetCellSize(i); + } + } + + //Lines + if (info.lines) + { + igtlUint32 * ptr_i = info.lines; + for (unsigned int i = 0; i < this->m_Lines->GetNumberOfCells(); i ++) + { + *ptr_i = this->m_Lines->GetCellSize(i); + ptr_i ++; + this->m_Lines->GetCell(i, ptr_i); + ptr_i += this->m_Lines->GetCellSize(i); + } + } + + //Polygons + if (info.polygons) + { + igtlUint32 * ptr_i = info.polygons; + for (unsigned int i = 0; i < this->m_Polygons->GetNumberOfCells(); i ++) + { + *ptr_i = this->m_Polygons->GetCellSize(i); + ptr_i ++; + this->m_Polygons->GetCell(i, ptr_i); + ptr_i += this->m_Polygons->GetCellSize(i); + } + } + + //TriangleStrips + if (info.triangle_strips) + { + igtlUint32 * ptr_i = info.triangle_strips; + for (unsigned int i = 0; i < this->m_TriangleStrips->GetNumberOfCells(); i ++) + { + *ptr_i = this->m_TriangleStrips->GetCellSize(i); + ptr_i ++; + this->m_TriangleStrips->GetCell(i, ptr_i); + ptr_i += this->m_TriangleStrips->GetCellSize(i); + } + } + + SetPolyDataInfoAttribute(&info, this); + + igtl_polydata_pack(&info, this->m_Content, IGTL_TYPE_PREFIX_NONE); + + igtl_polydata_free_info(&info); + + return 1; +} + + +int PolyDataMessage::UnpackContent() +{ + igtl_polydata_info info; + + igtl_polydata_init_info(&info); + + int r = 0; + + bool isUnpacked(true); + r = igtl_polydata_unpack(IGTL_TYPE_PREFIX_NONE, (void*)this->m_Content, &info, this->CalculateReceiveContentSize(isUnpacked)); + + if ( r == 0) + { + return 0; + } + + // Points + if (this->m_Points.IsNull()) + { + this->m_Points = igtl::PolyDataPointArray::New(); + } + this->m_Points->Clear(); + if (info.header.npoints > 0) + { + this->m_Points->SetNumberOfPoints(info.header.npoints); + for (unsigned int i = 0; i < info.header.npoints; i ++) + { + this->m_Points->SetPoint(i, &(info.points[i*3])); + } + } + + igtlUint32 * ptr; + + // Vertices + if (this->m_Vertices.IsNull()) + { + this->m_Vertices = igtl::PolyDataCellArray::New(); + } + this->m_Vertices->Clear(); + ptr = info.vertices; + for (unsigned int i = 0; i < info.header.nvertices; i ++) + { + unsigned int n = *ptr; + ptr ++; + this->m_Vertices->AddCell(n, ptr); + ptr += n; + } + + // Lines + if (this->m_Lines.IsNull()) + { + this->m_Lines = igtl::PolyDataCellArray::New(); + } + this->m_Lines->Clear(); + ptr = info.lines; + for (unsigned int i = 0; i < info.header.nlines; i ++) + { + unsigned int n = *ptr; + ptr ++; + this->m_Lines->AddCell(n, ptr); + ptr += n; + } + + // Polygons + if (this->m_Polygons.IsNull()) + { + this->m_Polygons = igtl::PolyDataCellArray::New(); + } + this->m_Polygons->Clear(); + ptr = info.polygons; + for (unsigned int i = 0; i < info.header.npolygons; i ++) + { + unsigned int n = *ptr; + ptr ++; + this->m_Polygons->AddCell(n, ptr); + ptr += n; + } + + // TriangleStrips + if (this->m_TriangleStrips.IsNull()) + { + this->m_TriangleStrips = igtl::PolyDataCellArray::New(); + } + this->m_TriangleStrips->Clear(); + ptr = info.triangle_strips; + for (unsigned int i = 0; i < info.header.ntriangle_strips; i ++) + { + unsigned int n = *ptr; + ptr ++; + this->m_TriangleStrips->AddCell(n, ptr); + ptr += n; + } + + // Attributes + this->m_Attributes.clear(); + igtl_polydata_attribute * attr = info.attributes; + for (unsigned int i = 0; i < info.header.nattributes; i ++) + { + + + PolyDataAttribute::Pointer pda = PolyDataAttribute::New(); + if (pda.IsNotNull()) + { + pda->Clear(); + pda->SetType(attr->type, attr->ncomponents); + pda->SetSize(attr->n); + pda->SetName(attr->name); + pda->SetData(attr->data); + attr ++; + this->m_Attributes.push_back(pda); + } + } + + + return 1; +} + + +void PolyDataMessage::Clear() +{ + + if (this->m_Points.IsNotNull()) + { + //this->m_Points->Delete(); + this->m_Points = NULL; + } + if (this->m_Vertices.IsNotNull()) + { + //this->m_Vertices->Delete(); + this->m_Vertices = NULL; + } + if(this->m_Lines.IsNotNull()) + { + //this->m_Lines->Delete(); + this->m_Lines = NULL; + } + if (this->m_Polygons.IsNotNull()) + { + //this->m_Polygons->Delete(); + this->m_Polygons = NULL; + } + if (this->m_TriangleStrips.IsNotNull()) + { + //this->m_TriangleStrips->Delete(); + this->m_TriangleStrips = NULL; + } + // TODO: is this OK? + this->m_Attributes.clear(); +} + +void PolyDataMessage::ClearAttributes() +{ + std::vector::iterator iter; + for (iter = this->m_Attributes.begin(); iter != this->m_Attributes.end(); iter ++) + { + *iter = NULL; + } + this->m_Attributes.clear(); +} + +void PolyDataMessage::AddAttribute(PolyDataAttribute * att) +{ + m_IsBodyPacked = false; + this->m_Attributes.push_back(att); +} + +int PolyDataMessage::GetNumberOfAttributes() +{ + return this->m_Attributes.size(); +} + +PolyDataAttribute * PolyDataMessage::GetAttribute(AttributeList::size_type id) +{ + if (id >= this->m_Attributes.size()) + { + return NULL; + } + + return this->m_Attributes[id]; +} + +PolyDataAttribute * PolyDataMessage::GetAttribute(const std::string& name) +{ + for(AttributeList::size_type i = 0; i < this->m_Attributes.size(); ++i) + { + if (this->m_Attributes[i]->GetName() == name) + { + return this->m_Attributes[i]; + } + } + + return NULL; +} + +PolyDataAttribute * PolyDataMessage::GetAttribute(int type) +{ + for (AttributeList::size_type i = 0; i < this->m_Attributes.size(); ++i) + { + if (this->m_Attributes[i]->GetType() == type) + { + return this->m_Attributes[i]; + } + } + + return NULL; +} + +GetPolyDataMessage::GetPolyDataMessage() +{ + this->m_SendMessageType = "GET_POLYDATA"; +} + +bool RTSPolyDataMessage::GetStatus() const +{ + return m_Status == 1; +} + +void RTSPolyDataMessage::SetStatus(bool status) +{ + m_IsBodyPacked = false; + m_Status = status ? 1 : 0; +} + +igtlUint64 RTSPolyDataMessage::CalculateContentBufferSize() +{ + return sizeof(igtl_uint8); +} + +int RTSPolyDataMessage::PackContent() +{ + AllocateBuffer(); + + igtl_uint8* content; + // Copy data +#if OpenIGTLink_HEADER_VERSION >= 2 + content = this->m_Content; +#else + content = this->m_Body; +#endif + + *content = m_Status; + + return 1; +} + +int RTSPolyDataMessage::UnpackContent() +{ + igtl_uint8* content; + +#if OpenIGTLink_HEADER_VERSION >= 2 + content = this->m_Content; +#else + content = this->m_Body; +#endif + + this->m_Status = *content; + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlPolyDataMessage.h b/openigtlink/repo/Source/igtlPolyDataMessage.h new file mode 100644 index 0000000..02870c5 --- /dev/null +++ b/openigtlink/repo/Source/igtlPolyDataMessage.h @@ -0,0 +1,434 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlPolyDataMessage_h +#define __igtlPolyDataMessage_h + +#include + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +namespace igtl +{ + +/// A class for the GET_POLYDATA message type. +class IGTLCommon_EXPORT GetPolyDataMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::GetPolyDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::GetPolyDataMessage); + +protected: + GetPolyDataMessage(); + ~GetPolyDataMessage() {}; +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; +}; + +/// A class for the RTS_POLYDATA message type. +class IGTLCommon_EXPORT RTSPolyDataMessage : public MessageBase +{ +public: + igtlTypeMacro(igtl::RTSPolyDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::RTSPolyDataMessage); + + bool GetStatus() const; + void SetStatus(bool status); + +protected: + RTSPolyDataMessage() : MessageBase() { this->m_SendMessageType = "RTS_POLYDATA"; }; + ~RTSPolyDataMessage() {}; + +protected: + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + +protected: + /// Result of the previous GET_POLYDATA/POLYDATA message + igtl_uint8 m_Status; +}; + +/// A class for the STP_POLYDATA message type. +class IGTLCommon_EXPORT StopPolyDataMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::StopPolyDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::StopPolyDataMessage); + +protected: + StopPolyDataMessage() : MessageBase() { this->m_SendMessageType = "STP_POLYDATA"; }; + ~StopPolyDataMessage() {}; +protected: + virtual int GetBodyPackSize() { return 0; }; + virtual int PackBody() { AllocatePack(); return 1; }; + virtual int UnpackBody() { return 1; }; +}; + +/// A class for the STT_POLYDATA message type. +class IGTLCommon_EXPORT StartPolyDataMessage : public MessageBase +{ +public: + igtlTypeMacro(igtl::StartPolyDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::StartPolyDataMessage); + +protected: + StartPolyDataMessage() : MessageBase() { this->m_SendMessageType = "STT_POLYDATA"; }; + ~StartPolyDataMessage() {}; +protected: + virtual int GetBodyPackSize() { return 0; }; + virtual int PackBody() { AllocatePack(); return 1; }; + virtual int UnpackBody() { return 1; }; +}; + + + +// A class to manage a point array. +class IGTLCommon_EXPORT PolyDataPointArray : public Object { + + public: + + /// A vector to represent coordinates of a point. + typedef std::vector Point; + + public: + igtlTypeMacro(igtl::PolyDataPointArray, igtl::Object); + igtlNewMacro(igtl::PolyDataPointArray); + + protected: + PolyDataPointArray(); + ~PolyDataPointArray(); + + public: + + /// Clears the all points in the list. + void Clear(); + + /// Sets the number of points. This function will change the size of the list. + void SetNumberOfPoints(int n); + + /// Gets the number of points in the list. + int GetNumberOfPoints(); + + /// Substitutes the point specified by 'id' with a point specified by 'point'. + /// The 'point' contains the x, y, and z coordinates of the point. + int SetPoint(unsigned int id, igtlFloat32 * point); + + /// Substitutes the point specified by 'id' with a point specified by 'x', 'y' and 'z'. + int SetPoint(unsigned int id, igtlFloat32 x, igtlFloat32 y, igtlFloat32 z); + + /// Adds a point specified by 'point' to the list. + /// The 'point' contains the x, y, and z coordinates of the point. + int AddPoint(igtlFloat32 * point); + + /// Adds a point 'point' specified by 'x', 'y' and 'z'. + int AddPoint(igtlFloat32 x, igtlFloat32 y, igtlFloat32 z); + + /// Gets the coordinates of the point specified by 'id' + int GetPoint(unsigned int id, igtlFloat32 & x, igtlFloat32 & y, igtlFloat32 & z); + + /// Gets the coordinates of the point specified by 'id' + int GetPoint(unsigned int id, igtlFloat32 * point); + + /// Implement support for C++11 ranged for loops + igtlRangeBasedForHeaderMemberMacro(std::vector); + + private: + /// A list of the points. + std::vector< Point > m_Data; +}; + +igtlRangeBasedForHeaderExternalMacro(PolyDataPointArray, std::vector, IGTLCommon_EXPORT); + +// The PolyDataCellArray class is used to pass vertices, lines, polygons, and triangle strips +class IGTLCommon_EXPORT PolyDataCellArray : public Object { + + public: + + typedef std::list Cell; + + enum { + NULL_POINT = 0xFFFFFFFF, + }; + + public: + igtlTypeMacro(igtl::PolyDataCellArray, igtl::Object); + igtlNewMacro(igtl::PolyDataCellArray); + + protected: + PolyDataCellArray(); + ~PolyDataCellArray(); + + public: + + /// Clears the cell array. + void Clear(); + + /// Gets the number of cells in the array. + igtlUint32 GetNumberOfCells(); + + /// Adds an array of cells stored in 'cell'. The number of cells is specified by 'n'. + void AddCell(int n, igtlUint32 * cell); + + /// Adds an array of cells stored in 'cell'. + void AddCell(const Cell& cell); + + /// GetTotalSize() returns the total memory size of the cell data array in + /// POLYDATA message. Cell data array is array of cell data, consisting of + /// and array of . Both + /// and are unsigned 32-bit integer. + /// Consequently, the total size can be calculated by: + /// sizeof(igtlUint32) * (number of points for 0th cell + 1) + (number of points for 1th cell + 1) + /// ... + (number of points for (N-1)th cell + 1). Note that this includes the first igtlUint32 value + /// that specifies the number of points in each cell. + igtlUint32 GetTotalSize(); + + /// Gets the size of the cell specified by 'id'. + igtlUint32 GetCellSize(unsigned int id); + + /// Gets the cell specified by the 'id'. A list of points in the cell will be stored in the + /// 'cell'. A memory area sufficient to store the points in the cell must be allocated + /// before calling GetCell() function, and specified as 'cell'. + int GetCell(unsigned int id, igtlUint32 * cell); + + /// Gets the cell specified by the 'id'. A list of points in the cell will be stored in the 'cell'. + int GetCell(unsigned int id, Cell& cell); + + /// Implement support for C++11 ranged for loops + igtlRangeBasedForHeaderMemberMacro(std::vector); + + private: + /// A lists of the cells. Each cell consists of multiple points. + std::vector m_Data; +}; + +/// Implement support for C++11 ranged for loops +igtlRangeBasedForHeaderExternalMacro(PolyDataCellArray, std::vector, IGTLCommon_EXPORT); + +/// Attribute class used for passing attribute data. +class IGTLCommon_EXPORT PolyDataAttribute : public Object { + public: + + /// Point and cell types. + enum { + POINT_SCALAR = 0x00, + POINT_VECTOR = 0x01, + POINT_NORMAL = 0x02, + POINT_TENSOR = 0x03, + POINT_RGBA = 0x04, + POINT_TCOORDS = 0x05, + CELL_SCALAR = 0x10, + CELL_VECTOR = 0x11, + CELL_NORMAL = 0x12, + CELL_TENSOR = 0x13, + CELL_RGBA = 0x14, + CELL_TCOORDS = 0x15 + }; + + public: + igtlTypeMacro(igtl::PolyDataAttribute, igtl::Object); + igtlNewMacro(igtl::PolyDataAttribute); + + protected: + PolyDataAttribute(); + ~PolyDataAttribute(); + + public: + + /// Clears the attributes + void Clear(); + + /// SetType() is used to set the attribute type. If the attribute is set properly, + /// the function returns the type value (POINT_* or CELL_*). Otherwise + /// the function returns negative value. The second argument will be ignored + /// if 't' is neither POINT_SCALAR nor CELL_SCALAR. + /// If the POINT_SCALAR and CELL_SCALAR is specified as 't', the number of + /// components can be specified as the second argument. The number of + /// components must be 0 < n < 128. + int SetType(int t, int n=1); + + /// Gets the attribute type. + igtlUint8 GetType() { return this->m_Type; }; + + /// Gets the number of components. The number depends on the type of the points/cells e.g. + /// 3 in case of POINT_VECTOR. + igtlUint32 GetNumberOfComponents(); + + /// Sets the size of the attribute. + igtlUint32 SetSize(igtlUint32 size); + + /// Gets the size of the attribute. + igtlUint32 GetSize(); + + /// Sets the name of the attribute. + void SetName(const char * name); + + /// Gets the name of the attribute. + const char* GetName() { return this->m_Name.c_str(); }; + + /// Sets the attribute by byte array. + int SetData(igtlFloat32 * data); + + /// Gets the attribute as a byte array. + int GetData(igtlFloat32 * data); + + /// Sets the Nth data. + int SetNthData(unsigned int n, igtlFloat32 * data); + + /// Gets the Nth data. + int GetNthData(unsigned int n, igtlFloat32 * data); + + /// Gets the Nth data. + int GetNthData(unsigned int n, std::vector& data); + + /// Implement support for C++11 ranged for loops + std::vector::iterator begin(); + std::vector::iterator end(); + std::vector::const_iterator begin() const; + std::vector::const_iterator end() const; + + std::vector::reverse_iterator rbegin(); + std::vector::reverse_iterator rend(); + std::vector::const_reverse_iterator rbegin() const; + std::vector::const_reverse_iterator rend() const; + + private: + /// The attribute type. + igtlUint8 m_Type; + + /// The number of components. + igtlUint8 m_NComponents; + + /// The size of the attribute. + igtlUint32 m_Size; + + /// The name of the attribute. + std::string m_Name; + + /// The list of attributes. + std::vector m_Data; + +}; + +/// Implement support for C++11 ranged for loops +IGTLCommon_EXPORT std::vector::iterator begin(PolyDataAttribute& list); +IGTLCommon_EXPORT std::vector::iterator end(PolyDataAttribute& list); +IGTLCommon_EXPORT std::vector::const_iterator begin(const PolyDataAttribute& list); +IGTLCommon_EXPORT std::vector::const_iterator end(const PolyDataAttribute& list); + +IGTLCommon_EXPORT std::vector::reverse_iterator rbegin(PolyDataAttribute& list); +IGTLCommon_EXPORT std::vector::reverse_iterator rend(PolyDataAttribute& list); +IGTLCommon_EXPORT std::vector::const_reverse_iterator rbegin(const PolyDataAttribute& list); +IGTLCommon_EXPORT std::vector::const_reverse_iterator rend(const PolyDataAttribute& list); + +/// A class for the POLYDATA message type. +class IGTLCommon_EXPORT PolyDataMessage: public MessageBase +{ +public: + typedef std::vector AttributeList; + + igtlTypeMacro(igtl::PolyDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::PolyDataMessage); + +public: + + /// Clears the polydata. + void Clear(); + + /// Sets an array of points. + igtlSetObjectMacro(Points, PolyDataPointArray); + + /// Gets an array of points. + igtlGetObjectMacro(Points, PolyDataPointArray); + + /// Sets an array of vertices. + igtlSetObjectMacro(Vertices, PolyDataCellArray); + + /// Gets an array of vertices. + igtlGetObjectMacro(Vertices, PolyDataCellArray); + + /// Sets an array of lines. + igtlSetObjectMacro(Lines, PolyDataCellArray); + + /// Gets an array of lines. + igtlGetObjectMacro(Lines, PolyDataCellArray); + + /// Sets an array of polygons. + igtlSetObjectMacro(Polygons, PolyDataCellArray); + + /// Gets an array of polygons. + igtlGetObjectMacro(Polygons, PolyDataCellArray); + + /// Sets an array of triangle strips. + igtlSetObjectMacro(TriangleStrips, PolyDataCellArray); + + /// Gets an array of triangle strips. + igtlGetObjectMacro(TriangleStrips, PolyDataCellArray); + + /// Clears the attributes. + void ClearAttributes(); + + /// Adds an attribute. + void AddAttribute(PolyDataAttribute * att); + + /// Gets the number of attributes. + int GetNumberOfAttributes(); + + /// Gets an attribute specified by 'id'. + PolyDataAttribute * GetAttribute(AttributeList::size_type id); + + /// Gets an attribute specified by 'name'. + PolyDataAttribute * GetAttribute(const std::string& name); + + /// Gets an attribute specified by 'type'. + PolyDataAttribute * GetAttribute(int type); + +protected: + PolyDataMessage(); + ~PolyDataMessage(); + +protected: + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// A pointer to the array of points. + PolyDataPointArray::Pointer m_Points; + + /// A pointer to the array of vertices. + PolyDataCellArray::Pointer m_Vertices; + + /// A pointer to the array of lines. + PolyDataCellArray::Pointer m_Lines; + + /// A pointer to the array of polygons. + PolyDataCellArray::Pointer m_Polygons; + + /// A pointer to the array of triangle strips. + PolyDataCellArray::Pointer m_TriangleStrips; + + /// A list of pointers to the attributes. + AttributeList m_Attributes; + +}; + +} // namespace igtl + +#endif // _igtlPolyDataMessage_h diff --git a/openigtlink/repo/Source/igtlPositionMessage.cxx b/openigtlink/repo/Source/igtlPositionMessage.cxx new file mode 100644 index 0000000..4cc46b8 --- /dev/null +++ b/openigtlink/repo/Source/igtlPositionMessage.cxx @@ -0,0 +1,291 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlPositionMessage.h" + +#include "igtl_header.h" +#include "igtl_position.h" + +#include +#include + +namespace igtl { + +PositionMessage::PositionMessage(): + MessageBase() +{ + Init(); + m_SendMessageType = "POSITION"; +} + +PositionMessage::~PositionMessage() +{ +} + +void PositionMessage::Init() +{ + this->m_PackType = ALL; + + this->m_Position[0] = 0.0; + this->m_Position[1] = 0.0; + this->m_Position[2] = 0.0; + + this->m_Quaternion[0] = 0.0; + this->m_Quaternion[1] = 0.0; + this->m_Quaternion[2] = 0.0; + this->m_Quaternion[3] = 1.0; +} + +void PositionMessage::SetPackType(int t) +{ + if (t >= POSITION_ONLY && t <= ALL) + { + this->m_PackType = t; + } +} + +int PositionMessage::SetPackTypeByContentSize(int s) +{ + m_IsBodyPacked = false; + if (s == IGTL_POSITION_MESSAGE_POSITON_ONLY_SIZE) + { + this->m_PackType = POSITION_ONLY; + } + else if (s == IGTL_POSITION_MESSAGE_WITH_QUATERNION3_SIZE) + { + this->m_PackType = WITH_QUATERNION3; + } + else if (s == IGTL_POSITION_MESSAGE_DEFAULT_SIZE) + { + this->m_PackType = ALL; + } + else + { + // Do any error handling? + this->m_PackType = ALL; + return 0; + } + + return this->m_PackType; +} + +void PositionMessage::SetPosition(const float* pos) +{ + m_IsBodyPacked = false; + this->m_Position[0] = pos[0]; + this->m_Position[1] = pos[1]; + this->m_Position[2] = pos[2]; +} + +void PositionMessage::SetPosition(float x, float y, float z) +{ + m_IsBodyPacked = false; + this->m_Position[0] = x; + this->m_Position[1] = y; + this->m_Position[2] = z; +} + + +void PositionMessage::SetQuaternion(const float* quat) +{ + m_IsBodyPacked = false; + this->m_Quaternion[0] = quat[0]; + this->m_Quaternion[1] = quat[1]; + this->m_Quaternion[2] = quat[2]; + this->m_Quaternion[3] = quat[3]; +} + +void PositionMessage::SetQuaternion(float ox, float oy, float oz, float w) +{ + m_IsBodyPacked = false; + this->m_Quaternion[0] = ox; + this->m_Quaternion[1] = oy; + this->m_Quaternion[2] = oz; + this->m_Quaternion[3] = w; +} + +void PositionMessage::GetPosition(float* pos) +{ + pos[0] = this->m_Position[0]; + pos[1] = this->m_Position[1]; + pos[2] = this->m_Position[2]; +} + +void PositionMessage::GetPosition(float* x, float* y, float* z) +{ + *x = this->m_Position[0]; + *y = this->m_Position[1]; + *z = this->m_Position[2]; +} + +void PositionMessage::GetQuaternion(float* quat) +{ + quat[0] = this->m_Quaternion[0]; + quat[1] = this->m_Quaternion[1]; + quat[2] = this->m_Quaternion[2]; + quat[3] = this->m_Quaternion[3]; +} + +void PositionMessage::GetQuaternion(float* ox, float* oy, float* oz, float* w) +{ + *ox = this->m_Quaternion[0]; + *oy = this->m_Quaternion[1]; + *oz = this->m_Quaternion[2]; + *w = this->m_Quaternion[3]; +} + +igtlUint64 PositionMessage::CalculateContentBufferSize() +{ + igtlUint64 ret; + + switch (this->m_PackType) + { + case POSITION_ONLY: + ret = IGTL_POSITION_MESSAGE_POSITON_ONLY_SIZE; + break; + case WITH_QUATERNION3: + ret = IGTL_POSITION_MESSAGE_WITH_QUATERNION3_SIZE; + break; + default: + ret = IGTL_POSITION_MESSAGE_DEFAULT_SIZE; + break; + } + + return ret; +} + +int PositionMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + igtl_position* p = NULL; +#if OpenIGTLink_HEADER_VERSION >= 2 + p = (igtl_position*)(this->m_Content); +#elif OpenIGTLink_PROTOCOL_VERSION <=2 + p = (igtl_position*)(this->m_Body); +#endif + + p->position[0] = this->m_Position[0]; + p->position[1] = this->m_Position[1]; + p->position[2] = this->m_Position[2]; + + if (this->m_PackType == WITH_QUATERNION3) + { + p->quaternion[0] = this->m_Quaternion[0]; + p->quaternion[1] = this->m_Quaternion[1]; + p->quaternion[2] = this->m_Quaternion[2]; + } + else if (this->m_PackType == ALL) + { + p->quaternion[0] = this->m_Quaternion[0]; + p->quaternion[1] = this->m_Quaternion[1]; + p->quaternion[2] = this->m_Quaternion[2]; + p->quaternion[3] = this->m_Quaternion[3]; + } + + switch (this->m_PackType) + { + case POSITION_ONLY: + igtl_position_convert_byte_order_position_only(p); + break; + case WITH_QUATERNION3: + igtl_position_convert_byte_order_quaternion3(p); + break; + default: //IGTL_POSITION_MESSAGE_DEFAULT_SIZE + igtl_position_convert_byte_order(p); + break; + } + + return 1; +} + +int PositionMessage::UnpackContent() +{ + igtl_position* p = NULL; +#if OpenIGTLink_HEADER_VERSION >= 2 + p = (igtl_position*)(this->m_Content); +#elif OpenIGTLink_PROTOCOL_VERSION <=2 + p = (igtl_position*)(this->m_Body); +#endif + + bool isUnpacked(true); + igtl_uint64 contentSize = CalculateReceiveContentSize(isUnpacked); + if( !isUnpacked) + { + return 0; + } + switch (contentSize) + { + case IGTL_POSITION_MESSAGE_POSITON_ONLY_SIZE: + this->m_PackType = POSITION_ONLY; + igtl_position_convert_byte_order_position_only(p); + break; + case IGTL_POSITION_MESSAGE_WITH_QUATERNION3_SIZE: + this->m_PackType = WITH_QUATERNION3; + igtl_position_convert_byte_order_quaternion3(p); + break; + default: //IGTL_POSITION_MESSAGE_DEFAULT_SIZE + this->m_PackType = ALL; + igtl_position_convert_byte_order(p); + break; + } + + this->m_Position[0] = p->position[0]; + this->m_Position[1] = p->position[1]; + this->m_Position[2] = p->position[2]; + + if (this->m_PackType == POSITION_ONLY) + { + this->m_Quaternion[0] = 0.0; + this->m_Quaternion[1] = 0.0; + this->m_Quaternion[2] = 0.0; + this->m_Quaternion[3] = 1.0; + } + + if (this->m_PackType == WITH_QUATERNION3) + { + float ox = p->quaternion[0]; + float oy = p->quaternion[1]; + float oz = p->quaternion[2]; + float sq = 1.0 - (ox*ox + oy*oy + oz*oz); + if (sq < 0.0) + { + // TODO: what should we do with invalid quaternion? + // Tentatively we set (0, 0, 0, 1); + this->m_Quaternion[0] = 0.0; + this->m_Quaternion[1] = 0.0; + this->m_Quaternion[2] = 0.0; + this->m_Quaternion[3] = 1.0; + } + else + { + float w = sqrt(sq); + this->m_Quaternion[0] = ox; + this->m_Quaternion[1] = oy; + this->m_Quaternion[2] = oz; + this->m_Quaternion[3] = w; + } + } + else if (this->m_PackType == ALL) + { + this->m_Quaternion[0] = p->quaternion[0]; + this->m_Quaternion[1] = p->quaternion[1]; + this->m_Quaternion[2] = p->quaternion[2]; + this->m_Quaternion[3] = p->quaternion[3]; + } + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlPositionMessage.h b/openigtlink/repo/Source/igtlPositionMessage.h new file mode 100644 index 0000000..222b3b3 --- /dev/null +++ b/openigtlink/repo/Source/igtlPositionMessage.h @@ -0,0 +1,115 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlPositionMessage_h +#define __igtlPositionMessage_h + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +namespace igtl +{ + +/// The POSITION data type is used to transfer position and orientation information. +/// The data are a combination of 3-dimensional vector for the position and quaternion +/// for the orientation. Although equivalent position and orientation can be described +/// with the TRANSFORM data type, the POSITION data type has the advantage of smaller +/// data size (19%). It is therefore more suitable for pushing high frame-rate data +/// from tracking devices. +class IGTLCommon_EXPORT PositionMessage: public MessageBase +{ +public: + + /// Types of message formats. The format of the POSITION message type can contain + /// only a 3-element position vector (POSITION_ONLY), a combination of 3-element + /// position vector and 3-element quaternion (WITH_QUATERNION3), or a combination + /// of 3-element position vector and 4-element quaternion (ALL). + enum { + POSITION_ONLY = 1, + WITH_QUATERNION3, + ALL, + }; + +public: + igtlTypeMacro(igtl::PositionMessage, igtl::MessageBase); + igtlNewMacro(igtl::PositionMessage); + +public: + + /// Initializes the class. + void Init(); + + /// Sets the type of the pack. 't' must be either POSITION_ONLY, WITH_QUATERNION3, or ALL. + void SetPackType(int t); /* POSITION_ONLY / WITH_QUATERNION3 / ALL */ + + /// Gets the type of the pack. The returned value must be either POSITION_ONLY, WITH_QUATERNION3, or ALL. + int GetPackType() { return m_PackType; }; + + /// Specifies the pack type by body size (in most case obtained from general header). + int SetPackTypeByContentSize(int s); + + /// Sets the position by 3-element array of x, y, and z coordinates. + void SetPosition(const float* pos); + + /// Sets the position by x, y, and z coordinates. + void SetPosition(float x, float y, float z); + + /// Sets the quaternion by 4-element array. + void SetQuaternion(const float* quat); + + /// Sets the quaternion by elements of the quaternion (ox, oy, oz and w). + void SetQuaternion(float ox, float oy, float oz, float w); + + /// Gets the position. The function substitutes 3-element array of x, y and z coordinates in 'pos'. + void GetPosition(float* pos); + + /// Gets the position. The function substitutes the coordinates in 'x', 'y', and 'z'. + void GetPosition(float* x, float* y, float* z); + + /// Gets the quaternion. The function substitutes the array of elements of the quaternion in 'quat'. + void GetQuaternion(float* quat); + + /// Gets the quaternion. The function substitutes the elements of the quaternion in 'ox', 'oy', 'oz' and 'w'. + void GetQuaternion(float* ox, float* oy, float* oz, float* w); + +protected: + PositionMessage(); + ~PositionMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// The type of message formats (either POSITION_ONLY, WITH_QUATERNION3, or ALL). + igtlInt32 m_PackType; + + /// An array of x, y, and z coordinates for the position. + igtlFloat32 m_Position[3]; + + /// An array of ox, oy, oz, and w elements for the quaternion. + igtlFloat32 m_Quaternion[4]; + +}; + + +} // namespace igtl + +#endif // _igtlPositionMessage_h + + + diff --git a/openigtlink/repo/Source/igtlQuaternionTrackingDataMessage.cxx b/openigtlink/repo/Source/igtlQuaternionTrackingDataMessage.cxx new file mode 100644 index 0000000..d51b9e7 --- /dev/null +++ b/openigtlink/repo/Source/igtlQuaternionTrackingDataMessage.cxx @@ -0,0 +1,408 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlQuaternionTrackingDataMessage.h" +#include "igtlMath.h" + +#include "igtl_header.h" +#include "igtl_qtdata.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include +#include + +namespace igtl { + + +//---------------------------------------------------------------------- +// igtl::QuaternionTrackingDataElement class + +QuaternionTrackingDataElement::QuaternionTrackingDataElement() : Object() +{ + this->m_Name = ""; + this->m_Type = TYPE_TRACKER; + + this->m_position[0] = 0; + this->m_position[1] = 0; + this->m_position[2] = 0; + + this->m_quaternion[0] = 0; + this->m_quaternion[1] = 0; + this->m_quaternion[2] = 0; + this->m_quaternion[3] = 1; +} + + +QuaternionTrackingDataElement::~QuaternionTrackingDataElement() +{ +} + + +int QuaternionTrackingDataElement::SetName(const char* name) +{ + if (name != NULL && strlen(name) <= IGTL_QTDATA_LEN_NAME) + { + this->m_Name = name; + return 1; + } + else + { + return 0; + } +} + + +int QuaternionTrackingDataElement::SetType(igtlUint8 type) +{ + if(type == TYPE_TRACKER || + type == TYPE_6D || + type == TYPE_3D || + type == TYPE_5D) + { + this->m_Type = type; + return type; + } + else + { + return 0; + } +} + + +void QuaternionTrackingDataElement::SetPosition(float p[3]) +{ + this->m_position[0] = p[0]; + this->m_position[1] = p[1]; + this->m_position[2] = p[2]; +} + + +void QuaternionTrackingDataElement::GetPosition(float p[3]) +{ + p[0] = this->m_position[0]; + p[1] = this->m_position[1]; + p[2] = this->m_position[2]; +} + + +void QuaternionTrackingDataElement::SetPosition(float px, float py, float pz) +{ + this->m_position[0] = px; + this->m_position[1] = py; + this->m_position[2] = pz; +} + + +void QuaternionTrackingDataElement::GetPosition(float* px, float* py, float* pz) +{ + *px = this->m_position[0]; + *py = this->m_position[1]; + *pz = this->m_position[2]; +} + + +void QuaternionTrackingDataElement::SetQuaternion(float q[4]) +{ + this->m_quaternion[0] = q[0]; + this->m_quaternion[1] = q[1]; + this->m_quaternion[2] = q[2]; + this->m_quaternion[3] = q[3]; +} + + +void QuaternionTrackingDataElement::GetQuaternion(float q[4]) +{ + q[0] = this->m_quaternion[0]; + q[1] = this->m_quaternion[1]; + q[2] = this->m_quaternion[2]; + q[3] = this->m_quaternion[3]; +} + + +void QuaternionTrackingDataElement::SetQuaternion(float qx, float qy, float qz, float w) +{ + this->m_quaternion[0] = qx; + this->m_quaternion[1] = qy; + this->m_quaternion[2] = qz; + this->m_quaternion[3] = w; +} + + +void QuaternionTrackingDataElement::GetQuaternion(float* qx, float* qy, float* qz, float* w) +{ + *qx = this->m_quaternion[0]; + *qy = this->m_quaternion[1]; + *qz = this->m_quaternion[2]; + *w = this->m_quaternion[3]; +} + + +//---------------------------------------------------------------------- +// igtl::StartQuaternionTrackingDataMessage class + +StartQuaternionTrackingDataMessage::StartQuaternionTrackingDataMessage() +{ + this->m_SendMessageType = "STT_QTDATA"; + this->m_Resolution = 0; + this->m_CoordinateName = ""; +} + + +StartQuaternionTrackingDataMessage::~StartQuaternionTrackingDataMessage() +{ +} + + +int StartQuaternionTrackingDataMessage::SetCoordinateName(const char* name) +{ + if (name != NULL && strlen(name) <= IGTL_STT_QTDATA_LEN_COORDNAME) + { + this->m_CoordinateName = name; + return 1; + } + else + { + return 0; + } +} + + +igtlUint64 StartQuaternionTrackingDataMessage::CalculateContentBufferSize() +{ + return IGTL_STT_QTDATA_SIZE; +} + + +int StartQuaternionTrackingDataMessage::PackContent() +{ + AllocateBuffer(); + + igtl_stt_qtdata* stt_qtdata = (igtl_stt_qtdata*)this->m_Content; + + stt_qtdata->resolution = this->m_Resolution; + strncpy(stt_qtdata->coord_name, this->m_CoordinateName.c_str(), IGTL_STT_QTDATA_LEN_COORDNAME); + + igtl_stt_qtdata_convert_byte_order(stt_qtdata); + + return 1; + +} + + +int StartQuaternionTrackingDataMessage::UnpackContent() +{ + igtl_stt_qtdata* stt_qtdata = (igtl_stt_qtdata*)this->m_Content; + + igtl_stt_qtdata_convert_byte_order(stt_qtdata); + + this->m_Resolution = stt_qtdata->resolution; + + char strbuf[IGTL_STT_QTDATA_LEN_COORDNAME+1]; + strbuf[IGTL_STT_QTDATA_LEN_COORDNAME] = '\n'; + strncpy(strbuf, stt_qtdata->coord_name, IGTL_STT_QTDATA_LEN_COORDNAME); + + this->SetCoordinateName(strbuf); + + return 1; + +} + + +RTSQuaternionTrackingDataMessage::RTSQuaternionTrackingDataMessage() + : m_Status(0) +{ + this->m_SendMessageType = "RTS_QTDATA"; +} + +//---------------------------------------------------------------------- +// igtl::RTSQuaternionTrackingDataMessage class + +igtlUint64 RTSQuaternionTrackingDataMessage::CalculateContentBufferSize() +{ + return IGTL_RTS_QTDATA_SIZE; +} + +int RTSQuaternionTrackingDataMessage::PackContent() +{ + AllocateBuffer(); + + igtl_rts_qtdata* rts_qtdata = (igtl_rts_qtdata*)this->m_Content; + + rts_qtdata->status = this->m_Status; + + igtl_rts_qtdata_convert_byte_order(rts_qtdata); + + return 1; +} + + +int RTSQuaternionTrackingDataMessage::UnpackContent() +{ + igtl_rts_qtdata* rts_qtdata = (igtl_rts_qtdata*)this->m_Content; + + igtl_rts_qtdata_convert_byte_order(rts_qtdata); + + this->m_Status= rts_qtdata->status; + + return 1; +} + + + +//---------------------------------------------------------------------- +// igtl::QuaternionTrackingDataMessage class + +QuaternionTrackingDataMessage::QuaternionTrackingDataMessage() +{ + this->m_SendMessageType = "QTDATA"; + this->m_QuaternionTrackingDataList.clear(); +} + + +QuaternionTrackingDataMessage::~QuaternionTrackingDataMessage() +{ +} + + +int QuaternionTrackingDataMessage::AddQuaternionTrackingDataElement(QuaternionTrackingDataElement::Pointer& elem) +{ + this->m_QuaternionTrackingDataList.push_back(elem); + return this->m_QuaternionTrackingDataList.size(); +} + + +void QuaternionTrackingDataMessage::ClearQuaternionTrackingDataElements() +{ + this->m_QuaternionTrackingDataList.clear(); +} + + +int QuaternionTrackingDataMessage::GetNumberOfQuaternionTrackingDataElements() +{ + return this->m_QuaternionTrackingDataList.size(); +} + + +void QuaternionTrackingDataMessage::GetQuaternionTrackingDataElement(int index, QuaternionTrackingDataElement::Pointer& elem) +{ + if (index >= 0 && index < (int)this->m_QuaternionTrackingDataList.size()) + { + elem = this->m_QuaternionTrackingDataList[index]; + } +} + + +igtlUint64 QuaternionTrackingDataMessage::CalculateContentBufferSize() +{ + return IGTL_QTDATA_ELEMENT_SIZE * this->m_QuaternionTrackingDataList.size(); +} + + +int QuaternionTrackingDataMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + igtl_qtdata_element* element = NULL; + element = (igtl_qtdata_element*)(this->m_Content); + + igtl_qtdata_element * elementHolder = element; + std::vector::iterator iter; + for (iter = this->m_QuaternionTrackingDataList.begin(); iter != this->m_QuaternionTrackingDataList.end(); iter ++) + { + strncpy((char*)element->name, (*iter)->GetName(), IGTL_QTDATA_LEN_NAME); + element->type = (*iter)->GetType(); + element->reserved = 0; + float p[3]; + (*iter)->GetPosition(p); + float q[4]; + (*iter)->GetQuaternion(q); + + for (int i = 0; i < 3; i ++) + { + element->position[i] = p[i]; + } + for (int j = 0; j < 4; j ++) + { + element->quaternion[j] = q[j]; + } + + element ++; + } + + igtl_qtdata_convert_byte_order(elementHolder, this->m_QuaternionTrackingDataList.size()); + + return 1; +} + + +int QuaternionTrackingDataMessage::UnpackContent() +{ + this->m_QuaternionTrackingDataList.clear(); + + igtl_qtdata_element* element = NULL; + int nElement = 0; +#if OpenIGTLink_HEADER_VERSION >= 2 + element = (igtl_qtdata_element*) (this->m_Content); + bool isUnpacked(true); + nElement = igtl_qtdata_get_data_n(CalculateReceiveContentSize(isUnpacked)); +#elif OpenIGTLink_PROTOCOL_VERSION <=2 + element = (igtl_qtdata_element*) this->m_Body; + nElement = igtl_qtdata_get_data_n(this->m_BodySizeToRead); +#endif + igtl_qtdata_convert_byte_order(element, nElement); + + char strbuf[128]; + for (int i = 0; i < nElement; i ++) + { + QuaternionTrackingDataElement::Pointer elemClass = QuaternionTrackingDataElement::New(); + + // Add '\n' at the end of each string + // (necessary for a case, where a string reaches the maximum length.) + strbuf[IGTL_QTDATA_LEN_NAME] = '\n'; + strncpy(strbuf, (char*)element->name, IGTL_QTDATA_LEN_NAME); + elemClass->SetName((const char*)strbuf); + elemClass->SetType(element->type); + + float p[3] = {0, 0, 0}; + float q[4] = {0, 0, 0, 1}; + + for (int i = 0; i < 3; i ++) + { + p[i] = element->position[i]; + } + for (int j = 0; j < 4; j ++) + { + q[j] = element->quaternion[j]; + } + + elemClass->SetPosition(p); + elemClass->SetQuaternion(q); + + this->m_QuaternionTrackingDataList.push_back(elemClass); + + element ++; + } + + return 1; +} + +StopQuaternionTrackingDataMessage::StopQuaternionTrackingDataMessage() +{ + this->m_SendMessageType = "STP_QTDATA"; +} + +} // namespace igtl \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlQuaternionTrackingDataMessage.h b/openigtlink/repo/Source/igtlQuaternionTrackingDataMessage.h new file mode 100644 index 0000000..7273777 --- /dev/null +++ b/openigtlink/repo/Source/igtlQuaternionTrackingDataMessage.h @@ -0,0 +1,243 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlQuaternionTrackingDataMessage_h +#define __igtlQuaternionTrackingDataMessage_h + +#include +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + + +namespace igtl +{ + +/// A class to manage tracking data as a quaternion used in the QTDATA message type. +/// A QuaternionTrackingDataElement class instance holds tracking data for 1 tracking device. +class IGTLCommon_EXPORT QuaternionTrackingDataElement: public Object +{ +public: + igtlTypeMacro(igtl::QuaternionTrackingDataElement, igtl::Object); + igtlNewMacro(igtl::QuaternionTrackingDataElement); + + /// Tracking data type. + /// TYPE_TRACKER: Tracker + /// TYPE_6D: 6D instrument: (regular instrument) + /// TYPE_3D: 3D instrument (only tip of the instrument defined) + /// TYPE_5D: 5D instrument (tip and handle are defined, but not the normal vector) + enum { + TYPE_TRACKER = 1, + TYPE_6D = 2, + TYPE_3D = 3, + TYPE_5D = 4, + }; + +public: + + /// Sets the name of the instrument/tracker. + int SetName(const char* name); + + /// Gets the name of the instrument/tracker. + const char* GetName() { return this->m_Name.c_str(); }; + + /// Sets the type of the instrument/tracker. + int SetType(igtlUint8 type); + + /// Gets the type of the instrument/tracker. + igtlUint8 GetType() { return this->m_Type; }; + + /// Sets the position by 3-element array of x, y, and z coordinates. + void SetPosition(float p[3]); + + /// Gets the position. The function substitutes 3-element array of x, y and z coordinates in 'p'. + void GetPosition(float p[3]); + + /// Sets the position by x, y, and z coordinates. + void SetPosition(float px, float py, float pz); + + /// Gets the position. The function substitutes the xyz coordinates in 'px', 'py', and 'pz'. + void GetPosition(float* px, float* py, float* pz); + + /// Sets the quaternion by 4-element array. + void SetQuaternion(float q[4]); + + /// Gets the quaternion. The function substitutes the array of elements of the quaternion in 'q'. + void GetQuaternion(float q[4]); + + /// Sets the quaternion by elements of the quaternion (x, y, z and w). + void SetQuaternion(float qx, float qy, float qz, float w); + + /// Gets the quaternion. The function substitutes the elements of the quaternion in 'qx', 'qy', 'qz' and 'qw'. + void GetQuaternion(float* qx, float* qy, float* qz, float* w); + +protected: + QuaternionTrackingDataElement(); + ~QuaternionTrackingDataElement(); + +protected: + + /// Name / description (< 20 bytes) + std::string m_Name; + + /// Tracking data type (TYPE_TRACKER, TYPE_6D, TYPE_3D, TYPE_5D) + igtlUint8 m_Type; + + /// position (x, y, z) + igtlFloat32 m_position[3]; + + /// orientation as quaternion (qx, qy, qz, w) + igtlFloat32 m_quaternion[4]; +}; + +/// A class for the STT_QTDATA message type. +class IGTLCommon_EXPORT StartQuaternionTrackingDataMessage: public MessageBase +{ + +public: + igtlTypeMacro(igtl::StartQuaternionTrackingDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::StartQuaternionTrackingDataMessage); + +public: + + /// Sets the time resolution for streaming of QTDATA messages + void SetResolution(igtlInt32 res) { this->m_Resolution = res; }; // ms + + /// Gets the time resolution for streaming of QTDATA messages + igtlInt32 GetResolution() { return this->m_Resolution; }; + + /// Sets the name of the coordinate system. The name must be defined by the user. + int SetCoordinateName(const char* name); + + /// Gets the name of the coordinate system. + const char* GetCoordinateName() { return this->m_CoordinateName.c_str(); }; + +protected: + StartQuaternionTrackingDataMessage(); + ~StartQuaternionTrackingDataMessage(); + +protected: + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + +protected: + + /// Minimum time between two frames (ms). Use 0 for as fast as possible. + igtlInt32 m_Resolution; + + /// Name of the coordinate system + std::string m_CoordinateName; + +}; + + +class IGTLCommon_EXPORT StopQuaternionTrackingDataMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::StopQuaternionTrackingDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::StopQuaternionTrackingDataMessage); + +protected: + StopQuaternionTrackingDataMessage(); + ~StopQuaternionTrackingDataMessage() {}; + +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; + +}; + + +/// A class for the RTS_QTDATA message type. +class IGTLCommon_EXPORT RTSQuaternionTrackingDataMessage: public MessageBase +{ +public: + /// Status types + enum { + STATUS_SUCCESS = 0, + STATUS_ERROR = 1 + }; + + igtlTypeMacro(igtl::RTSQuaternionTrackingDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::RTSQuaternionTrackingDataMessage); + + /// Sets the status. 'status' must be either STATUS_SUCCESS or STATUS_ERROR. + void SetStatus(igtlUint8 status){ this->m_Status = status; } + + /// Gets the status. The function returns either STATUS_SUCCESS or STATUS_ERROR. + igtlUint8 GetStatus() { return this->m_Status; }; + +protected: + RTSQuaternionTrackingDataMessage(); + ~RTSQuaternionTrackingDataMessage() {}; + + /// A variable to store the status. + igtlUint8 m_Status; + +protected: + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + +}; + + +/// The QTDATA message type is intended for transferring 3D positions of surgical tools, +/// markers etc. Its role is almost identical to TDATA, except that QTDATA describes +/// orientation by using quaternion. +class IGTLCommon_EXPORT QuaternionTrackingDataMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::QuaternionTrackingDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::QuaternionTrackingDataMessage); + +public: + + /// Adds tracking data element. + int AddQuaternionTrackingDataElement(QuaternionTrackingDataElement::Pointer& elem); + + /// Clears the all tracking data element in the list. + void ClearQuaternionTrackingDataElements(); + + /// Gets the number of tracking data elements in the list. + int GetNumberOfQuaternionTrackingDataElements(); + + /// Gets the tracking data element specified by 'index'. + void GetQuaternionTrackingDataElement(int index, QuaternionTrackingDataElement::Pointer& elem); + + +protected: + QuaternionTrackingDataMessage(); + ~QuaternionTrackingDataMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// The list of tracking data elements. + std::vector m_QuaternionTrackingDataList; + +}; + + +} // namespace igtl + +#endif // _igtlQuaternionTrackingDataMessage_h diff --git a/openigtlink/repo/Source/igtlQueryMessage.cxx b/openigtlink/repo/Source/igtlQueryMessage.cxx new file mode 100644 index 0000000..49fe974 --- /dev/null +++ b/openigtlink/repo/Source/igtlQueryMessage.cxx @@ -0,0 +1,143 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlQueryMessage.h" + +#include "igtl_header.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include + +namespace igtl { + +QueryMessage::QueryMessage() +{ + this->m_SendMessageType = "QUERY"; +} + +QueryMessage::~QueryMessage() +{ +} + + +int QueryMessage::SetDeviceUID(const char* string) +{ + if (string == NULL || strlen(string) > 0xFFFF) /* If the length is beyond the range of unsigned short */ + { + return 0; + } + m_DeviceUID = string; + return (int) this->m_DeviceUID.length(); +} + + +int QueryMessage::SetDeviceUID(const std::string & string) +{ + if (string.length() > 0xFFFF) /* If the length is beyond the range of unsigned short */ + { + return 0; + } + this->m_DeviceUID = string; + return (int) this->m_DeviceUID.length(); +} + + +std::string QueryMessage::GetDeviceUID() +{ + return this->m_DeviceUID; +} + + + +int QueryMessage::SetDataType(const char* dataType) +{ + if (dataType == NULL || strlen(dataType) > IGTL_QUERY_DATE_TYPE_SIZE) /* If the length is beyond the range specified by the spec */ + { + return 0; + } + strcpy((char*)m_DataType, dataType); + return 1; +} + + +int QueryMessage::SetDataType(const std::string& dataType) +{ + return this->SetDataType(dataType.c_str()); +} + + + +igtlUint64 QueryMessage::CalculateContentBufferSize() +{ + // Body pack size is the sum of DeviceUID and data type fields + return IGTL_QUERY_HEADER_SIZE + this->m_DeviceUID.length(); +} + + +int QueryMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + igtl_query_header * query_header; + char * deviceName; + + // Set pointers +#if OpenIGTLink_HEADER_VERSION >= 2 + query_header = (igtl_query_header*) this->m_Content; + deviceName = (char *) this->m_Content + sizeof(igtl_query_header); +#else + query_header = (igtl_query_header*) this->m_Body; + deviceName = (char *) this->m_Body + sizeof(igtl_query_header); +#endif + + // Copy data + query_header->deviceUIDLength = static_cast(this->m_DeviceUID.length()); + query_header->queryID = this->m_QueryID; + memcpy(query_header->queryDataType, this->m_DataType, IGTL_QUERY_DATE_TYPE_SIZE); + strncpy(deviceName, this->m_DeviceUID.c_str(), query_header->deviceUIDLength); + + // Convert byte order from host to network + igtl_query_convert_byte_order(query_header); + + return 1; +} + +int QueryMessage::UnpackContent() +{ + igtl_query_header * query_header; + char * deviceName; + +#if OpenIGTLink_HEADER_VERSION >= 2 + query_header = (igtl_query_header*) this->m_Content; + deviceName = (char *) this->m_Content + sizeof(igtl_query_header); +#else + query_header = (igtl_query_header*) this->m_Body; + deviceName = (char *) this->m_Body + sizeof(igtl_query_header); +#endif + + // Convert byte order from network to host + igtl_query_convert_byte_order(query_header); + + // Copy data + this->m_QueryID = query_header->queryID; + memcpy(m_DataType, query_header->queryDataType, IGTL_QUERY_DATE_TYPE_SIZE); + this->m_DeviceUID.clear(); + this->m_DeviceUID.append(deviceName, query_header->deviceUIDLength); + + return 1; +} + +} // namespace igtl \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlQueryMessage.h b/openigtlink/repo/Source/igtlQueryMessage.h new file mode 100644 index 0000000..9980604 --- /dev/null +++ b/openigtlink/repo/Source/igtlQueryMessage.h @@ -0,0 +1,81 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlQueryMessage_h +#define __igtlQueryMessage_h + +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" +#include "igtl_query.h" + +namespace igtl +{ + +/// THe STRING message type is used for transferring a character string. It supports character strings up to 65535 bytes. +class IGTLCommon_EXPORT QueryMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::QueryMessage, igtl::MessageBase); + igtlNewMacro(igtl::QueryMessage); + +public: + + /// Sets the string by character array. + int SetDeviceUID(const char* string); + + /// Sets the string by std::string. + int SetDeviceUID(const std::string & string); + + /// Sets the string by character array. + int SetDataType(const char* string); + + /// Sets the string by std::string. + int SetDataType(const std::string & string); + + /// Gets the device uid. + std::string GetDeviceUID(); + + /// Gets the data type. + std::string GetDataType(); + +protected: + QueryMessage(); + ~QueryMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// The string. + std::string m_DeviceUID; + + igtlUint32 m_QueryID; + + /// Query Data Type + igtlUint8 m_DataType[IGTL_QUERY_DATE_TYPE_SIZE ]; +}; + + +} // namespace igtl + +#endif // _igtlQueryMessage_h + + + diff --git a/openigtlink/repo/Source/igtlSensorMessage.cxx b/openigtlink/repo/Source/igtlSensorMessage.cxx new file mode 100644 index 0000000..c7ff1c0 --- /dev/null +++ b/openigtlink/repo/Source/igtlSensorMessage.cxx @@ -0,0 +1,189 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlSensorMessage.h" + +#include "igtl_header.h" +#include "igtl_sensor.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include + +namespace igtl { + +SensorMessage::SensorMessage(): + MessageBase() +{ + m_SendMessageType = "SENSOR"; + + this->m_Length = 0; + this->m_Status = 0; + this->m_Unit = 0; + this->m_Array.clear(); +} + + +SensorMessage::~SensorMessage() +{ +} + + +int SensorMessage::SetLength(unsigned int n) +{ + if (n <= 256) + { + this->m_Length = n; + this->m_Array.resize(n); + } + + return (int) this->m_Length; +} + + +unsigned int SensorMessage::GetLength() +{ + return this->m_Length; +} + + +int SensorMessage::SetUnit(igtlUnit unit) +{ + this->m_Unit = unit; + return 1; +} + + +int SensorMessage::SetUnit(igtl::Unit * unit) +{ + this->m_Unit = unit->Pack(); + + return 1; +} + + +igtlUnit SensorMessage::GetUnit() +{ + return this->m_Unit; +} + + +int SensorMessage::GetUnit(igtl::Unit * unit) +{ + return unit->Unpack(this->m_Unit); +} + + +int SensorMessage::SetValue(igtlFloat64 * data) +{ + for (int i = 0; i < this->m_Length; i ++) + { + this->m_Array[i] = data[i]; + } + + return 1; +} + + +int SensorMessage::SetValue(unsigned int i, igtlFloat64 value) +{ + if (i < this->m_Length) + { + this->m_Array[i] = value; + return 1; + } + + return 0; +} + + +igtlFloat64 SensorMessage::GetValue(unsigned int i) +{ + if (i < this->m_Length) + { + return this->m_Array[i]; + } + else + { + return 0.0; + } +} + + +igtlUint64 SensorMessage::CalculateContentBufferSize() +{ + // Body pack size is the sum of LARRAY, STATUS, UNIT and DATA + return sizeof(igtlUint8)*2 + sizeof(igtlUnit) + sizeof(igtlFloat64)*this->m_Length; +} + + +int SensorMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + // Set pointers + igtl_sensor_header * sensor_header; + igtl_float64 * data; + sensor_header = (igtl_sensor_header *) (this->m_Content); + data = (igtl_float64 *) (this->m_Content + sizeof(igtl_sensor_header)); + + // Copy data + sensor_header->larray = this->m_Length; + sensor_header->status = this->m_Status; + sensor_header->unit = this->m_Unit; + + for (int i = 0; i < this->m_Length; i ++) + { + data[i] = this->m_Array[i]; + } + + // Convert byte order from local to network + igtl_sensor_convert_byte_order(sensor_header, data); + + return 1; +} + +int SensorMessage::UnpackContent() +{ + // Set pointers + igtl_sensor_header * sensor_header; + igtl_float64 * data; + sensor_header = (igtl_sensor_header *) (this->m_Content); + data = (igtl_float64 *) (this->m_Content + sizeof(igtl_sensor_header)); + + // Convert byte order from local to network + igtl_sensor_convert_byte_order(sensor_header, data); + + // Copy data + this->m_Length = sensor_header->larray; + this->m_Status = sensor_header->status; + this->m_Unit = sensor_header->unit; + + this->m_Array.resize(this->m_Length); + for (int i = 0; i < this->m_Length; i ++) + { + this->m_Array[i] = data[i]; + } + + return 1; +} + +} // namespace igtl + + + + + diff --git a/openigtlink/repo/Source/igtlSensorMessage.h b/openigtlink/repo/Source/igtlSensorMessage.h new file mode 100644 index 0000000..dac0d9e --- /dev/null +++ b/openigtlink/repo/Source/igtlSensorMessage.h @@ -0,0 +1,96 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlSensorMessage_h +#define __igtlSensorMessage_h + +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +#include "igtlUnit.h" + +namespace igtl +{ + +/// SENSOR is a message type, which is used to transfer sensor reading, +/// 3-axis position, velocity, acceleration, angle, angle velocity and angle acceleration. +/// The message format is intended for manipulator control and various types of sensors. +class IGTLCommon_EXPORT SensorMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::SensorMessage, igtl::MessageBase); + igtlNewMacro(igtl::SensorMessage); + +public: + + /// Sets the length of the array. Returns the resulted length. + int SetLength(unsigned int n); + + /// Gets the length of the array. + unsigned int GetLength(); + + /// Sets the unit for the sensor values. Returns 1 if success. + int SetUnit(igtlUnit unit); + + /// Sets the unit for the sensor values Returns 1 if success. + int SetUnit(igtl::Unit * unit); + + /// Gets the unit as 64-bit unit field defined in igtlUnit.h. + igtlUnit GetUnit(); + + /// Gets the unit as igtl::Unit class. + int GetUnit(igtl::Unit * unit); + + /// Sets sensor values from an array of 64-bit floating data. Returns 1 if success. + int SetValue(igtlFloat64 * data); + + /// Sets the value for the i-th sensor. Returns 1 if success. + int SetValue(unsigned int i, igtlFloat64 value); + + /// Gets the value of the i-th sensor. + igtlFloat64 GetValue(unsigned int i); + +protected: + SensorMessage(); + ~SensorMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// Length of sensor array. + igtlUint8 m_Length; + + /// Sensor status (Reserved). + igtlUint8 m_Status; + + /// Unit (generated by igtl::Unit::Pack()). + igtlUnit m_Unit; + + /// The array of sensor values. + std::vector m_Array; +}; + + +} // namespace igtl + +#endif // _igtlSensorMessage_h + + diff --git a/openigtlink/repo/Source/igtlServerSocket.cxx b/openigtlink/repo/Source/igtlServerSocket.cxx new file mode 100644 index 0000000..8cf7043 --- /dev/null +++ b/openigtlink/repo/Source/igtlServerSocket.cxx @@ -0,0 +1,120 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkServerSocket.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "igtlServerSocket.h" +#include "igtlClientSocket.h" + +namespace igtl +{ + +//----------------------------------------------------------------------------- +ServerSocket::ServerSocket() +{ +} + +//----------------------------------------------------------------------------- +ServerSocket::~ServerSocket() +{ +} + +//----------------------------------------------------------------------------- +int ServerSocket::GetServerPort() +{ + if (!this->GetConnected()) + { + return 0; + } + return this->GetPort(this->m_SocketDescriptor); +} + +//----------------------------------------------------------------------------- +int ServerSocket::CreateServer(int port) +{ + if (this->m_SocketDescriptor != -1) + { + igtlWarningMacro("Server Socket already exists. Closing old socket."); + this->CloseSocket(this->m_SocketDescriptor); + this->m_SocketDescriptor = -1; + } + this->m_SocketDescriptor = this->CreateSocket(); + if (this->m_SocketDescriptor < 0) + { + return -1; + } + if ( this->BindSocket(this->m_SocketDescriptor, port) != 0|| + this->Listen(this->m_SocketDescriptor) != 0) + { + // failed to bind or listen. + this->CloseSocket(this->m_SocketDescriptor); + this->m_SocketDescriptor = -1; + return -1; + } + // Success. + return 0; +} + +//----------------------------------------------------------------------------- +//ClientSocket* ServerSocket::WaitForConnection(unsigned long msec /*=0*/) +ClientSocket::Pointer ServerSocket::WaitForConnection(unsigned long msec /*=0*/) +{ + if (this->m_SocketDescriptor < 0) + { + igtlErrorMacro("Server Socket not created yet!"); + return NULL; + } + + int ret = this->SelectSocket(this->m_SocketDescriptor, msec); + if (ret == 0) + { + // Timed out. + return NULL; + } + if (ret == -1) + { + igtlErrorMacro("Error selecting socket."); + return NULL; + } + int clientsock = this->Accept(this->m_SocketDescriptor); + if (clientsock == -1) + { + igtlErrorMacro("Failed to accept the socket."); + return NULL; + } + // Create a new ClientSocket and return it. + ClientSocket::Pointer cs = ClientSocket::New(); + cs->m_SocketDescriptor = clientsock; + return cs; +} + +//----------------------------------------------------------------------------- +void ServerSocket::PrintSelf(std::ostream& os) const +{ + this->Superclass::PrintSelf(os); +} + + +} // end of igtl namespace diff --git a/openigtlink/repo/Source/igtlServerSocket.h b/openigtlink/repo/Source/igtlServerSocket.h new file mode 100644 index 0000000..2fc4fd4 --- /dev/null +++ b/openigtlink/repo/Source/igtlServerSocket.h @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkServerSocket.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME igtlServerSocket - Encapsulate a socket that accepts connections. +// .SECTION Description +// + +#ifndef __igtlServerSocket_h +#define __igtlServerSocket_h + +#include "igtlSocket.h" +#include "igtlClientSocket.h" +#include "igtlWin32Header.h" + +namespace igtl +{ + +class IGTLCommon_EXPORT ServerSocket : public Socket +{ +public: + igtlTypeMacro(igtl::ServerSocket, igtl::Socket); + igtlNewMacro(igtl::ServerSocket); + + // Description: + // Creates a server socket at a given port and binds to it. + // Returns -1 on error. 0 on success. + int CreateServer(int port); + + // Description: + // Waits for a connection. When a connection is received + // a new ClientSocket object is created and returned. + // Returns NULL on timeout. + //ClientSocket* WaitForConnection(unsigned long msec=0); + ClientSocket::Pointer WaitForConnection(unsigned long msec=0); + + // Description: + // Returns the port on which the server is running. + int GetServerPort(); +protected: + ServerSocket(); + ~ServerSocket(); + + void PrintSelf(std::ostream& os) const override; + +private: + ServerSocket(const ServerSocket&); // Not implemented. + void operator=(const ServerSocket&); // Not implemented. +}; + +} // end of igtl namespace + + +#endif + diff --git a/openigtlink/repo/Source/igtlSessionManager.cxx b/openigtlink/repo/Source/igtlSessionManager.cxx new file mode 100644 index 0000000..ea67044 --- /dev/null +++ b/openigtlink/repo/Source/igtlSessionManager.cxx @@ -0,0 +1,321 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: git@github.com:openigtlink/OpenIGTLink.git + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include +#include +#include + +#include "igtlSessionManager.h" +#include "igtlMessageHandler.h" +#include "igtlClientSocket.h" +#include "igtlServerSocket.h" + +#include "igtl_header.h" + +namespace igtl +{ + + +SessionManager::SessionManager() +{ + this->m_MessageHandlerList.clear(); + this->m_Mode = MODE_SERVER; + + this->m_Header = igtl::MessageHeader::New(); + this->m_TimeStamp = igtl::TimeStamp::New(); + + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; +} + + +SessionManager::~SessionManager() +{ +} + + +int SessionManager::AddMessageHandler(MessageHandler* handler) +{ + // Check if there is any handler for the same message type + std::vector< MessageHandler* >::iterator iter; + for (iter = this->m_MessageHandlerList.begin(); iter != this->m_MessageHandlerList.end(); iter ++) + { + if ( (*iter)->GetMessageType() == handler->GetMessageType() ) + { + return 0; + } + } + + // If not, add the handler to the list. + this->m_MessageHandlerList.push_back(handler); + + return 1; +} + + +int SessionManager::RemoveMessageHandler(MessageHandler* handler) +{ + // Check if there is any handler for the same message type + std::vector< MessageHandler* >::iterator iter; + for (iter = this->m_MessageHandlerList.begin(); iter != this->m_MessageHandlerList.end(); iter ++) + { + if (*iter == handler) + { + this->m_MessageHandlerList.erase(iter); + return 1; + } + } + return 0; +} + + +int SessionManager::Connect() +{ + + this->m_Socket = NULL; + + if (this->m_Mode == MODE_CLIENT) + { + ClientSocket::Pointer clientSocket; + clientSocket = ClientSocket::New(); + //this->DebugOff(); + if (this->m_Hostname.length() == 0) + { + return 0; + } + //this->m_Socket->SetConnectTimeout(1000); + int r = clientSocket->ConnectToServer(this->m_Hostname.c_str(), this->m_Port); + if (r == 0) // if connected to server + { + //clientSocket->SetReceiveTimeout(0); + this->m_Socket = clientSocket; + } + else + { + return 0; + } + } + else + { + ServerSocket::Pointer serverSocket; + serverSocket = ServerSocket::New(); + int r = serverSocket->CreateServer(this->m_Port); + if (r < 0) + { + return 0; + } + + if (serverSocket.IsNotNull()) + { + //this->ServerSocket->CreateServer(this->m_Port); + this->m_Socket = serverSocket->WaitForConnection(10000); + } + + if (this->m_Socket.IsNotNull() && this->m_Socket->GetConnected()) // if client connected + { + this->m_Socket->DebugOff(); + } + else + { + return 0; + } + } + + this->m_Socket->SetReceiveBlocking(0); // Pseudo non-blocking + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; + return 1; +} + + +int SessionManager::Disconnect() +{ + if (this->m_Socket.IsNotNull()) + { + this->m_Socket->CloseSocket(); + } + + return 0; +} + +int SessionManager::ProcessMessage() +{ + // The workflow of this function is as follows: + // + // HEADER: + // IF the message is (a) a new message: + // start reading the header; + // ELSE IF the message is a message in progress: + // if the process is reading the header: + // continue to read the header; + // ELSE: + // GOTO BODY; + // + // IF the header has not been received: + // GOTO BODY; + // ELSE + // RETURN; + // + // BODY: + // IF the process has not started reading the body: + // check the body type; + // find an appropriate handler; + // start reading the body + // ELSE: + // continue to read the body + // + + //-------------------------------------------------- + // Header + if (this->m_CurrentReadIndex == 0) + { + // Initialize receive buffer + this->m_Header->InitBuffer(); + + // Receive generic header from the socket + bool timeout(false); + igtl_uint64 r = this->m_Socket->Receive(this->m_Header->GetBufferPointer(), this->m_Header->GetBufferSize(), timeout, 0); + if (r == 0) + { + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; + return 0; // Disconnected + } + if (r != this->m_Header->GetBufferSize()) + { + // Only a part of header has arrived. + if (timeout) // timeout + { + this->m_CurrentReadIndex = 0; + } + else + { + this->m_CurrentReadIndex = r; + } + return -1; + } + // The header has been received. + this->m_CurrentReadIndex = IGTL_HEADER_SIZE; + } + else if (this->m_CurrentReadIndex < IGTL_HEADER_SIZE) + { + // Message transfer was interrupted in the header + bool timeout(false); + igtl_uint64 r = this->m_Socket->Receive((void*)((char*)this->m_Header->GetBufferPointer()+this->m_CurrentReadIndex), + this->m_Header->GetBufferSize()-this->m_CurrentReadIndex, timeout, 0); + if (r == 0) + { + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; + return 0; // Disconnected + } + if (r != this->m_Header->GetBufferSize()-this->m_CurrentReadIndex) + { + // Only a part of header has arrived. + if (r > 0) // exclude a case of timeout + { + this->m_CurrentReadIndex += r; + } + return -1; + } + // The header has been received. + this->m_CurrentReadIndex = IGTL_HEADER_SIZE; + } + + + //-------------------------------------------------- + // Body + if (this->m_HeaderDeserialized == 0) + { + // Deserialize the header + this->m_Header->Unpack(); + + // Get time stamp + igtlUint32 sec; + igtlUint32 nanosec; + + this->m_Header->GetTimeStamp(this->m_TimeStamp); + this->m_TimeStamp->GetTimeStamp(&sec, &nanosec); + //std::cerr << "Time stamp: " + // << sec << "." << std::setw(9) << std::setfill('0') + // << nanosec << std::endl; + + // Look for a message handler that matches to the message type. + int found = 0; + std::vector< MessageHandler* >::iterator iter; + for (iter = this->m_MessageHandlerList.begin(); iter != this->m_MessageHandlerList.end(); iter ++) + { +#if OpenIGTLink_HEADER_VERSION >= 2 + if ( this->m_Header->GetMessageType() == (*iter)->GetMessageType() ) +#else + if (strcmp(this->m_Header->GetDeviceType(), (*iter)->GetMessageType()) == 0) +#endif + { + this->m_CurrentMessageHandler = *iter; + found = 1; + break; + } + } + + // If there is no message handler, skip the message + if (!found) + { +#if OpenIGTLink_HEADER_VERSION >= 2 + std::cerr << "Receiving: " << this->m_Header->GetMessageType() << std::endl; +#else + std::cerr << "Receiving: " << this->m_Header->GetDeviceType() << std::endl; +#endif + this->m_Socket->Skip(this->m_Header->GetBodySizeToRead(), 0); + // Reset the index counter to be ready for the next message + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; + return 1; + } + + this->m_HeaderDeserialized = 1; + } + + igtl_uint64 r = this->m_CurrentMessageHandler->ReceiveMessage(this->m_Socket, this->m_Header, + this->m_CurrentReadIndex-IGTL_HEADER_SIZE); + if (r == this->m_Header->GetBodySizeToRead()) + { + this->m_CurrentReadIndex = 0; + this->m_HeaderDeserialized = 0; + } + else + { + this->m_CurrentReadIndex += IGTL_HEADER_SIZE + r; + } + + return 1; +} + + +int SessionManager::PushMessage(MessageBase* message) +{ + + if (message && this->m_Socket.IsNotNull() && this->m_Socket->GetConnected()) // if client connected + { + return this->m_Socket->Send(message->GetBufferPointer(), message->GetBufferSize()); + } + else + { + return 0; + } +} + + +} diff --git a/openigtlink/repo/Source/igtlSessionManager.h b/openigtlink/repo/Source/igtlSessionManager.h new file mode 100644 index 0000000..0d3568a --- /dev/null +++ b/openigtlink/repo/Source/igtlSessionManager.h @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: git@github.com:openigtlink/OpenIGTLink.git + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlSessionManager_h +#define __igtlSessionManager_h + +#include "igtlObject.h" +#include "igtlMacro.h" +#include "igtlMessageHandler.h" + + +#include + +namespace igtl +{ + +class IGTLCommon_EXPORT SessionManager: public Object +{ + public: + igtlTypeMacro(SessionManager, Object) + igtlNewMacro(SessionManager); + + public: + enum { + MODE_SERVER, + MODE_CLIENT + }; + + void SetHostname(const char * str) {this->m_Hostname = str; this->m_ConfigurationUpdated = true; } + const char * GetHostname() { return this->m_Hostname.c_str(); } + void SetPort(int p) { this->m_Port = p; this->m_ConfigurationUpdated = true; } + int GetPort() { return this->m_Port; } + + // Description: + // Set the role of session manager. Either MODE_SERVER or MODE_CLIENT + void SetMode(int m) {this->m_Mode = m; this->m_ConfigurationUpdated = true; } + int GetMode() {return this->m_Mode; } + + // Description: + // Register / Unregister a message handler + int AddMessageHandler(MessageHandler*); + int RemoveMessageHandler(MessageHandler*); + + // Description: + // Functions to manage the session + int Connect(); + int Disconnect(); + int ProcessMessage(); + int PushMessage(MessageBase*); + + protected: + SessionManager(); + ~SessionManager(); + + protected: + bool m_ConfigurationUpdated; + std::string m_Hostname; + int m_Port; + int m_Mode; + + // Description: + // m_CurrentReadIndex is used to save the current position of the message. + // The index becomes >0 when message transfer is interrupted and only a part + // of message has arrived. + int m_CurrentReadIndex; + int m_HeaderDeserialized; + + MessageHandler* m_CurrentMessageHandler; + + std::vector< MessageHandler* > m_MessageHandlerList; + Socket::Pointer m_Socket; + + igtl::MessageHeader::Pointer m_Header; + igtl::TimeStamp::Pointer m_TimeStamp; + +}; + +} +#endif // __igtlSessionManager_h diff --git a/openigtlink/repo/Source/igtlSimpleFastMutexLock.cxx b/openigtlink/repo/Source/igtlSimpleFastMutexLock.cxx new file mode 100644 index 0000000..cb34b4e --- /dev/null +++ b/openigtlink/repo/Source/igtlSimpleFastMutexLock.cxx @@ -0,0 +1,107 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkSimpleFastMutexLock.cxx,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "igtlSimpleFastMutexLock.h" + +namespace igtl +{ + +// Construct a new SimpleMutexLock +SimpleFastMutexLock::SimpleFastMutexLock() +{ +#ifdef OpenIGTLink_USE_SPROC + init_lock( &m_FastMutexLock ); +#endif + +#if defined(_WIN32) && !defined(OpenIGTLink_USE_PTHREADS) + //this->MutexLock = CreateMutex( NULL, FALSE, NULL ); + InitializeCriticalSection(&m_FastMutexLock); +#endif + +#ifdef OpenIGTLink_USE_PTHREADS +#ifdef OpenIGTLink_HP_PTHREADS + pthread_mutex_init(&(m_FastMutexLock), pthread_mutexattr_default); +#else + pthread_mutex_init(&(m_FastMutexLock), NULL); +#endif +#endif + +} + +// Destruct the SimpleMutexVariable +SimpleFastMutexLock::~SimpleFastMutexLock() +{ +#if defined(_WIN32) && !defined(OpenIGTLink_USE_PTHREADS) + //CloseHandle(this->MutexLock); + DeleteCriticalSection(&m_FastMutexLock); +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + pthread_mutex_destroy( &m_FastMutexLock); +#endif +} + +// Lock the FastMutexLock +void SimpleFastMutexLock::Lock() const +{ +#ifdef OpenIGTLink_USE_SPROC + spin_lock( &m_FastMutexLock ); +#endif + +#if defined(_WIN32) && !defined(OpenIGTLink_USE_PTHREADS) + //WaitForSingleObject( this->MutexLock, INFINITE ); + EnterCriticalSection(&m_FastMutexLock); +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + pthread_mutex_lock( &m_FastMutexLock); +#endif +} + +// Unlock the FastMutexLock +void SimpleFastMutexLock::Unlock() const +{ +#ifdef OpenIGTLink_USE_SPROC + release_lock( &m_FastMutexLock ); +#endif + +#if defined(_WIN32) && !defined(OpenIGTLink_USE_PTHREADS) + //ReleaseMutex( this->MutexLock ); + LeaveCriticalSection(&m_FastMutexLock); +#endif + +#ifdef OpenIGTLink_USE_PTHREADS + pthread_mutex_unlock( &m_FastMutexLock); +#endif +} + +}//end namespace igtl diff --git a/openigtlink/repo/Source/igtlSimpleFastMutexLock.h b/openigtlink/repo/Source/igtlSimpleFastMutexLock.h new file mode 100644 index 0000000..51f5bbf --- /dev/null +++ b/openigtlink/repo/Source/igtlSimpleFastMutexLock.h @@ -0,0 +1,109 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkSimpleFastMutexLock.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlSimpleFastMutexLock_h +#define __igtlSimpleFastMutexLock_h + +#include "igtlMacro.h" + +#ifdef OpenIGTLink_USE_SPROC +#include +#endif + +#ifdef OpenIGTLink_USE_PTHREADS +#include +#endif + +#if defined(_WIN32) && !defined(OpenIGTLink_USE_PTHREADS) +#include "igtlWindows.h" +#endif + +namespace igtl +{ + +#ifdef OpenIGTLink_USE_SPROC +#include +typedef abilock_t FastMutexType; +#endif + +#ifdef OpenIGTLink_USE_PTHREADS +#include +typedef pthread_mutex_t FastMutexType; +#endif + +#if defined(_WIN32) && !defined(OpenIGTLink_USE_PTHREADS) +#include +typedef CRITICAL_SECTION FastMutexType; +#endif + +#ifndef OpenIGTLink_USE_SPROC +#ifndef OpenIGTLink_USE_PTHREADS +#ifndef _WIN32 +typedef int FastMutexType; +#endif +#endif +#endif + +/** \class SimpleFastMutexLock + * \brief Critical section locking class that can be allocated on the stack. + * + * SimpleFastMutexLock is used by FastMutexLock to perform mutex locking. + * SimpleFastMutexLock is not a subclass of Object and is designed to be + * allocated on the stack. + * + * \ingroup OSSystemObjects + */ + +// Critical Section object that is not a igtlObject. +class IGTLCommon_EXPORT SimpleFastMutexLock +{ +public: + /** Standard class typedefs. */ + typedef SimpleFastMutexLock Self; + + /** Constructor and destructor left public purposely because of stack allocation. */ + SimpleFastMutexLock(); + ~SimpleFastMutexLock(); + + /** Lock access. */ + void Lock() const; + + /** Unlock access. */ + void Unlock() const; + +protected: + mutable FastMutexType m_FastMutexLock; +}; + +}//end igtl namespace +#endif + diff --git a/openigtlink/repo/Source/igtlSmartPointer.h b/openigtlink/repo/Source/igtlSmartPointer.h new file mode 100644 index 0000000..bd3f29a --- /dev/null +++ b/openigtlink/repo/Source/igtlSmartPointer.h @@ -0,0 +1,175 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkSmartPointer.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlSmartPointer_h +#define __igtlSmartPointer_h + +#include "igtlMacro.h" +#include + +namespace igtl +{ + +/** \class SmartPointer + * \brief Implements transparent reference counting. + * + * SmartPointer implements reference counting by overloading + * operator -> (and *) among others. This allows natural interface + * to the class referred to by the pointer without having to invoke + * special Register()/UnRegister() methods directly. + * + * To compile / test this class + * Windows: cl SmartPointerTest.cxx; .\SmartPointerTest.exe + * linux: c++ SmartPointerTest.cxx ./a.out + * other: CCcompiler SmartPointerTest.cxx ./a.out + * + * \ingroup IGTLSystemObjects + * \ingroup DataAccess + */ +template +class IGTL_EXPORT SmartPointer +{ +public: + typedef TObjectType ObjectType; + + /** Constructor */ + SmartPointer () + { m_Pointer = 0; } + + /** Copy constructor */ + SmartPointer (const SmartPointer &p): + m_Pointer(p.m_Pointer) + { this->Register(); } + + /** Constructor to pointer p */ + SmartPointer (ObjectType *p): + m_Pointer(p) + { this->Register(); } + + /** Destructor */ + ~SmartPointer () + { + this->UnRegister(); + m_Pointer = 0; + } + + /** Overload operator -> */ + ObjectType *operator -> () const + { return m_Pointer; } + + /** Return pointer to object. */ + operator ObjectType * () const + { return m_Pointer; } + + /** Test if the pointer has been initialized */ + bool IsNotNull() const + { return m_Pointer != 0; } + bool IsNull() const + { return m_Pointer == 0; } + + /** Template comparison operators. */ + template + bool operator == ( R r ) const + { return (m_Pointer == static_cast(r) ); } + + template + bool operator != ( R r ) const + { return (m_Pointer != static_cast(r) ); } + + /** Access function to pointer. */ + ObjectType *GetPointer () const + { return m_Pointer; } + + /** Comparison of pointers. Less than comparison. */ + bool operator < (const SmartPointer &r) const + { return (void*)m_Pointer < (void*) r.m_Pointer; } + + /** Comparison of pointers. Greater than comparison. */ + bool operator > (const SmartPointer &r) const + { return (void*)m_Pointer > (void*) r.m_Pointer; } + + /** Comparison of pointers. Less than or equal to comparison. */ + bool operator <= (const SmartPointer &r) const + { return (void*)m_Pointer <= (void*) r.m_Pointer; } + + /** Comparison of pointers. Greater than or equal to comparison. */ + bool operator >= (const SmartPointer &r) const + { return (void*)m_Pointer >= (void*) r.m_Pointer; } + + /** Overload operator assignment. */ + SmartPointer &operator = (const SmartPointer &r) + { return this->operator = (r.GetPointer()); } + + /** Overload operator assignment. */ + SmartPointer &operator = (ObjectType *r) + { + if (m_Pointer != r) + { + ObjectType* tmp = m_Pointer; //avoid recursive unregisters by retaining temporarily + m_Pointer = r; + this->Register(); + if ( tmp ) { tmp->UnRegister(); } + } + return *this; + } + + /** Function to print object pointed to */ + ObjectType *Print (std::ostream& os) const + { + // This prints the object pointed to by the pointer + (*m_Pointer).Print(os); + return m_Pointer; + } + +private: + /** The pointer to the object referrred to by this smart pointer. */ + ObjectType* m_Pointer; + + void Register() + { + if(m_Pointer) { m_Pointer->Register(); } + } + + void UnRegister() + { + if(m_Pointer) { m_Pointer->UnRegister(); } + } +}; + + +template +std::ostream& operator<< (std::ostream& os, SmartPointer p) +{ + p.Print(os); + return os; +} + +} // end namespace igtl + +#endif diff --git a/openigtlink/repo/Source/igtlSocket.cxx b/openigtlink/repo/Source/igtlSocket.cxx new file mode 100644 index 0000000..9c6beec --- /dev/null +++ b/openigtlink/repo/Source/igtlSocket.cxx @@ -0,0 +1,666 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: igtlSocket.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +#include "igtlSocket.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) + #include + #include +#else + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +#include +#include + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define WSA_VERSION MAKEWORD(1,1) +#define igtlCloseSocketMacro(sock) (closesocket(sock)) +#else +#define igtlCloseSocketMacro(sock) \ + { \ + shutdown(sock, 2); \ + close(sock); \ + } +#endif + +namespace igtl +{ + +//----------------------------------------------------------------------------- +Socket::Socket() +{ + this->m_SocketDescriptor = -1; + this->m_SendTimeoutFlag = 0; + this->m_ReceiveTimeoutFlag = 0; +} + +//----------------------------------------------------------------------------- +Socket::~Socket() +{ + if (this->m_SocketDescriptor != -1) + { + this->CloseSocket(this->m_SocketDescriptor); + this->m_SocketDescriptor = -1; + } +} + +//----------------------------------------------------------------------------- +int Socket::CreateSocket() +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + // Declare variables + WSADATA wsaData; + //SOCKET ListenSocket; + //sockaddr_in service; + + //--------------------------------------- + // Initialize Winsock + int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); + if( iResult != NO_ERROR ) + { + std::cerr << "Error at WSAStartup" << std::endl; + return -1; + } +#endif + + int sock = socket(AF_INET, SOCK_STREAM, 0); + // Eliminate windows 0.2 second delay sending (buffering) data. + int on = 1; + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&on, sizeof(on))) + { + return -1; + } + return sock; +} + +//----------------------------------------------------------------------------- +int Socket::BindSocket(int socketdescriptor, int port) +{ + struct sockaddr_in server; + + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = htons(port); + // Allow the socket to be bound to an address that is already in use +#ifdef _WIN32 + int opt=1; + setsockopt(socketdescriptor, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(int)); +#elif defined(VTK_HAVE_SO_REUSEADDR) + int opt=1; + setsockopt(socketdescriptor, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, sizeof(int)); +#endif + + if ( bind(socketdescriptor, reinterpret_cast(&server), sizeof(server)) ) + { + return -1; + } + return 0; +} + +//----------------------------------------------------------------------------- +int Socket::Accept(int socketdescriptor) +{ + if (socketdescriptor < 0) + { + return -1; + } + return accept(socketdescriptor, 0, 0); +} + +//----------------------------------------------------------------------------- +int Socket::Listen(int socketdescriptor) +{ + if (socketdescriptor < 0) + { + return -1; + } + return listen(socketdescriptor, 1); +} + +//----------------------------------------------------------------------------- +int Socket::SelectSocket(int socketdescriptor, unsigned long msec) +{ + if (socketdescriptor < 0 ) + { + // invalid socket descriptor. + return -1; + } + + fd_set rset; + struct timeval tval; + struct timeval* tvalptr = 0; + if ( msec > 0 ) + { + tval.tv_sec = msec / 1000; + tval.tv_usec = (msec % 1000)*1000; + tvalptr = &tval; + } + FD_ZERO(&rset); + FD_SET(socketdescriptor, &rset); + int res = select(socketdescriptor + 1, &rset, 0, 0, tvalptr); + if(res == 0) + { + return 0;//for time limit expire + } + + if ( res < 0 || !(FD_ISSET(socketdescriptor, &rset)) ) + { + // Some error. + return -1; + } + // The indicated socket has some activity on it. + return 1; +} + +//----------------------------------------------------------------------------- +int Socket::SelectSockets(const int* sockets_to_select, int size, + unsigned long msec, int* selected_index) +{ + int i; + int max_fd = -1; + *selected_index = -1; + if (size < 0) + { + return -1; + } + + fd_set rset; + struct timeval tval; + struct timeval* tvalptr = 0; + if ( msec > 0 ) + { + tval.tv_sec = msec / 1000; + tval.tv_usec = msec % 1000; + tvalptr = &tval; + } + FD_ZERO(&rset); + for (i=0; i max_fd)? sockets_to_select[i] : max_fd; + } + + int res = select(max_fd + 1, &rset, 0, 0, tvalptr); + if (res == 0) + { + return 0; //Timeout + } + if (res < 0) + { + // SelectSocket error. + return -1; + } + + //check which socket has some activity. + for (i=0; ih_addr, hp->h_length); + name.sin_port = htons(port); + + int r = connect(socketdescriptor, reinterpret_cast(&name), + sizeof(name)); + + return r; +} + +//----------------------------------------------------------------------------- +int Socket::GetPort(int sock) +{ + struct sockaddr_in sockinfo; + memset(&sockinfo, 0, sizeof(sockinfo)); +#if defined(OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T) + socklen_t sizebuf = sizeof(sockinfo); +#else + int sizebuf = sizeof(sockinfo); +#endif +// FIXME: Setup configuration for VTK_HAVE_GETSOCKNAME_WITH_SOCKLEN_T so we can uncomment these lines + if(getsockname(sock, reinterpret_cast(&sockinfo), &sizebuf) != 0) + { + return 0; + } + return ntohs(sockinfo.sin_port); +} + +//----------------------------------------------------------------------------- +void Socket::CloseSocket(int socketdescriptor) +{ + if (socketdescriptor < 0) + { + return; + } + igtlCloseSocketMacro(socketdescriptor); +} + +//----------------------------------------------------------------------------- +int Socket::Send(const void* data, igtlUint64 length) +{ + if (!this->GetConnected()) + { + return 0; + } + if (length == 0) + { + // nothing to send. + return 1; + } + const char* buffer = reinterpret_cast(data); + igtlUint64 total = 0; + do + { + int flags; +#if defined(_WIN32) && !defined(__CYGWIN__) + flags = 0; +#else + // On unix boxes if the client disconnects and the server attempts + // to send data through the socket then the application crashes + // due to SIGPIPE signal. Disable the signal to prevent crash. + //#ifndef __sun + // flags = MSG_NOSIGNAL; + //#else + // // Signal is not present on SUN systems, the signal has + // // to be managed at application level. + // flags = 0; + //#endif + #if defined(MSG_NOSIGNAL) // For Linux > 2.2 + flags = MSG_NOSIGNAL; + #else + #if defined(SO_NOSIGPIPE) // Mac OS X + int set = 1; + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); + #endif + flags = 0; + #endif +#endif + int n = send(this->m_SocketDescriptor, buffer + total, (length > std::numeric_limits::max()) ? std::numeric_limits::max() : length-total, flags); + + if(n < 0) + { + // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Send failed."); + return 0; + } + total += n; + } while(total < length); + return 1; +} + +//----------------------------------------------------------------------------- +igtlUint64 Socket::Receive(void* data, igtlUint64 length, bool& timeout, int readFully/*=1*/) +{ + if (!this->GetConnected()) + { + timeout = false; + return 0; + } + + char* buffer = reinterpret_cast(data); + igtlUint64 total = 0; + do + { +#if defined(_WIN32) && !defined(__CYGWIN__) + int trys = 0; +#endif + + int n = recv(this->m_SocketDescriptor, buffer + total, (length > std::numeric_limits::max() ? std::numeric_limits::max() : length - total), 0); + +#if defined(_WIN32) && !defined(__CYGWIN__) + if(n == 0) + { + // On long messages, Windows recv sometimes fails with WSAENOBUFS, but + // will work if you try again. + int error = WSAGetLastError(); + if ((error == WSAENOBUFS) && (trys++ < 1000)) + { + Sleep(1); + continue; + } + // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Receive failed."); + return 0; + } + else if (n < 0) + { + // TODO: Need to check if this means timeout. + timeout = true; + return 0; + } +#else + if(n == 0) // Disconnected + { + // FIXME : Use exceptions ? igtlErrorMacro("Socket Error: Receive failed."); + return 0; + } + else if (n < 0) // Error (including time out) + { + // TODO: If it is time-out, errno == EAGAIN + timeout = true; + return 0; + } +#endif + + total += n; + } while(readFully && total < length); + return total; +} + + +//----------------------------------------------------------------------------- +int Socket::SetTimeout(int timeout) +{ + if (SetReceiveTimeout(timeout) && SetSendTimeout(timeout)) + { + return 1; + } + else + { + return 0; + } +} + + +//----------------------------------------------------------------------------- +int Socket::SetReceiveTimeout(int timeout) +{ + if (!this->GetConnected()) + { + return 0; + } + +#if defined(_WIN32) && !defined(__CYGWIN__) + this->m_ReceiveTimeout = timeout; + int len; +#else + this->m_ReceiveTimeout.tv_sec = timeout/1000; /* second */ + this->m_ReceiveTimeout.tv_usec = (timeout%1000) * 1000; /* microsecond */ + socklen_t len; +#endif + if ( timeout > 0 ) + { + getsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_OrigReceiveTimeout), &len); + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_ReceiveTimeout), sizeof(this->m_ReceiveTimeout)); + this->m_ReceiveTimeoutFlag = 1; + } + else if (this->m_ReceiveTimeoutFlag) + { + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_OrigReceiveTimeout), sizeof(this->m_OrigReceiveTimeout)); + this->m_ReceiveTimeoutFlag = 0; + } + + return timeout; +} + + +//----------------------------------------------------------------------------- +int Socket::SetSendTimeout(int timeout) +{ + if (!this->GetConnected()) + { + return 0; + } + +#if defined(_WIN32) && !defined(__CYGWIN__) + this->m_SendTimeout = timeout; + int len; +#else + this->m_SendTimeout.tv_sec = timeout/1000; /* second */ + this->m_SendTimeout.tv_usec = (timeout%1000) * 1000; /* microsecond */ + socklen_t len; +#endif + if ( timeout > 0 ) + { + getsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_OrigSendTimeout), &len); + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_SendTimeout), sizeof(this->m_SendTimeout)); + this->m_SendTimeoutFlag = 1; + } + else if (this->m_SendTimeoutFlag) + { + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_OrigSendTimeout), sizeof(this->m_OrigSendTimeout)); + this->m_SendTimeoutFlag = 0; + } + + return timeout; +} + + +//----------------------------------------------------------------------------- +int Socket::SetReceiveBlocking(int sw) +{ + if (!this->GetConnected()) + { + return 0; + } + + // If sw == 1, timeout is set to 0 (wait until it receives message) +#if defined(_WIN32) && !defined(__CYGWIN__) + if (sw==0) + { + this->m_ReceiveTimeout = 1; + } + else + { + this->m_ReceiveTimeout = 0; + } + int len; +#else + if (sw==0) + { + this->m_ReceiveTimeout.tv_sec = 0; /* second */ + this->m_ReceiveTimeout.tv_usec = 1; /* nanosecond */ + } + else + { + this->m_ReceiveTimeout.tv_sec = 0; /* second */ + this->m_ReceiveTimeout.tv_usec = 0; /* nanosecond */ + } + socklen_t len; +#endif + if (sw==0) + { + getsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_OrigReceiveTimeout), &len); + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_ReceiveTimeout), sizeof(this->m_ReceiveTimeout)); + this->m_ReceiveTimeoutFlag = 1; + } + else if (this->m_ReceiveTimeoutFlag) + { + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_RCVTIMEO, + (char*)&(this->m_OrigReceiveTimeout), sizeof(this->m_OrigReceiveTimeout)); + this->m_ReceiveTimeoutFlag = 0; + } + + return sw; +} + + +//----------------------------------------------------------------------------- +int Socket::SetSendBlocking(int sw) +{ + if (!this->GetConnected()) + { + return 0; + } + + // If sw == 1, timeout is set to 0 (wait until it receives message) +#if defined(_WIN32) && !defined(__CYGWIN__) + if (sw==0) + { + this->m_SendTimeout = 1; + } + else + { + this->m_SendTimeout = 0; + } + int len; +#else + if (sw==0) + { + this->m_SendTimeout.tv_sec = 0; /* second */ + this->m_SendTimeout.tv_usec = 1; /* nanosecond */ + } + else + { + this->m_SendTimeout.tv_sec = 0; /* second */ + this->m_SendTimeout.tv_usec = 0; /* nanosecond */ + } + socklen_t len; +#endif + if (sw==0) + { + getsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_OrigSendTimeout), &len); + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_SendTimeout), sizeof(this->m_SendTimeout)); + this->m_SendTimeoutFlag = 1; + } + else if (this->m_SendTimeoutFlag) + { + setsockopt(this->m_SocketDescriptor, SOL_SOCKET, SO_SNDTIMEO, + (char*)&(this->m_OrigSendTimeout), sizeof(this->m_OrigSendTimeout)); + this->m_SendTimeoutFlag = 0; + } + + return sw; +} + + +//----------------------------------------------------------------------------- +int Socket::GetSocketAddressAndPort(std::string& address, int& port) +{ + struct sockaddr_in sockinfo; + + memset(&sockinfo, 0, sizeof(sockinfo)); + +#if defined(OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T) + socklen_t sizebuf = sizeof(sockinfo); +#else + int sizebuf = sizeof(sockinfo); +#endif + + if( getsockname(this->m_SocketDescriptor, reinterpret_cast(&sockinfo), &sizebuf) != 0) + { + return 0; + } + const char* a = inet_ntoa(sockinfo.sin_addr); + if ( a == NULL ) + { + return 0; + } + address = a; + port = ntohs(sockinfo.sin_port); + + return 1; +} + + +//----------------------------------------------------------------------------- +int Socket::Skip(igtlUint64 length, int skipFully/*=1*/) +{ + if (length == 0) + { + return 0; + } + + unsigned char dummy[256]; + igtlUint64 block = 256; + igtlUint64 n = 0; + igtlUint64 remain = length; + + do + { + if (remain < block) + { + block = remain; + } + + bool timeout(false); + n = this->Receive(dummy, block, timeout, skipFully); + if (!skipFully && n <= 0) + { + break; + } + remain -= n; + } + while (remain > 0 || (skipFully && n < block)); + + return (length - remain); +} + +//----------------------------------------------------------------------------- +void Socket::PrintSelf(std::ostream& os) const +{ + this->Superclass::PrintSelf(os); +} + + +} // end of igtl namespace diff --git a/openigtlink/repo/Source/igtlSocket.h b/openigtlink/repo/Source/igtlSocket.h new file mode 100644 index 0000000..7e533d3 --- /dev/null +++ b/openigtlink/repo/Source/igtlSocket.h @@ -0,0 +1,194 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: igtlSocket.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/** \class Socket + * \brief BSD socket encapsulation. + * + * This abstract class encapsulates a BSD socket. + * It provides an API for basic socket operations. + * + * This class was largely based on the igtlSocket class + * from the Visualization Toolkit VTK. + * + */ + +#ifndef __igtlSocket_h +#define __igtlSocket_h + +#include "igtlMacro.h" +#include "igtlObject.h" +#include "igtlObjectFactory.h" +#include "igtlTypes.h" +#include "igtlWin32Header.h" + + +#if defined(_WIN32) && !defined(__CYGWIN__) +#else +#include +#endif + + +namespace igtl +{ + +class SocketCollection; + +/// class IGTL_EXPORT Socket +class IGTLCommon_EXPORT Socket : public Object +{ + public: + igtlTypeMacro(igtl::Socket, igtl::Object) + igtlNewMacro(igtl::Socket); + +public: + + /// Check is the socket is alive. + bool GetConnected() { return (this->m_SocketDescriptor >=0); } + + /// Close the socket. + void CloseSocket() { + this->CloseSocket(this->m_SocketDescriptor); + this->m_SocketDescriptor = -1; + } + + /// These methods send data over the socket. + /// Returns 1 on success, 0 on error and raises vtkCommand::ErrorEvent. + /// SIGPIPE or other signal may be raised on systems (e.g., Sun Solaris) where + /// MSG_NOSIGNAL flag is not supported for the socket send method. + int Send(const void* data, igtlUint64 length); + + /// Receive data from the socket. + /// This call blocks until some data is read from the socket, unless timeout is set + /// by SetTimeout() or SetReceiveTimeout(). + /// When the readFully flag is set, this call will block until all the requested data is + /// read from the socket. The readFully flag will be ignored if the timeout is active. + /// 0 on error, else number of bytes read is returned. + /// On timeout, the timeout variable will be set to true and the return value is ignored + igtlUint64 Receive(void* data, igtlUint64 length, bool& timeout, int readFully=1); + + /// Set sending/receiving timeout for the existing socket in millisecond. + /// This function should be called after opening the socket. + int SetTimeout(int timeout); + + /// Set reciving timeout for the existing socket in millisecond. + /// This function should be called after opening the socket. + int SetReceiveTimeout(int timeout); + + /// Set sending timeout for the existing socket in millisecond. + /// This function should be called after opening the socket. + int SetSendTimeout(int timeout); + + /// Set (psuedo) non-blocking mode for recv(). When sw=1, the time out is set to + /// minimum value (1 microsecond in UNIX, 1 millisecond in Windows) for receiving. + int SetReceiveBlocking(int sw); + + /// Set (psuedo) non-blocking mode for recv(). When sw=1, the time out is set to + /// minimum value (1 microsecond in UNIX, 1 millisecond in Windows) for sending. + int SetSendBlocking(int sw); + + /// Get socket address + int GetSocketAddressAndPort(std::string& address, int & port); + + /// Skip reading data from the socket. + /// The Skip() call has been newly introduced to the igtlSocket, + /// after the class is imported from VTK, thus the call is + /// not available in vtkSocket class. + int Skip(igtlUint64 length, int skipFully=1); + +protected: + Socket(); + ~Socket(); + + void PrintSelf(std::ostream& os) const override; + + int m_SocketDescriptor; + igtlGetMacro(SocketDescriptor, int); + + //BTX + friend class vtkSocketCollection; + //ETX + + /// Creates an endpoint for communication and returns the descriptor. + /// -1 indicates error. + int CreateSocket(); + + /// Close the socket. + void CloseSocket(int socketdescriptor); + + /// Binds socket to a particular port. + /// Returns 0 on success other -1 is returned. + int BindSocket(int socketdescriptor, int port); + + /// Selects a socket ie. waits for it to change status. + /// Returns 1 on success; 0 on timeout; -1 on error. msec=0 implies + /// no timeout. + int SelectSocket(int socketdescriptor, unsigned long msec); + + /// Accept a connection on a socket. Returns -1 on error. Otherwise + /// the descriptor of the accepted socket. + int Accept(int socketdescriptor); + + /// Listen for connections on a socket. Returns 0 on success. -1 on error. + int Listen(int socketdescriptor); + + /// Connect to a server socket. Returns 0 on success, -1 on error. + int Connect(int socketdescriptor, const char* hostname, int port); + + /// Returns the port to which the socket is connected. + /// 0 on error. + int GetPort(int socketdescriptor); + + /// Selects set of sockets. Returns 0 on timeout, -1 on error. + /// 1 on success. Selected socket's index is returned through + /// selected_index + static int SelectSockets(const int* sockets_to_select, int size, + unsigned long msec, int* selected_index); + +private: + Socket(const Socket&); // Not implemented. + void operator=(const Socket&); // Not implemented. + +#if defined(_WIN32) && !defined(__CYGWIN__) + DWORD m_SendTimeout; + DWORD m_ReceiveTimeout; + DWORD m_OrigSendTimeout; + DWORD m_OrigReceiveTimeout; +#else + struct timeval m_SendTimeout; + struct timeval m_ReceiveTimeout; + struct timeval m_OrigSendTimeout; + struct timeval m_OrigReceiveTimeout; +#endif + int m_SendTimeoutFlag; + int m_ReceiveTimeoutFlag; + +}; + +} + +#endif diff --git a/openigtlink/repo/Source/igtlStatusMessage.cxx b/openigtlink/repo/Source/igtlStatusMessage.cxx new file mode 100644 index 0000000..d0c4de8 --- /dev/null +++ b/openigtlink/repo/Source/igtlStatusMessage.cxx @@ -0,0 +1,149 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlStatusMessage.h" + +#include "igtl_header.h" +#include "igtl_status.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include + +namespace igtl { + +StatusMessage::StatusMessage(): + MessageBase() +{ + m_StatusHeader = NULL; + m_StatusMessage = NULL; + + m_ErrorName[0] = '\n'; + m_SendMessageType = "STATUS"; + m_StatusMessageString = ""; + +} + +StatusMessage::~StatusMessage() +{ +} + +void StatusMessage::SetCode(int code) +{ + m_IsBodyPacked = false; + if (code >= 0 && code < STATUS_NUM_TYPES) + { + this->m_Code = code; + } + else + { + this->m_Code = 0; + } +} + +int StatusMessage::GetCode() +{ + return this->m_Code; +} + +void StatusMessage::SetSubCode(igtlInt64 subcode) +{ + m_IsBodyPacked = false; + this->m_SubCode = subcode; +} + +igtlInt64 StatusMessage::GetSubCode() +{ + return this->m_SubCode; +} + +void StatusMessage::SetErrorName(const char* name) +{ + m_IsBodyPacked = false; + this->m_ErrorName[IGTL_STATUS_ERROR_NAME_LENGTH-1] = '\0'; + strncpy(this->m_ErrorName, name, IGTL_STATUS_ERROR_NAME_LENGTH); +} + +const char* StatusMessage::GetErrorName() +{ + return this->m_ErrorName; +} + +void StatusMessage::SetStatusString(const char* str) +{ + m_IsBodyPacked = false; + this->m_StatusMessageString = str; +} + +const char* StatusMessage::GetStatusString() +{ + return this->m_StatusMessageString.c_str(); +} + + +igtlUint64 StatusMessage::CalculateContentBufferSize() +{ + // The body size sum of the header size and status message size. + // Note that the status message ends with '\0' + return IGTL_STATUS_HEADER_SIZE + m_StatusMessageString.size() + 1; +} + +int StatusMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + m_StatusHeader = this->m_Content; + + m_StatusMessage = (char*)&m_StatusHeader[IGTL_STATUS_HEADER_SIZE]; + igtl_status_header* status_header = (igtl_status_header*)this->m_StatusHeader; + + status_header->code = static_cast(this->m_Code); + status_header->subcode = this->m_SubCode; + strncpy(status_header->error_name, this->m_ErrorName, IGTL_STATUS_ERROR_NAME_LENGTH); + strcpy(this->m_StatusMessage, this->m_StatusMessageString.c_str()); + + igtl_status_convert_byte_order(status_header); + + return 1; +} + +int StatusMessage::UnpackContent() +{ + m_StatusHeader = this->m_Content; + m_StatusMessage = (char*)&m_StatusHeader[IGTL_STATUS_HEADER_SIZE]; + + igtl_status_header* status_header = (igtl_status_header*)this->m_StatusHeader; + igtl_status_convert_byte_order(status_header); + + this->m_Code = status_header->code; + this->m_SubCode = status_header->subcode; + this->m_ErrorName[IGTL_STATUS_ERROR_NAME_LENGTH-1] = '\0'; + strncpy(this->m_ErrorName, status_header->error_name, IGTL_STATUS_ERROR_NAME_LENGTH); + + // make sure that the status message in the pack ends with '\0' + bool isUnpacked(true); + if (m_StatusMessage[CalculateReceiveContentSize(isUnpacked)-IGTL_STATUS_HEADER_SIZE-1] == '\0') + { + this->m_StatusMessageString = m_StatusMessage; + } + else + { + //std::cerr << "status message in the pack does not end with '\0'" << std::endl; + } + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlStatusMessage.h b/openigtlink/repo/Source/igtlStatusMessage.h new file mode 100644 index 0000000..c777a95 --- /dev/null +++ b/openigtlink/repo/Source/igtlStatusMessage.h @@ -0,0 +1,140 @@ +/*========================================================================= + + Program: The OpenIGTLinkLibrary + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlStatusMessage_h +#define __igtlStatusMessage_h + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +namespace igtl +{ + + +/// A class for the GET_STATUS message type. +class IGTLCommon_EXPORT GetStatusMessage: public HeaderOnlyMessageBase +{ +public: + igtlTypeMacro(igtl::GetStatusMessage, igtl::HeaderOnlyMessageBase); + igtlNewMacro(igtl::GetStatusMessage); + +protected: + GetStatusMessage() : HeaderOnlyMessageBase() { this->m_SendMessageType = "GET_STATUS"; }; + ~GetStatusMessage() {}; +}; + + +/// The STATUS data type is used to notify the receiver about the current status of the sender. +/// The data consist of status code in a 16-bit unsigned integer, sub code in a 64-bit integer, +/// error name in a 20-byte-length character string, and a status message. The length of +/// the status message is determined by the size information in the general header. +/// The status code is defined as a part of the OpenIGTLink protocol specification listed +/// bellow. The sub code is device specific and is defined by developers. In addition, +/// developers can build their own error name/code into the status message and additional +/// optional description in the following data field. +class IGTLCommon_EXPORT StatusMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::StatusMessage, igtl::MessageBase); + igtlNewMacro(igtl::StatusMessage); + +public: + + /// Status codes -- see igtl_status.h + enum { + STATUS_INVALID = 0, + STATUS_OK = 1, + STATUS_UNKNOWN_ERROR = 2, + STATUS_PANICK_MODE = 3, /* emergency */ + STATUS_NOT_FOUND = 4, /* file, configuration, device etc */ + STATUS_ACCESS_DENIED = 5, + STATUS_BUSY = 6, + STATUS_TIME_OUT = 7, /* Time out / Connection lost */ + STATUS_OVERFLOW = 8, /* Overflow / Can't be reached */ + STATUS_CHECKSUM_ERROR = 9, /* Checksum error */ + STATUS_CONFIG_ERROR = 10, /* Configuration error */ + STATUS_RESOURCE_ERROR = 11, /* Not enough resource (memory, storage etc) */ + STATUS_UNKNOWN_INSTRUCTION = 12, /* Illegal/Unknown instruction */ + STATUS_NOT_READY = 13, /* Device not ready (starting up)*/ + STATUS_MANUAL_MODE = 14, /* Manual mode (device does not accept commands) */ + STATUS_DISABLED = 15, /* Device disabled */ + STATUS_NOT_PRESENT = 16, /* Device not present */ + STATUS_UNKNOWN_VERSION = 17, /* Device version not known */ + STATUS_HARDWARE_FAILURE = 18, /* Hardware failure */ + STATUS_SHUT_DOWN = 19, /* Exiting / shut down in progress */ + STATUS_NUM_TYPES = 20 + }; + +public: + + /// Sets the status code. + void SetCode(int code); + + /// Gets the status code. + int GetCode(); + + /// Sets the sub code. + void SetSubCode(igtlInt64 subcode); + + /// Gets the sub code. + igtlInt64 GetSubCode(); + + /// Sets the error name. The error name can be defined by a developer. + void SetErrorName(const char* name); + + /// Gets the error name. + const char* GetErrorName(); + + /// Sets the status string. + void SetStatusString(const char* str); + + /// Gets the status string. + const char* GetStatusString(); + +protected: + StatusMessage(); + ~StatusMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// The error code. + igtlUint16 m_Code; + + /// The sub code. + igtlInt64 m_SubCode; + + /// The error name. + char m_ErrorName[20]; + + /// The status message string. + std::string m_StatusMessageString; + + /// A pointer to the byte array of the status header. + unsigned char* m_StatusHeader; + + /// A pointer to the byte array of the status message. + char* m_StatusMessage; + +}; + + +} // namespace igtl + +#endif // _igtlStatusMessage_h \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlStringMessage.cxx b/openigtlink/repo/Source/igtlStringMessage.cxx new file mode 100644 index 0000000..f30bfef --- /dev/null +++ b/openigtlink/repo/Source/igtlStringMessage.cxx @@ -0,0 +1,140 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlStringMessage.h" + +#include "igtl_header.h" +#include "igtl_string.h" + +#include + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +namespace igtl { + +StringMessage::StringMessage() +{ + this->m_SendMessageType = "STRING"; + this->m_Encoding = IGTL_STRING_MESSAGE_DEFAULT_ENCODING; + this->m_String.clear(); +} + +StringMessage::~StringMessage() +{ +} + + +int StringMessage::SetString(const char* string) +{ + if (strlen(string) > 0xFFFF) /* If the length is beyond the range of unsigned short */ + { + return 0; + } + m_IsBodyPacked = false; + this->m_String = string; + return (int) this->m_String.length(); +} + + +int StringMessage::SetString(const std::string & string) +{ + if (string.length() > 0xFFFF) /* If the length is beyond the range of unsigned short */ + { + return 0; + } + m_IsBodyPacked = false; + this->m_String = string; + return (int) this->m_String.length(); +} + + +int StringMessage::SetEncoding(igtlUint16 enc) +{ + // TODO: the argument should be validated before it is substituted + this->m_Encoding = enc; + m_IsBodyPacked = false; + return 1; +} + + +const char* StringMessage::GetString() +{ + return this->m_String.c_str(); +} + + +igtlUint16 StringMessage::GetEncoding() +{ + return this->m_Encoding; +} + + +igtlUint64 StringMessage::CalculateContentBufferSize() +{ + // Body pack size is the sum of ENCODING, LENGTH and STRING fields + return sizeof(igtlUint16)*2 + this->m_String.length(); +} + + +int StringMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + igtl_string_header * string_header; + char * string; + // Set pointers +#if OpenIGTLink_HEADER_VERSION >= 2 + string_header = (igtl_string_header*) this->m_Content; + string = (char *) this->m_Content + sizeof(igtlUint16)*2; +#elif OpenIGTLink_PROTOCOL_VERSION <=2 + string_header = (igtl_string_header*) this->m_Body; + string = (char *) this->m_Body + sizeof(igtlUint16)*2; +#endif + + // Copy data + string_header->encoding = static_cast(this->m_Encoding); + string_header->length = static_cast(this->m_String.length()); + strncpy(string, this->m_String.c_str(), string_header->length); + + // Convert byte order from host to network + igtl_string_convert_byte_order(string_header); + + return 1; +} + +int StringMessage::UnpackContent() +{ + igtl_string_header * string_header; + char * string; +#if OpenIGTLink_HEADER_VERSION >= 2 + string_header = (igtl_string_header*) (this->m_Content); + string = (char *) this->m_Content + sizeof(igtlUint16)*2; +#elif OpenIGTLink_PROTOCOL_VERSION <=2 + string_header = (igtl_string_header*) this->m_Body; + string = (char *) this->m_Body + sizeof(igtlUint16)*2; +#endif + + // Convert byte order from network to host + igtl_string_convert_byte_order(string_header); + + // Copy data + this->m_Encoding = string_header->encoding; + this->m_String.clear(); + this->m_String.append(string, string_header->length); + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlStringMessage.h b/openigtlink/repo/Source/igtlStringMessage.h new file mode 100644 index 0000000..d5bcc4c --- /dev/null +++ b/openigtlink/repo/Source/igtlStringMessage.h @@ -0,0 +1,82 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlStringMessage_h +#define __igtlStringMessage_h + +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +#define IGTL_STRING_MESSAGE_DEFAULT_ENCODING 3 /* Default encoding -- ANSI-X3.5-1968 */ + +namespace igtl +{ + +/// THe STRING message type is used for transferring a character string. It supports character strings up to 65535 bytes. +class IGTLCommon_EXPORT StringMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::StringMessage, igtl::MessageBase); + igtlNewMacro(igtl::StringMessage); + +public: + + /// Sets the string by character array. + int SetString(const char* string); + + /// Sets the string by std::string. + int SetString(const std::string & string); + + /// Sets the encoding of the string. For character encoding, please refer IANA Character Sets + /// (http://www.iana.org/assignments/character-sets). + /// US-ASCII (ANSI-X3.4-1968; MIBenum = 3) is strongly recommended. + int SetEncoding(igtlUint16 enc); + + /// Gets the string. + const char* GetString(); + + /// Gets the encoding of the string. The returned value is defined in + /// IANA Character Sets (http://www.iana.org/assignments/character-sets). + igtlUint16 GetEncoding(); + +protected: + StringMessage(); + ~StringMessage() override; + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// The encoding of the string. + /// The value is defined in IANA Character Sets (http://www.iana.org/assignments/character-sets). + igtlUint16 m_Encoding; + + /// The string. + std::string m_String; + +}; + + +} // namespace igtl + +#endif // _igtlStringMessage_h + + + diff --git a/openigtlink/repo/Source/igtlTimeStamp.cxx b/openigtlink/repo/Source/igtlTimeStamp.cxx new file mode 100644 index 0000000..88e7329 --- /dev/null +++ b/openigtlink/repo/Source/igtlTimeStamp.cxx @@ -0,0 +1,254 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +/*========================================================================= + + Part of the code is copied from itk::RealTimeClock class in + Insight Segmentation & Registration Toolkit: + + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkRealTimeClock.cxx,v $ + Language: C++ + Date: $Date: 2011-03-24 00:08:23 -0400 (Thu, 24 Mar 2011) $ + Version: $Revision: 7354 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlTimeStamp.h" + +#include + +#if defined(WIN32) || defined(_WIN32) + #include +#else + #include +#endif // defined(WIN32) || defined(_WIN32) + +#include + +#include "igtl_util.h" + +namespace igtl +{ + +TimeStamp::TimeStamp(): Object() +{ +#if defined(WIN32) || defined(_WIN32) + + //LARGE_INTEGER frequency; + //::QueryPerformanceFrequency(&frequency); + // + //this->m_WinFrequency = + // static_cast< FrequencyType >( (__int64)frequency.QuadPart ); + // + //SYSTEMTIME st1; + //SYSTEMTIME st2; + //FILETIME ft1; + //FILETIME ft2; + // + //::memset( &st1, 0, sizeof( st1 ) ); + //::memset( &st2, 0, sizeof( st2 ) ); + // + //st1.wYear = 1601; + //st1.wMonth = 1; + //st1.wDay = 1; + // + //st2.wYear = 1970; + //st2.wMonth = 1; + //st2.wDay = 1; + // + //::SystemTimeToFileTime(&st1, &ft1); + //::SystemTimeToFileTime(&st2, &ft2); + // + //LARGE_INTEGER ui1; + //LARGE_INTEGER ui2; + // + //memcpy( &ui1, &ft1, sizeof( ui1 ) ); + //memcpy( &ui2, &ft2, sizeof( ui2 ) ); + // + //this->m_WinDifference = + // static_cast< TimeStampType >( ui2.QuadPart - ui1.QuadPart) / + // static_cast< TimeStampType >( 1e7 ); + // + //FILETIME currentTime; + //LARGE_INTEGER intTime; + //LARGE_INTEGER tick; + // + //::GetSystemTimeAsFileTime( ¤tTime ); + //::QueryPerformanceCounter( &tick ); + // + //memcpy( &intTime, ¤tTime, sizeof( intTime ) ); + // + //this->m_WinOrigin = + // static_cast< TimeStampType >( intTime.QuadPart ) / + // static_cast< TimeStampType >( 1e7 ); + // + //this->m_WinOrigin -= + // static_cast< TimeStampType >( (__int64)tick.QuadPart ) / + // this->m_WinFrequency; + // + //this->m_WinOrigin += this->m_WinDifference; + // + //this->m_Frequency = static_cast( m_WinFrequency ); + + this->m_WinTimeOrigin = time( NULL ); + this->m_WinClockOrigin = clock(); + this->m_Frequency = 1000000; + +#else + + this->m_Frequency = 1000000; + +#endif // defined(WIN32) || defined(_WIN32) +} + + +TimeStamp::~TimeStamp() +{ +} + + +void TimeStamp::GetTime() +{ +#if defined(WIN32) || defined(_WIN32) + + //LARGE_INTEGER tick; + // + //::QueryPerformanceCounter( &tick ); + // + //TimeStampType value = + // static_cast< TimeStampType >( (__int64)tick.QuadPart ) / + // this->m_WinFrequency; + // + //value += this->m_WinOrigin; + // + //double second = floor(value); + + clock_t c1 = clock(); + this->m_Second = this->m_WinTimeOrigin + ( c1 - this->m_WinClockOrigin ) / CLOCKS_PER_SEC; + this->m_Nanosecond = (c1 - this->m_WinClockOrigin ) % CLOCKS_PER_SEC * ( 1e9 / CLOCKS_PER_SEC ); + +#else + + struct timeval tval; + + ::gettimeofday( &tval, 0 ); + + this->m_Second = tval.tv_sec; + this->m_Nanosecond = tval.tv_usec * 1000; /* convert from micro to nano */ + +#endif // defined(WIN32) || defined(_WIN32) + +} + +void TimeStamp::SetTime(double tm) +{ + double second = floor(tm); + this->m_Second = static_cast(second); + this->m_Nanosecond = static_cast((tm - second)*1e9); +} + +void TimeStamp::SetTime(igtlUint32 second, igtlUint32 nanosecond) +{ + if (nanosecond < 1e9) + { + this->m_Second = second; + this->m_Nanosecond = nanosecond; + } +} + + +void TimeStamp::SetTime(igtlUint64 tm) +{ + // Export from 64-bit fixed-point expression used in OpenIGTLink + igtlInt32 sec = static_cast((tm >> 32 ) & 0xFFFFFFFF); + igtlInt32 fraction = static_cast(tm & 0xFFFFFFFF); + this->m_Second = sec; + this->m_Nanosecond = igtl_frac_to_nanosec(static_cast(fraction)); +} + + +//----------------------------------------------------------------------------- +void TimeStamp::SetTimeInNanoseconds(igtlUint64 tm) +{ + igtlUint64 sec = tm / 1e9; // integer rounding + igtlUint64 nano = sec * 1e9; // round it back up to get whole number of seconds expressed in nanoseconds. + this->m_Second = static_cast(sec); + this->m_Nanosecond = static_cast(tm - nano); +} + + +double TimeStamp::GetTimeStamp() +{ + double tm; + tm = static_cast(this->m_Second) + + static_cast(this->m_Nanosecond) / 1e9; + + return tm; +} + +void TimeStamp::GetTimeStamp(igtlUint32* second, igtlUint32* nanosecond) +{ + *second = this->m_Second; + *nanosecond = this->m_Nanosecond; +} + + +igtlUint64 TimeStamp::GetTimeStampUint64() +{ + // Export as 64-bit fixed-point expression used in OpenIGTLink + igtlInt32 sec = this->m_Second; + igtlInt32 fraction = igtl_nanosec_to_frac(this->m_Nanosecond); + + igtlUint64 ts = sec & 0xFFFFFFFF; + ts = (ts << 32) | (fraction & 0xFFFFFFFF); + + return ts; +} + + +//----------------------------------------------------------------------------- +igtlUint64 TimeStamp::GetTimeStampInNanoseconds() const +{ + igtlUint64 tmp = this->m_Second * 1e9; + tmp += this->m_Nanosecond; + return tmp; +} + +void TimeStamp::PrintSelf( std::ostream& os) const +{ + Superclass::PrintSelf(os); + + std::string indent = " "; + + os << indent << "Frequency of the clock: " + << this->m_Frequency << std::endl; + os << indent << "Second : " + << this->m_Second << std::endl; + os << indent << "Nanosecond : " + << this->m_Nanosecond << std::endl; +} + +} + + diff --git a/openigtlink/repo/Source/igtlTimeStamp.h b/openigtlink/repo/Source/igtlTimeStamp.h new file mode 100644 index 0000000..f52479d --- /dev/null +++ b/openigtlink/repo/Source/igtlTimeStamp.h @@ -0,0 +1,116 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlTimeStamp_h +#define __igtlTimeStamp_h + +#include "igtlMacro.h" +#include "igtlObject.h" +#include "igtlObjectFactory.h" +#include "igtlTypes.h" + +#if defined(WIN32) || defined(_WIN32) +#include +#endif + +namespace igtl +{ + +class IGTLCommon_EXPORT TimeStamp : public Object +{ +public: + igtlTypeMacro(TimeStamp, Object); + igtlNewMacro(Self); + + /// Gets the frequency of a clock. + igtlGetConstMacro(Frequency, igtlUint32); + + /// Gets the second part of the time stamp. + igtlGetConstMacro(Second, igtlUint32); + + /// Gets the fraction of second part of the time stamp. + igtlGetConstMacro(Nanosecond, igtlUint32); + + /// Gets the current time from the system's clock and save it as a time stamp. + void GetTime(); + + /// Sets the time by double floating-point value. + void SetTime(double tm); + + /// Sets the time by second and nanosecond + void SetTime(igtlUint32 second, igtlUint32 nanosecond); + + /// Sets the time by using 64-bit fixed-point expression used in OpenIGTLink. + void SetTime(igtlUint64 tm); + + /// Sets the time using the total number of nano-seconds since the start of time (Unix Epoch = 1 Jan 1970). + /// Note: This is deliberately different to SetTime(); + void SetTimeInNanoseconds(igtlUint64 tm); + + /// Gets the time stamp. Returns a double floating-point value. + double GetTimeStamp(); + + /// Gets the time stamp. The second and nanosecond parts are stored in 'second' and 'nanosecond' + void GetTimeStamp(igtlUint32* second, igtlUint32* nanosecond); + + /// Gets the time stamp. Returns a 64-bit fixed-point expression used in OpenIGTLink. + igtlUint64 GetTimeStampUint64(); + + /// Gets the time in nano-seconds since the start of time (Unix Epoch = 1 Jan 1970). + /// Note: This is deliberately different to GetTimeStampUint64(); + igtlUint64 GetTimeStampInNanoseconds() const; + +protected: + + /** constructor */ + TimeStamp(); + + /** destructor */ + virtual ~TimeStamp(); + + /** Print the object information in a stream. */ + void PrintSelf( std::ostream& os) const override; + +private: + + /// Clock frequency (Hz) + igtlInt32 m_Frequency; + + /// Second part of the time relative to 00:00:00 January 1, 1970 UTC + igtlInt32 m_Second; + + /// Nano-second part of the time stamp + igtlInt32 m_Nanosecond; + + +#if defined(WIN32) || defined(_WIN32) + //typedef double TimeStampType; + //typedef double FrequencyType; + // + //FrequencyType m_WinFrequency; + //TimeStampType m_WinDifference; + //TimeStampType m_WinOrigin; + + time_t m_WinTimeOrigin; + clock_t m_WinClockOrigin; + +#endif + +}; + +} // end of namespace igtl + +#endif // __igtlTimeStamp_h + + diff --git a/openigtlink/repo/Source/igtlTrackingDataMessage.cxx b/openigtlink/repo/Source/igtlTrackingDataMessage.cxx new file mode 100644 index 0000000..440ba01 --- /dev/null +++ b/openigtlink/repo/Source/igtlTrackingDataMessage.cxx @@ -0,0 +1,388 @@ +/*========================================================================= + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + Copyright (c) Insight Software Consortium. All rights reserved. + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + =========================================================================*/ + +#include "igtlTrackingDataMessage.h" +#include "igtlMath.h" + +#include "igtl_header.h" +#include "igtl_tdata.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include +#include + +namespace igtl { + + +//---------------------------------------------------------------------- +// igtl::TrackingDataElement class + +TrackingDataElement::TrackingDataElement() : Object() +{ + this->m_Name = ""; + this->m_Type = TYPE_TRACKER; + IdentityMatrix(this->m_Matrix); +} + + +TrackingDataElement::~TrackingDataElement() +{ +} + + +int TrackingDataElement::SetName(const char* name) +{ + if (name != NULL && strlen(name) <= IGTL_TDATA_LEN_NAME) + { + this->m_Name = name; + return 1; + } + else + { + return 0; + } +} + + +int TrackingDataElement::SetType(igtlUint8 type) +{ + if(type == TYPE_TRACKER || + type == TYPE_6D || + type == TYPE_3D || + type == TYPE_5D) + { + this->m_Type = type; + return type; + } + else + { + return 0; + } +} + + +void TrackingDataElement::SetPosition(float p[3]) +{ + this->m_Matrix[0][3] = p[0]; + this->m_Matrix[1][3] = p[1]; + this->m_Matrix[2][3] = p[2]; +} + + +void TrackingDataElement::GetPosition(float p[3]) +{ + p[0] = this->m_Matrix[0][3]; + p[1] = this->m_Matrix[1][3]; + p[2] = this->m_Matrix[2][3]; +} + + +void TrackingDataElement::SetPosition(float px, float py, float pz) +{ + this->m_Matrix[0][3] = px; + this->m_Matrix[1][3] = py; + this->m_Matrix[2][3] = pz; +} + + +void TrackingDataElement::GetPosition(float* px, float* py, float* pz) +{ + *px = this->m_Matrix[0][3]; + *py = this->m_Matrix[1][3]; + *pz = this->m_Matrix[2][3]; +} + + +void TrackingDataElement::SetMatrix(Matrix4x4& mat) +{ + m_Matrix[0][0] = mat[0][0]; + m_Matrix[1][0] = mat[1][0]; + m_Matrix[2][0] = mat[2][0]; + m_Matrix[3][0] = mat[3][0]; + + m_Matrix[0][1] = mat[0][1]; + m_Matrix[1][1] = mat[1][1]; + m_Matrix[2][1] = mat[2][1]; + m_Matrix[3][1] = mat[3][1]; + + m_Matrix[0][2] = mat[0][2]; + m_Matrix[1][2] = mat[1][2]; + m_Matrix[2][2] = mat[2][2]; + m_Matrix[3][2] = mat[3][2]; + + m_Matrix[0][3] = mat[0][3]; + m_Matrix[1][3] = mat[1][3]; + m_Matrix[2][3] = mat[2][3]; + m_Matrix[3][3] = mat[3][3]; +} + + +void TrackingDataElement::GetMatrix(Matrix4x4& mat) +{ + mat[0][0] = m_Matrix[0][0]; + mat[1][0] = m_Matrix[1][0]; + mat[2][0] = m_Matrix[2][0]; + mat[3][0] = m_Matrix[3][0]; + + mat[0][1] = m_Matrix[0][1]; + mat[1][1] = m_Matrix[1][1]; + mat[2][1] = m_Matrix[2][1]; + mat[3][1] = m_Matrix[3][1]; + + mat[0][2] = m_Matrix[0][2]; + mat[1][2] = m_Matrix[1][2]; + mat[2][2] = m_Matrix[2][2]; + mat[3][2] = m_Matrix[3][2]; + + mat[0][3] = m_Matrix[0][3]; + mat[1][3] = m_Matrix[1][3]; + mat[2][3] = m_Matrix[2][3]; + mat[3][3] = m_Matrix[3][3]; +} + + +//---------------------------------------------------------------------- +// igtl::StartTrackingDataMessage class + +StartTrackingDataMessage::StartTrackingDataMessage() +{ + this->m_SendMessageType = "STT_TDATA"; + this->m_Resolution = 0; + this->m_CoordinateName = ""; +} + + +StartTrackingDataMessage::~StartTrackingDataMessage() +{ +} + + +int StartTrackingDataMessage::SetCoordinateName(const char* name) +{ + if (name != NULL && strlen(name) <= IGTL_STT_TDATA_LEN_COORDNAME) + { + this->m_CoordinateName = name; + return 1; + } + else + { + return 0; + } +} + + +igtlUint64 StartTrackingDataMessage::CalculateContentBufferSize() +{ + return IGTL_STT_TDATA_SIZE; +} + + +int StartTrackingDataMessage::PackContent() +{ + AllocateBuffer(); + igtl_stt_tdata* stt_tdata = NULL; + stt_tdata = (igtl_stt_tdata*)(this->m_Content); + + stt_tdata->resolution = this->m_Resolution; + strncpy(stt_tdata->coord_name, this->m_CoordinateName.c_str(), IGTL_STT_TDATA_LEN_COORDNAME); + + igtl_stt_tdata_convert_byte_order(stt_tdata); + + return 1; + +} + + +int StartTrackingDataMessage::UnpackContent() +{ + igtl_stt_tdata* stt_tdata = NULL; + stt_tdata = (igtl_stt_tdata*)(this->m_Content); + + igtl_stt_tdata_convert_byte_order(stt_tdata); + + this->m_Resolution = stt_tdata->resolution; + + char strbuf[IGTL_STT_TDATA_LEN_COORDNAME+1]; + strbuf[IGTL_STT_TDATA_LEN_COORDNAME] = '\n'; + strncpy(strbuf, stt_tdata->coord_name, IGTL_STT_TDATA_LEN_COORDNAME); + + this->SetCoordinateName(strbuf); + + return 1; + +} + + +//---------------------------------------------------------------------- +// igtl::RTSTrackingDataMessage class + +igtlUint64 RTSTrackingDataMessage::CalculateContentBufferSize() +{ + return IGTL_RTS_TDATA_SIZE; +} + +int RTSTrackingDataMessage::PackContent() +{ + AllocateBuffer(); + igtl_rts_tdata* rts_tdata = NULL; + rts_tdata = (igtl_rts_tdata*)this->m_Content; + + rts_tdata->status = this->m_Status; + + igtl_rts_tdata_convert_byte_order(rts_tdata); + + return 1; +} + + +int RTSTrackingDataMessage::UnpackContent() +{ + igtl_rts_tdata* rts_tdata = NULL; + rts_tdata = (igtl_rts_tdata*)this->m_Content; + + igtl_rts_tdata_convert_byte_order(rts_tdata); + + this->m_Status= rts_tdata->status; + + return 1; +} + +//---------------------------------------------------------------------- +// igtl::TrackingDataMessage class + +TrackingDataMessage::TrackingDataMessage() +{ + this->m_SendMessageType = "TDATA"; + this->m_TrackingDataList.clear(); +} + + +TrackingDataMessage::~TrackingDataMessage() +{ +} + + +int TrackingDataMessage::AddTrackingDataElement(TrackingDataElement::Pointer& elem) +{ + m_IsBodyPacked = false; + this->m_TrackingDataList.push_back(elem); + return this->m_TrackingDataList.size(); +} + + +void TrackingDataMessage::ClearTrackingDataElements() +{ + this->m_TrackingDataList.clear(); +} + + +int TrackingDataMessage::GetNumberOfTrackingDataElements() +{ + return this->m_TrackingDataList.size(); +} + + +void TrackingDataMessage::GetTrackingDataElement(int index, TrackingDataElement::Pointer& elem) +{ + if (index >= 0 && index < (int)this->m_TrackingDataList.size()) + { + elem = this->m_TrackingDataList[index]; + } +} + + +igtlUint64 TrackingDataMessage::CalculateContentBufferSize() +{ + // The body size sum of the header size and status message size. + return IGTL_TDATA_ELEMENT_SIZE * this->m_TrackingDataList.size(); +} + + +int TrackingDataMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + igtl_tdata_element* element = NULL; + element = (igtl_tdata_element*)(this->m_Content); + + igtl_tdata_element * elementHolder = element; + std::vector::iterator iter; + + for (iter = this->m_TrackingDataList.begin(); iter != this->m_TrackingDataList.end(); iter ++) + { + strncpy((char*)element->name, (*iter)->GetName(), IGTL_TDATA_LEN_NAME); + element->type = (*iter)->GetType(); + element->reserved = 0; + Matrix4x4 matrix; + (*iter)->GetMatrix(matrix); + for (int i = 0; i < 3; i ++) + { + element->transform[i] = matrix[i][0]; + element->transform[i+3] = matrix[i][1]; + element->transform[i+6] = matrix[i][2]; + element->transform[i+9] = matrix[i][3]; + } + element ++; + } + + igtl_tdata_convert_byte_order(elementHolder, this->m_TrackingDataList.size()); + + return 1; +} + + +int TrackingDataMessage::UnpackContent() +{ + + this->m_TrackingDataList.clear(); + + igtl_tdata_element* element = NULL; + int nElement = 0; + + element = (igtl_tdata_element*)(this->m_Content); + bool isUnpacked(true); + nElement = igtl_tdata_get_data_n(CalculateReceiveContentSize(isUnpacked)); + + igtl_tdata_convert_byte_order(element, nElement); + + char strbuf[128]; + for (int i = 0; i < nElement; i ++) + { + TrackingDataElement::Pointer elemClass = TrackingDataElement::New(); + + // Add '\n' at the end of each string + // (neccesary for a case, where a string reaches the maximum length.) + strbuf[IGTL_TDATA_LEN_NAME] = '\n'; + strncpy(strbuf, (char*)element->name, IGTL_TDATA_LEN_NAME); + elemClass->SetName((const char*)strbuf); + elemClass->SetType(element->type); + + Matrix4x4 matrix; + IdentityMatrix(matrix); + for (int j = 0; j < 3; j ++) + { + matrix[j][0] = element->transform[j]; + matrix[j][1] = element->transform[j+3]; + matrix[j][2] = element->transform[j+6]; + matrix[j][3] = element->transform[j+9]; + } + elemClass->SetMatrix(matrix); + + this->m_TrackingDataList.push_back(elemClass); + + element ++; + } + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlTrackingDataMessage.h b/openigtlink/repo/Source/igtlTrackingDataMessage.h new file mode 100644 index 0000000..0c6e1f1 --- /dev/null +++ b/openigtlink/repo/Source/igtlTrackingDataMessage.h @@ -0,0 +1,237 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlTrackingDataMessage_h +#define __igtlTrackingDataMessage_h + +#include +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + + +namespace igtl +{ + +class IGTLCommon_EXPORT TrackingDataElement: public Object +{ +public: + igtlTypeMacro(igtl::TrackingDataElement, igtl::Object); + igtlNewMacro(igtl::TrackingDataElement); + + /// Tracking data type. + /// TYPE_TRACKER: Tracker + /// TYPE_6D: 6D instrument: (regular instrument) + /// TYPE_3D: 3D instrument (only tip of the instrument defined) + /// TYPE_5D: 5D instrument (tip and handle are defined, but not the normal vector) + enum { + TYPE_TRACKER = 1, + TYPE_6D = 2, + TYPE_3D = 3, + TYPE_5D = 4, + }; + +public: + + /// Sets the name of the instrument/tracker. + int SetName(const char* name); + + /// Gets the name of the instrument/tracker. + const char* GetName() { return this->m_Name.c_str(); }; + + /// Sets the type of the instrument/tracker. + int SetType(igtlUint8 type); + + /// Gets the type of the instrument/tracker. + igtlUint8 GetType() { return this->m_Type; }; + + /// Sets the position by 3-element array of x, y, and z coordinates. + void SetPosition(float p[3]); + + /// Gets the position. The function substitutes 3-element array of x, y and z coordinates in 'p'. + void GetPosition(float p[3]); + + /// Sets the position by x, y, and z coordinates. + void SetPosition(float px, float py, float pz); + + /// Gets the position. The function substitutes the xyz coordinates in 'px', 'py', and 'pz'. + void GetPosition(float* px, float* py, float* pz); + + /// Sets the 4-by-4 transformation matrix. + void SetMatrix(Matrix4x4& mat); + + /// Gets the 4-by-4 transformation matrix. + void GetMatrix(Matrix4x4& mat); + +protected: + TrackingDataElement(); + ~TrackingDataElement(); + +protected: + + /// Name / description (< 20 bytes + std::string m_Name; + + /// Tracking data type (TYPE_TRACKER, TYPE_6D, TYPE_3D, TYPE_5D) + igtlUint8 m_Type; + + /// Transform matrix + Matrix4x4 m_Matrix; +}; + + +/// A class for the STT_TDATA message type. +class IGTLCommon_EXPORT StartTrackingDataMessage: public MessageBase +{ + +public: + igtlTypeMacro(igtl::StartTrackingDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::StartTrackingDataMessage); + +public: + /// Sets the time resolution for streaming of QTDATA messages + void SetResolution(igtlInt32 res) { this->m_Resolution = res; }; // ms + + /// Gets the time resolution for streaming of QTDATA messages + igtlInt32 GetResolution() { return this->m_Resolution; }; + + /// Sets the name of the coordinate system. The name must be defined by the user. + int SetCoordinateName(const char* name); + + /// Gets the name of the coordinate system. + const char* GetCoordinateName() { return this->m_CoordinateName.c_str(); }; + +protected: + StartTrackingDataMessage(); + ~StartTrackingDataMessage(); + +protected: + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + +protected: + + /// Minimum time between two frames (ms). Use 0 for as fast as possible. + igtlInt32 m_Resolution; + + /// Name of the coordinate system. + std::string m_CoordinateName; + +}; + + +/// A class for the STP_TDATA message type. +class IGTLCommon_EXPORT StopTrackingDataMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::StopTrackingDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::StopTrackingDataMessage); + +protected: + StopTrackingDataMessage() : MessageBase() { this->m_SendMessageType = "STP_TDATA"; }; + ~StopTrackingDataMessage() {}; + +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; + +}; + + +/// A class for the RTS_TDATA message type. +class IGTLCommon_EXPORT RTSTrackingDataMessage: public MessageBase +{ +public: + /// Status type + enum { + STATUS_SUCCESS = 0, + STATUS_ERROR = 1 + }; + + igtlTypeMacro(igtl::RTSTrackingDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::RTSTrackingDataMessage); + + /// Sets the status. 'status' must be either STATUS_SUCCESS or STATUS_ERROR. + void SetStatus(igtlUint8 status){ this->m_Status = status; } + + /// Gets the status. The function returns either STATUS_SUCCESS or STATUS_ERROR. + igtlUint8 GetStatus() { return this->m_Status; }; + +protected: + RTSTrackingDataMessage() : MessageBase(), m_Status(0) { this->m_SendMessageType = "RTS_TDATA"; }; + ~RTSTrackingDataMessage() {}; + + /// A variable to store the status. + igtlUint8 m_Status; + +protected: + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + +}; + + +/// The TDATA message type is intended for transferring 3D positions of surgical tools, +/// markers etc. Those positions are often measured by optical, electromagnetic or other +/// type of 3D position sensor continuously and transferred as series of messages. +/// Since it is important for software that receives TDATA to control data flow, +/// STT_TDATA query data type has interval field to control the frame rate of consecutive messages. +class IGTLCommon_EXPORT TrackingDataMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::TrackingDataMessage, igtl::MessageBase); + igtlNewMacro(igtl::TrackingDataMessage); + +public: + + /// Adds tracking data element. + int AddTrackingDataElement(TrackingDataElement::Pointer& elem); + + /// Clears the all tracking data element in the list. + void ClearTrackingDataElements(); + + /// Gets the number of tracking data elements in the list. + int GetNumberOfTrackingDataElements(); + + inline int GetNumberOfTrackingDataElement() { return GetNumberOfTrackingDataElements(); }; // will be removed. + + /// Gets the tracking data element specified by 'index'. + void GetTrackingDataElement(int index, TrackingDataElement::Pointer& elem); + + +protected: + TrackingDataMessage(); + ~TrackingDataMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// The list of tracking data elements. + std::vector m_TrackingDataList; + +}; + + +} // namespace igtl + +#endif // _igtlTrackingDataMessage_h diff --git a/openigtlink/repo/Source/igtlTrajectoryMessage.cxx b/openigtlink/repo/Source/igtlTrajectoryMessage.cxx new file mode 100644 index 0000000..49b29c6 --- /dev/null +++ b/openigtlink/repo/Source/igtlTrajectoryMessage.cxx @@ -0,0 +1,370 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlTrajectoryMessage.h" + +#include "igtl_header.h" +#include "igtl_trajectory.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +#include +#include + +namespace igtl { + + +//---------------------------------------------------------------------- +// igtl::TrajectoryElement class + +TrajectoryElement::TrajectoryElement() : Object() +{ + this->m_Name = ""; + this->m_GroupName = ""; + this->m_Type = TYPE_TARGET_ONLY; + this->m_RGBA[0] = 0; + this->m_RGBA[1] = 0; + this->m_RGBA[2] = 0; + this->m_RGBA[3] = 0; + this->m_EntryPosition[0] = 0.0; + this->m_EntryPosition[1] = 0.0; + this->m_EntryPosition[2] = 0.0; + this->m_TargetPosition[0] = 0.0; + this->m_TargetPosition[1] = 0.0; + this->m_TargetPosition[2] = 0.0; + this->m_Radius = 0.0; + this->m_Owner = ""; +} + + +TrajectoryElement::~TrajectoryElement() +{ +} + + +int TrajectoryElement::SetName(const char* name) +{ + if (name != NULL && strlen(name) <= IGTL_TRAJECTORY_LEN_NAME) + { + this->m_Name = name; + return 1; + } + else + { + return 0; + } +} + + +int TrajectoryElement::SetGroupName(const char* grpname) +{ + if (grpname != NULL && strlen(grpname) <= IGTL_TRAJECTORY_LEN_GROUP_NAME) + { + this->m_GroupName = grpname; + return 1; + } + else + { + return 0; + } +} + + +int TrajectoryElement::SetType(igtlUint8 type) +{ + if (type == TYPE_ENTRY_ONLY|| + type == TYPE_TARGET_ONLY|| + TYPE_ENTRY_TARGET) + { + this->m_Type = type; + return 1; + } + else + { + return 0; + } +} + + +void TrajectoryElement::SetRGBA(igtlUint8 rgba[4]) +{ + this->m_RGBA[0] = rgba[0]; + this->m_RGBA[1] = rgba[1]; + this->m_RGBA[2] = rgba[2]; + this->m_RGBA[3] = rgba[3]; +} + + +void TrajectoryElement::SetRGBA(igtlUint8 r, igtlUint8 g, igtlUint8 b, igtlUint8 a) +{ + this->m_RGBA[0] = r; + this->m_RGBA[1] = g; + this->m_RGBA[2] = b; + this->m_RGBA[3] = a; +} + + +void TrajectoryElement::GetRGBA(igtlUint8* rgba) +{ + rgba[0] = this->m_RGBA[0]; + rgba[1] = this->m_RGBA[1]; + rgba[2] = this->m_RGBA[2]; + rgba[3] = this->m_RGBA[3]; +} + + + +void TrajectoryElement::GetRGBA(igtlUint8& r, igtlUint8& g, igtlUint8& b, igtlUint8& a) +{ + r = this->m_RGBA[0]; + g = this->m_RGBA[1]; + b = this->m_RGBA[2]; + a = this->m_RGBA[3]; +} + +void TrajectoryElement::SetEntryPosition(igtlFloat32 position[3]) +{ + this->m_EntryPosition[0] = position[0]; + this->m_EntryPosition[1] = position[1]; + this->m_EntryPosition[2] = position[2]; +} + + +void TrajectoryElement::SetEntryPosition(igtlFloat32 x, igtlFloat32 y, igtlFloat32 z) +{ + this->m_EntryPosition[0] = x; + this->m_EntryPosition[1] = y; + this->m_EntryPosition[2] = z; +} + + +void TrajectoryElement::GetEntryPosition(igtlFloat32* position) +{ + position[0] = this->m_EntryPosition[0]; + position[1] = this->m_EntryPosition[1]; + position[2] = this->m_EntryPosition[2]; +} + + +void TrajectoryElement::GetEntryPosition(igtlFloat32& x, igtlFloat32& y, igtlFloat32& z) +{ + x = this->m_EntryPosition[0]; + y = this->m_EntryPosition[1]; + z = this->m_EntryPosition[2]; +} + + +void TrajectoryElement::SetTargetPosition(igtlFloat32 position[3]) +{ + this->m_TargetPosition[0] = position[0]; + this->m_TargetPosition[1] = position[1]; + this->m_TargetPosition[2] = position[2]; +} + + +void TrajectoryElement::SetTargetPosition(igtlFloat32 x, igtlFloat32 y, igtlFloat32 z) +{ + this->m_TargetPosition[0] = x; + this->m_TargetPosition[1] = y; + this->m_TargetPosition[2] = z; +} + + +void TrajectoryElement::GetTargetPosition(igtlFloat32* position) +{ + position[0] = this->m_TargetPosition[0]; + position[1] = this->m_TargetPosition[1]; + position[2] = this->m_TargetPosition[2]; +} + + +void TrajectoryElement::GetTargetPosition(igtlFloat32& x, igtlFloat32& y, igtlFloat32& z) +{ + x = this->m_TargetPosition[0]; + y = this->m_TargetPosition[1]; + z = this->m_TargetPosition[2]; +} + + +int TrajectoryElement::SetOwner(const char* owner) +{ + if (strlen(owner) <= IGTL_TRAJECTORY_LEN_OWNER) + { + this->m_Owner = owner; + return 1; + } + else + { + return 0; + } +} + + +//---------------------------------------------------------------------- +// igtl::TrajectoryMessage class +TrajectoryMessage::TrajectoryMessage() +{ + this->m_SendMessageType = "TRAJ"; + this->m_TrajectoryList.clear(); +} + + +TrajectoryMessage::~TrajectoryMessage() +{ +} + + +int TrajectoryMessage::AddTrajectoryElement(TrajectoryElement::Pointer& elem) +{ + m_IsBodyPacked = false; + this->m_TrajectoryList.push_back(elem); + return this->m_TrajectoryList.size(); +} + + +void TrajectoryMessage::ClearTrajectoryElement(TrajectoryElement::Pointer& elem) +{ + igtlLegacyReplaceBodyMacro(TrajectoryMessage::ClearTrajectoryElement, 3.0, TrajectoryMessage::ClearAllTrajectoryElements); + (void)(elem); // Unused variable + this->m_TrajectoryList.clear(); +} + + +void TrajectoryMessage::ClearAllTrajectoryElements() +{ + this->m_TrajectoryList.clear(); +} + +int TrajectoryMessage::GetNumberOfTrajectoryElement() +{ + return this->m_TrajectoryList.size(); +} + + +void TrajectoryMessage::GetTrajectoryElement(int index, TrajectoryElement::Pointer& elem) +{ + if (index >= 0 && index < (int)this->m_TrajectoryList.size()) + { + elem = this->m_TrajectoryList[index]; + } +} + + +igtlUint64 TrajectoryMessage::CalculateContentBufferSize() +{ + return IGTL_TRAJECTORY_ELEMENT_SIZE * this->m_TrajectoryList.size(); +} + + +int TrajectoryMessage::PackContent() +{ + // Allocate buffer + AllocateBuffer(); + + igtl_trajectory_element* element = NULL; + element = (igtl_trajectory_element*)(this->m_Content); + + igtl_trajectory_element * elementHolder = element; + std::vector::iterator iter; + for (iter = this->m_TrajectoryList.begin(); iter != this->m_TrajectoryList.end(); iter ++) + { + strncpy((char*)element->name, (*iter)->GetName(), IGTL_TRAJECTORY_LEN_NAME); + strncpy((char*)element->group_name, (*iter)->GetGroupName(), IGTL_TRAJECTORY_LEN_GROUP_NAME); + + element->type = (*iter)->GetType(); + element->reserved = 0; + igtlUint8 rgba[4]; + (*iter)->GetRGBA(rgba); + element->rgba[0] = rgba[0]; + element->rgba[1] = rgba[1]; + element->rgba[2] = rgba[2]; + element->rgba[3] = rgba[3]; + + igtlFloat32 position[3]; + (*iter)->GetEntryPosition(position); + element->entry_pos[0] = position[0]; + element->entry_pos[1] = position[1]; + element->entry_pos[2] = position[2]; + + (*iter)->GetTargetPosition(position); + element->target_pos[0] = position[0]; + element->target_pos[1] = position[1]; + element->target_pos[2] = position[2]; + + element->radius = (*iter)->GetRadius(); + + strncpy((char*)element->owner_name, (*iter)->GetOwner(), IGTL_TRAJECTORY_LEN_OWNER); + + element ++; + } + + igtl_trajectory_convert_byte_order(elementHolder, this->m_TrajectoryList.size()); + + return 1; +} + + +int TrajectoryMessage::UnpackContent() +{ + this->m_TrajectoryList.clear(); + + igtl_trajectory_element* element = NULL; + int nElement = 0; +#if OpenIGTLink_HEADER_VERSION >= 2 + element = (igtl_trajectory_element*)(this->m_Content); + bool isUnpacked(true); + nElement = igtl_trajectory_get_data_n(CalculateReceiveContentSize(isUnpacked)); +#elif OpenIGTLink_PROTOCOL_VERSION <=2 + element = (igtl_trajectory_element*)this->m_Body; + nElement = igtl_trajectory_get_data_n(this->m_BodySizeToRead); +#endif + + igtl_trajectory_convert_byte_order(element, nElement); + + char strbuf[128]; + for (int i = 0; i < nElement; i ++) + { + TrajectoryElement::Pointer elemClass = TrajectoryElement::New(); + + // Add '\n' at the end of each string + // (necessary for a case, where a string reaches the maximum length.) + strbuf[IGTL_TRAJECTORY_LEN_NAME] = '\n'; + strncpy(strbuf, (char*)element->name, IGTL_TRAJECTORY_LEN_NAME); + elemClass->SetName((const char*)strbuf); + + strbuf[IGTL_TRAJECTORY_LEN_GROUP_NAME] = '\n'; + strncpy(strbuf, (char*)element->group_name, IGTL_TRAJECTORY_LEN_GROUP_NAME); + elemClass->SetGroupName(strbuf); + + elemClass->SetType(element->type); + + elemClass->SetRGBA(element->rgba); + elemClass->SetEntryPosition(element->entry_pos); + elemClass->SetTargetPosition(element->target_pos); + elemClass->SetRadius(element->radius); + + strbuf[IGTL_TRAJECTORY_LEN_OWNER] = '\n'; + strncpy(strbuf, (char*)element->owner_name, IGTL_TRAJECTORY_LEN_OWNER); + elemClass->SetOwner(strbuf); + + this->m_TrajectoryList.push_back(elemClass); + + element ++; + } + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlTrajectoryMessage.h b/openigtlink/repo/Source/igtlTrajectoryMessage.h new file mode 100644 index 0000000..486bd94 --- /dev/null +++ b/openigtlink/repo/Source/igtlTrajectoryMessage.h @@ -0,0 +1,205 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlTrajectoryMessage_h +#define __igtlTrajectoryMessage_h + +#include +#include + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" +#include "igtlTypes.h" + +#include "igtlImageMessage.h" + +namespace igtl +{ + +/// TrajectoryElement class is used to manage a trajectory in TrajectoryMessage class. +class IGTLCommon_EXPORT TrajectoryElement: public Object +{ +public: + igtlTypeMacro(igtl::TrajectoryElement, igtl::Object); + igtlNewMacro(igtl::TrajectoryElement); + + /// Types of trajectory. + enum { + TYPE_ENTRY_ONLY = 1, /* Trajectory with only entry point */ + TYPE_TARGET_ONLY = 2, /* Trajectory with only target point */ + TYPE_ENTRY_TARGET = 3, /* Trajectory with entry and target point */ + }; + +public: + + /// Sets the name of the trajectory. + int SetName(const char* name); + + /// Gets the name of the trajectory. + const char* GetName() { return this->m_Name.c_str(); }; + + /// Sets the group name e.g. "Trajectory" + int SetGroupName(const char* grpname); + + /// Gets the group name. + const char* GetGroupName() { return this->m_GroupName.c_str(); }; + + /// Sets the trajectory type. 'type' must be either TYPE_ENTRY_ONLY, TYPE_TARGET_ONLY, or TYPE_ENTRY_TARGET. + int SetType(igtlUint8 type); + /// Gets the trajectory type. The returned value is either TYPE_ENTRY_ONLY, TYPE_TARGET_ONLY, or TYPE_ENTRY_TARGET. + igtlUint8 GetType() { return this->m_Type; }; + + /// Sets the color of the trajectory using an array of r, g, b and alpha. + void SetRGBA(igtlUint8 rgba[4]); + + /// Sets the color of the trajectory by r, g, b and alpha. + void SetRGBA(igtlUint8 r, igtlUint8 g, igtlUint8 b, igtlUint8 a); + + /// Gets the color of the trajectory. An array of r, g, b and alpha is stored in 'rgba' + void GetRGBA(igtlUint8* rgba); + + /// Gets the color of the trajectory. + void GetRGBA(igtlUint8& r, igtlUint8& g, igtlUint8& b, igtlUint8& a); + + /// Sets the entry position using an array. + void SetEntryPosition(igtlFloat32 position[3]); + + /// Sets the entry position. + void SetEntryPosition(igtlFloat32 x, igtlFloat32 y, igtlFloat32 z); + + /// Sets the entry position using an array of x, y, and z coordinates. + void GetEntryPosition(igtlFloat32* position); + + /// Gets the entry position. + void GetEntryPosition(igtlFloat32& x, igtlFloat32& y, igtlFloat32& z); + + /// Sets the target position using an array of x, y, and z coordinates. + void SetTargetPosition(igtlFloat32 position[3]); + + /// Sets the target position. + void SetTargetPosition(igtlFloat32 x, igtlFloat32 y, igtlFloat32 z); + + /// Gets the target position. Stores an array of x, y, and z coordinates in 'position' + void GetTargetPosition(igtlFloat32* position); + + /// Gets the target position. + void GetTargetPosition(igtlFloat32& x, igtlFloat32& y, igtlFloat32& z); + + /// Sets the radius. + void SetRadius(igtlFloat32 radius) { this->m_Radius = radius; }; + + /// Gets the radius. + igtlFloat32 GetRadius() { return this->m_Radius; }; + + /// Sets the owner of the trajectory. 'owner' must be a name of image. + int SetOwner(const char* owner); + + /// Gets the owner of the trajectory. + const char* GetOwner() { return this->m_Owner.c_str(); }; + +protected: + TrajectoryElement(); + ~TrajectoryElement(); + +protected: + + /// name / description (< 64 bytes) + std::string m_Name; + + /// Can be "Labeled Trajectory", "Landmark", Fiducial", ... + std::string m_GroupName; + + /// Trajectory type (see TYPE_* constants) + igtlUint8 m_Type; + + /// Color in R/G/B/A + igtlUint8 m_RGBA[4]; + + /// Coordinate of the entry point + igtlFloat32 m_EntryPosition[3]; + + /// Coordinate of the target point + igtlFloat32 m_TargetPosition[3]; + + /// Radius of the trajectory. Can be 0. + igtlFloat32 m_Radius; + + /// Device name of the ower image. + std::string m_Owner; +}; + + +/// A class for the GET_TRAJ message type. +class IGTLCommon_EXPORT GetTrajectoryMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::GetTrajectoryMessage, igtl::MessageBase); + igtlNewMacro(igtl::GetTrajectoryMessage); + +protected: + GetTrajectoryMessage() : MessageBase() { this->m_SendMessageType = "GET_TRAJ"; }; + ~GetTrajectoryMessage() {}; +protected: + igtlUint64 CalculateContentBufferSize() override { return 0; }; + int PackContent() override { AllocateBuffer(); return 1; }; + int UnpackContent() override { return 1; }; +}; + + +/// The TRAJECTORY message type support to transfer information about 3D trajectory, +/// which is often used in surgical planning and guidance in image-guided therapy. +class IGTLCommon_EXPORT TrajectoryMessage: public MessageBase +{ +public: + igtlTypeMacro(igtl::TrajectoryMessage, igtl::MessageBase); + igtlNewMacro(igtl::TrajectoryMessage); + +public: + + /// Adds a trajectory to the list. + int AddTrajectoryElement(TrajectoryElement::Pointer& elem); + + /// Clears the all trajectory from the list. + igtlLegacyMacro( + void ClearTrajectoryElement(TrajectoryElement::Pointer& elem)); + + /// Clears all trajectory elements from the list. + void ClearAllTrajectoryElements(); + + /// Gets the number of trajectory in the list. + int GetNumberOfTrajectoryElement(); + + /// Gets the trajectory specified by 'index'. + void GetTrajectoryElement(int index, TrajectoryElement::Pointer& elem); + + +protected: + TrajectoryMessage(); + ~TrajectoryMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// A list of pointers to the trajectories. + std::vector m_TrajectoryList; + +}; + +} // namespace igtl + +#endif // _igtlTrajectoryMessage_h diff --git a/openigtlink/repo/Source/igtlTransformMessage.cxx b/openigtlink/repo/Source/igtlTransformMessage.cxx new file mode 100644 index 0000000..56220d1 --- /dev/null +++ b/openigtlink/repo/Source/igtlTransformMessage.cxx @@ -0,0 +1,269 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlTransformMessage.h" + +#include "igtl_header.h" +#include "igtl_transform.h" + +#include + +namespace igtl { + + +TransformMessage::TransformMessage() + : MessageBase() +{ + m_Transform = m_Content; + + matrix[0][0] = 1.0; + matrix[1][0] = 0.0; + matrix[2][0] = 0.0; + matrix[3][0] = 0.0; + + matrix[0][1] = 0.0; + matrix[1][1] = 1.0; + matrix[2][1] = 0.0; + matrix[3][1] = 0.0; + + matrix[0][2] = 0.0; + matrix[1][2] = 0.0; + matrix[2][2] = 1.0; + matrix[3][2] = 0.0; + + matrix[0][3] = 0.0; + matrix[1][3] = 0.0; + matrix[2][3] = 0.0; + matrix[3][3] = 1.0; + + m_SendMessageType = "TRANSFORM"; + +} + +TransformMessage::~TransformMessage() +{ +} + +void TransformMessage::SetPosition(float p[3]) +{ + m_IsBodyPacked = false; + matrix[0][3] = p[0]; + matrix[1][3] = p[1]; + matrix[2][3] = p[2]; +} + +void TransformMessage::GetPosition(float p[3]) +{ + p[0] = matrix[0][3]; + p[1] = matrix[1][3]; + p[2] = matrix[2][3]; +} + + +void TransformMessage::SetPosition(float px, float py, float pz) +{ + m_IsBodyPacked = false; + matrix[0][3] = px; + matrix[1][3] = py; + matrix[2][3] = pz; +} + +void TransformMessage::GetPosition(float* px, float* py, float* pz) +{ + *px = matrix[0][3]; + *py = matrix[1][3]; + *pz = matrix[2][3]; +} + +void TransformMessage::SetNormals(float o[3][3]) +{ + m_IsBodyPacked = false; + matrix[0][0] = o[0][0]; + matrix[0][1] = o[0][1]; + matrix[0][2] = o[0][2]; + matrix[1][0] = o[1][0]; + matrix[1][1] = o[1][1]; + matrix[1][2] = o[1][2]; + matrix[2][0] = o[2][0]; + matrix[2][1] = o[2][1]; + matrix[2][2] = o[2][2]; +} + +void TransformMessage::GetNormals(float o[3][3]) +{ + o[0][0] = matrix[0][0]; + o[0][1] = matrix[0][1]; + o[0][2] = matrix[0][2]; + o[1][0] = matrix[1][0]; + o[1][1] = matrix[1][1]; + o[1][2] = matrix[1][2]; + o[2][0] = matrix[2][0]; + o[2][1] = matrix[2][1]; + o[2][2] = matrix[2][2]; +} + +void TransformMessage::SetNormals(float t[3], float s[3], float n[3]) +{ + m_IsBodyPacked = false; + matrix[0][0] = t[0]; + matrix[1][0] = t[1]; + matrix[2][0] = t[2]; + matrix[0][1] = s[0]; + matrix[1][1] = s[1]; + matrix[2][1] = s[2]; + matrix[0][2] = n[0]; + matrix[1][2] = n[1]; + matrix[2][2] = n[2]; +} + +void TransformMessage::GetNormals(float t[3], float s[3], float n[3]) +{ + t[0] = matrix[0][0]; + t[1] = matrix[1][0]; + t[2] = matrix[2][0]; + s[0] = matrix[0][1]; + s[1] = matrix[1][1]; + s[2] = matrix[2][1]; + n[0] = matrix[0][2]; + n[1] = matrix[1][2]; + n[2] = matrix[2][2]; +} + +void TransformMessage::SetMatrix(Matrix4x4& mat) +{ + m_IsBodyPacked = false; + matrix[0][0] = mat[0][0]; + matrix[1][0] = mat[1][0]; + matrix[2][0] = mat[2][0]; + matrix[3][0] = mat[3][0]; + + matrix[0][1] = mat[0][1]; + matrix[1][1] = mat[1][1]; + matrix[2][1] = mat[2][1]; + matrix[3][1] = mat[3][1]; + + matrix[0][2] = mat[0][2]; + matrix[1][2] = mat[1][2]; + matrix[2][2] = mat[2][2]; + matrix[3][2] = mat[3][2]; + + matrix[0][3] = mat[0][3]; + matrix[1][3] = mat[1][3]; + matrix[2][3] = mat[2][3]; + matrix[3][3] = mat[3][3]; +} + +void TransformMessage::GetMatrix(Matrix4x4& mat) +{ + mat[0][0] = matrix[0][0]; + mat[1][0] = matrix[1][0]; + mat[2][0] = matrix[2][0]; + mat[3][0] = matrix[3][0]; + + mat[0][1] = matrix[0][1]; + mat[1][1] = matrix[1][1]; + mat[2][1] = matrix[2][1]; + mat[3][1] = matrix[3][1]; + + mat[0][2] = matrix[0][2]; + mat[1][2] = matrix[1][2]; + mat[2][2] = matrix[2][2]; + mat[3][2] = matrix[3][2]; + + mat[0][3] = matrix[0][3]; + mat[1][3] = matrix[1][3]; + mat[2][3] = matrix[2][3]; + mat[3][3] = matrix[3][3]; +} + +igtlUint64 TransformMessage::CalculateContentBufferSize() +{ + return IGTL_TRANSFORM_SIZE; +} + +int TransformMessage::PackContent() +{ + AllocateBuffer(); + + // The m_Transform is not aligned with m_Body, when allocatePack() is called. + // This is to realign the two pointers. +#if OpenIGTLink_HEADER_VERSION >= 2 + this->m_Transform = this->m_Content; +#else + this->m_Transform = m_Body; +#endif + //igtl_float32* transform = (igtl_float32*)this->m_Transform; // doesn't work on Solaris + igtl_float32 transform[12]; + + for (int i = 0; i < 3; i ++) { + transform[i] = matrix[i][0]; + transform[i+3] = matrix[i][1]; + transform[i+6] = matrix[i][2]; + transform[i+9] = matrix[i][3]; + } + + igtl_transform_convert_byte_order(transform); +#if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + memcpy((void*)(this->m_Transform), (void*)transform, sizeof(igtl_float32)*12); + } + else + { + memcpy((void*)this->m_Transform, (void*)transform, sizeof(igtl_float32)*12); + } +#elif OpenIGTLink_PROTOCOL_VERSION <= 2 + memcpy((void*)this->m_Transform, (void*)transform, sizeof(igtl_float32)*12); +#endif + + return 1; +} + +int TransformMessage::UnpackContent() +{ + this->m_Transform = this->m_Content; + + //igtl_float32* transform = (igtl_float32*)this->m_Transform; // doesn't work on Solaris + igtl_float32 transform[12]; +#if OpenIGTLink_HEADER_VERSION >= 2 + if (m_HeaderVersion == IGTL_HEADER_VERSION_2) + { + memcpy((void*)transform, (void*)(this->m_Transform), sizeof(igtl_float32)*12); + } + else + { + memcpy((void*)transform, (void*)this->m_Transform, sizeof(igtl_float32)*12); + } +#elif OpenIGTLink_PROTOCOL_VERSION <= 2 + memcpy((void*)transform, (void*)this->m_Transform, sizeof(igtl_float32)*12); +#endif + + igtl_transform_convert_byte_order(transform); + + for (int i = 0; i < 3; i ++) { + matrix[i][0] = transform[i] ; + matrix[i][1] = transform[i+3]; + matrix[i][2] = transform[i+6]; + matrix[i][3] = transform[i+9]; + } + + matrix[3][0] = 0.0; + matrix[3][1] = 0.0; + matrix[3][2] = 0.0; + matrix[3][3] = 1.0; + + return 1; +} + +} // namespace igtl diff --git a/openigtlink/repo/Source/igtlTransformMessage.h b/openigtlink/repo/Source/igtlTransformMessage.h new file mode 100644 index 0000000..ea927dc --- /dev/null +++ b/openigtlink/repo/Source/igtlTransformMessage.h @@ -0,0 +1,109 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlTransformMessage_h +#define __igtlTransformMessage_h + +#include "igtlObject.h" +#include "igtlMath.h" +#include "igtlMessageBase.h" + +namespace igtl +{ + +/// A class for the GET_TRANS message type. +class IGTLCommon_EXPORT GetTransformMessage: public HeaderOnlyMessageBase +{ +public: + igtlTypeMacro(igtl::GetTransformMessage, igtl::HeaderOnlyMessageBase); + igtlNewMacro(igtl::GetTransformMessage); + +protected: + GetTransformMessage() : HeaderOnlyMessageBase() { this->m_SendMessageType = "GET_TRANS"; }; + ~GetTransformMessage() {}; +}; + + + +/// The TRANSFORM data type is used to transfer a homogeneous linear transformation +/// in 4-by-4 matrix form. One such matrix was shown earlier in equation (1). +/// Note that if a device is sending only translation and rotation, then TRANSFORM +/// is equivalent to POSITION. But TRANSFORM can also be used to transfer affine +/// transformations or simple scaling. Like IMAGE and POSITION, TRANSFORM carries +/// information about the coordinate system used. +class IGTLCommon_EXPORT TransformMessage: public MessageBase +{ + +public: + igtlTypeMacro(igtl::TransformMessage, igtl::MessageBase); + igtlNewMacro(igtl::TransformMessage); + +public: + + /// Sets a position (or a translation vector) in the RAS coordinate system. + void SetPosition(float p[3]); + + /// Gets a position (or a translation vector) in the RAS coordinate system. + void GetPosition(float p[3]); + + /// Sets a position (or a translation vector) in the RAS coordinate system. + void SetPosition(float px, float py, float pz); + + /// Gets a position (or a translation vector) in the RAS coordinate system. + void GetPosition(float* px, float* py, float* pz); + + /// Sets normal vectors (or a rotation matrix) in the RAS coordinate system. + void SetNormals(float o[3][3]); + + /// Gets normal vectors (or a rotation matrix) in the RAS coordinate system. + void GetNormals(float o[3][3]); + + /// Sets normal vectors (or a rotation matrix) in the RAS coordinate system. + void SetNormals(float t[3], float s[3], float n[3]); + + /// Gets normal vectors (or a rotation matrix) in the RAS coordinate system. + void GetNormals(float t[3], float s[3], float n[3]); + + /// Sets rotation matrix using igtl::Matrix4x4. + void SetMatrix(Matrix4x4& mat); + + /// Sets rotation matrix using igtl::Matrix4x4. + void GetMatrix(Matrix4x4& mat); + + +protected: + TransformMessage(); + ~TransformMessage(); + +protected: + + igtlUint64 CalculateContentBufferSize() override; + int PackContent() override; + int UnpackContent() override; + + /// The transformation matrix. + Matrix4x4 matrix; + + /// The byte array for the serialized transform data. + unsigned char* m_Transform; + +}; + + +} // namespace igtl + +#endif // _igtlTransformMessage_h + + + diff --git a/openigtlink/repo/Source/igtlTypes.h b/openigtlink/repo/Source/igtlTypes.h new file mode 100644 index 0000000..098ed95 --- /dev/null +++ b/openigtlink/repo/Source/igtlTypes.h @@ -0,0 +1,88 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlTypes_H +#define __igtlTypes_H + +#include "igtlTypeConfig.h" + +/* 8-bit integer type */ +#if IGTL_SIZEOF_CHAR == 1 + typedef unsigned char igtlUint8; + typedef char igtlInt8; +#else + # error "No native data type can represent an 8-bit integer." +#endif + +/* 16-bit integer type */ +#if IGTL_SIZEOF_SHORT == 2 + typedef unsigned short igtlUint16; + typedef signed short igtlInt16; +#elif IGTL_SIZEOF_INT == 2 + typedef unsigned int igtlUint16; + typedef signed int igtlInt16; +#else + # error "No native data type can represent a 16-bit integer." +#endif + +/* 32-bit integer type */ +#if IGTL_SIZEOF_INT == 4 + typedef unsigned int igtlUint32; + typedef signed int igtlInt32; +#elif IGTL_SIZEOF_LONG == 4 + typedef unsigned long igtlUint32; + typedef signed long igtlInt32; +#else + # error "No native data type can represent a 32-bit integer." +#endif + +/* 64-bit integer type */ +#if defined(IGTL_TYPE_USE_LONG_LONG) && IGTL_SIZEOF_LONG_LONG == 8 + typedef unsigned long long igtlUint64; + typedef signed long long igtlInt64; +#elif IGTL_SIZEOF_INT == 8 + typedef unsigned int igtlUint64; + typedef signed int igtlInt64; +#elif IGTL_SIZEOF_LONG == 8 + typedef unsigned long igtlUint64; + typedef signed long igtlInt64; +#elif defined(IGTL_TYPE_USE___INT64) && IGTL_SIZEOF___INT64 == 8 + typedef unsigned __int64 igtlUint64; + typedef signed __int64 igtlInt64; +#elif defined(IGTL_TYPE_USE_INT64_T) && IGTL_SIZEOF_INT64_T == 8 + typedef unsigned int64_t igtlUint64; + typedef signed int64_t igtlInt64; +#else + # error "No native data type can represent a 64-bit integer." +#endif + +/* 32-bit floating point type */ +#if IGTL_SIZEOF_FLOAT == 4 + typedef float igtlFloat32; +#else +# error "No native data type can represent a 32-bit floating point value." +#endif + +/* 64-bit floating point type */ +#if IGTL_SIZEOF_DOUBLE == 8 + typedef double igtlFloat64; +#else +# error "No native data type can represent a 64-bit floating point value." +#endif + +/* 128-bit complex type */ +typedef double igtlComplex[2]; + + +#endif /* __igtlTypes_H */ diff --git a/openigtlink/repo/Source/igtlUDPClientSocket.cxx b/openigtlink/repo/Source/igtlUDPClientSocket.cxx new file mode 100755 index 0000000..35d16f6 --- /dev/null +++ b/openigtlink/repo/Source/igtlUDPClientSocket.cxx @@ -0,0 +1,69 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkClientSocket.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "igtlUDPClientSocket.h" +#include + +namespace igtl +{ + +//----------------------------------------------------------------------------- +UDPClientSocket::UDPClientSocket() +{ +} + +//----------------------------------------------------------------------------- +UDPClientSocket::~UDPClientSocket() +{ +} + +int UDPClientSocket::JoinNetwork(const char* groupIPAddr, int portNum) +{ + this->SetIPAddress(groupIPAddr); + this->SetPortNumber(portNum); + this->m_SocketDescriptor = this->CreateUDPClientSocket(); + return this->m_SocketDescriptor; +} + +//----------------------------------------------------------------------------- +int UDPClientSocket::ReadSocket(unsigned char* buffer, unsigned bufferSize) { + if (!this->m_SocketDescriptor) + { + igtlErrorMacro("Failed to create socket."); + return -1; + } + int bytesRead = ReceiveUDP(buffer, bufferSize); + return bytesRead; +} +//----------------------------------------------------------------------------- +void UDPClientSocket::PrintSelf(std::ostream& os) const +{ + this->Superclass::PrintSelf(os); +} + +} // end of igtl namespace + diff --git a/openigtlink/repo/Source/igtlUDPClientSocket.h b/openigtlink/repo/Source/igtlUDPClientSocket.h new file mode 100755 index 0000000..53aad6d --- /dev/null +++ b/openigtlink/repo/Source/igtlUDPClientSocket.h @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkClientSocket.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved.UDPClientSocket + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME igtlUDPClientSocket - Encapsulates a client UDPsocket. + +#ifndef __igtlUDPClientSocket_h +#define __igtlUDPClientSocket_h + +#include +#include "igtlGeneralSocket.h" +#include "igtlWin32Header.h" + +namespace igtl +{ + +class UDPServerSocket; + +class IGTLCommon_EXPORT UDPClientSocket : public GeneralSocket +{ +public: + igtlTypeMacro(igtl::UDPClientSocket, igtl::GeneralSocket) + igtlNewMacro(igtl::UDPClientSocket); + + int JoinNetwork(const char* groupIPAddr, int portNum); + + int ReadSocket(unsigned char* buffer, unsigned bufferSize); + +protected: + UDPClientSocket(); + ~UDPClientSocket(); + + void PrintSelf(std::ostream& os) const override; + + friend class UDPServerSocket; + +private: + UDPClientSocket(const UDPClientSocket&); // Not implemented. + void operator=(const UDPClientSocket&); // Not implemented. +}; + +} + +#endif + diff --git a/openigtlink/repo/Source/igtlUDPServerSocket.cxx b/openigtlink/repo/Source/igtlUDPServerSocket.cxx new file mode 100755 index 0000000..8953c63 --- /dev/null +++ b/openigtlink/repo/Source/igtlUDPServerSocket.cxx @@ -0,0 +1,164 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkServerSocket.cxx,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "igtlUDPServerSocket.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +namespace igtl +{ + +//----------------------------------------------------------------------------- +UDPServerSocket::UDPServerSocket() +{ +} + +//----------------------------------------------------------------------------- +UDPServerSocket::~UDPServerSocket() +{ +} + +//----------------------------------------------------------------------------- +bool UDPServerSocket::IsMulticastAddreesValid(const char* add) +{ + //224.0.0.0 through 224.0.0.255, are not routable + igtl_uint32 address = inet_addr(add); // to do: make sure the endian is correct + if(igtl_is_little_endian()) + { + address = BYTE_SWAP_INT32(address); + } + return address > 0xE00000FF && + address <= 0xEFFFFFFF; +} + +//----------------------------------------------------------------------------- +int UDPServerSocket::AddGroup(const char* add, igtl_uint16 port, unsigned int groupID) +{ + if (IsMulticastAddreesValid(add)) + { + for(std::vector::size_type i = 0; i < this->groups.size(); i++) + { + if (this->groups[i].groupID == groupID && + (strcmp((const char *)this->groups[i].address ,add)==0) + && this->groups[i].portNum == port ) + { + + return -1; + } + } + this->groups.push_back(GroupDest(add, port, groupID)); + } + return 0; +} + +//----------------------------------------------------------------------------- +int UDPServerSocket::AddClient(const char* add, igtl_uint16 port, unsigned int clientID) +{ + for(std::vector::size_type i = 0; i < this->clients.size(); i++) + { + if (this->clients[i].clientID == clientID && + (strcmp((const char *)this->clients[i].address ,add)==0) + && this->clients[i].portNum == port ) + { + + return -1; + } + } + this->clients.push_back(ClientDest(add, port, clientID)); + return 0; +} + +//----------------------------------------------------------------------------- +int UDPServerSocket::WriteSocket(unsigned char* buffer, unsigned bufferSize) +{ + int numByteSend = 0; + for(std::vector::size_type i = 0; i < this->groups.size(); i++) + { + this->SetIPAddress((const char*)this->groups[i].address); + this->SetPortNumber(this->groups[i].portNum); + numByteSend = SendUDP((char*)buffer, bufferSize); + } + for(std::vector::size_type i = 0; i < this->clients.size(); i++) + { + this->SetIPAddress((const char*)this->clients[i].address); + this->SetPortNumber(this->clients[i].portNum); + numByteSend = SendUDP((char*)buffer, bufferSize); + } + return numByteSend; +} + +//----------------------------------------------------------------------------- +int UDPServerSocket::CreateUDPServer() +{ + if (this->m_SocketDescriptor != -1) + { + igtlWarningMacro("Server Socket already exists. Closing old socket."); + this->CloseSocket(this->m_SocketDescriptor); + this->m_SocketDescriptor = -1; + } + this->m_SocketDescriptor = this->CreateUDPServerSocket(); + if (this->m_SocketDescriptor < 0) + { + return -1; + } + return 0; +} + +//----------------------------------------------------------------------------- +int UDPServerSocket::DeleteClient(unsigned int groupID) +{ + for(std::vector::size_type i = 0; this->groups.size(); i++) + { + if (this->groups[i].groupID == groupID) + { + this->groups.erase(this->groups.begin()+i); + return 0; + } + } + return -1; +} + +//----------------------------------------------------------------------------- +void UDPServerSocket::PrintSelf(std::ostream& os) const +{ + this->Superclass::PrintSelf(os); +} + +} // end of igtl namespace diff --git a/openigtlink/repo/Source/igtlUDPServerSocket.h b/openigtlink/repo/Source/igtlUDPServerSocket.h new file mode 100755 index 0000000..825c63f --- /dev/null +++ b/openigtlink/repo/Source/igtlUDPServerSocket.h @@ -0,0 +1,129 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: vtkServerSocket.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME igtlUDPServerSocket - Encapsulate a socket that accepts connections. +// .SECTION Description +// + +#ifndef __igtlUDPServerSocket_h +#define __igtlUDPServerSocket_h + +//#include +#include + +#include "igtlGeneralSocket.h" +#include "igtlUDPClientSocket.h" +#include "igtlWin32Header.h" +#include "igtl_header.h" +#include "igtl_util.h" + +namespace igtl +{ +class GroupDest +{ +public: + GroupDest(const char* add, igtl_uint16 port, unsigned int groupID) + { + this->address = new unsigned char[IP4AddressStrLen]; + strcpy((char*)this->address, add); + this->portNum = port; + this->groupID = groupID; + }; + unsigned char* address; + igtl_uint16 portNum; // should be in network byte order + unsigned int groupID; +}; + +class ClientDest +{ +public: + ClientDest(const char* add, igtl_uint16 port, unsigned int clientID) + { + this->address = new unsigned char[IP4AddressStrLen]; + strcpy((char*)this->address, add); + this->portNum = port; + this->clientID = clientID; + }; + unsigned char* address; + igtl_uint16 portNum; // should be in network byte order + unsigned int clientID; +}; + +class IGTLCommon_EXPORT UDPServerSocket : public GeneralSocket +{ +public: + igtlTypeMacro(igtl::UDPServerSocket, igtl::GeneralSocket); + igtlNewMacro(igtl::UDPServerSocket); + + bool IsMulticastAddreesValid(const char* add); + + + // Description: + // Add a client socket with given address at a given port and binds to it. + // Returns -1 on error. return clientID on success. + int AddGroup(const char* add, igtl_uint16 port, unsigned int clientID); + + // Description: + // Add a client socket with given address at a given port and binds to it. + // Returns -1 on error. return clientID on success. + int AddClient(const char* add, igtl_uint16 port, unsigned int clientID); + + + // Description: + // Add a client socket with given address at a given port and binds to it. + // Returns -1 on error. 0 on success. + int DeleteClient(unsigned int groupID); + + // Description: + // Creates a UDP server socket at a given port and binds to it. + // Returns -1 on error. 0 on success. + int CreateUDPServer(); + + // Desciption: + // Write the data to all clients + int WriteSocket(unsigned char* buffer, unsigned bufferSize); + +protected: + UDPServerSocket(); + ~UDPServerSocket(); + + std::vector groups; + + std::vector clients; + + void PrintSelf(std::ostream& os) const override; + +private: + UDPServerSocket(const UDPServerSocket&); // Not implemented. + void operator=(const UDPServerSocket&); // Not implemented. +}; + +} // end of igtl namespace + + +#endif + diff --git a/openigtlink/repo/Source/igtlUnit.cxx b/openigtlink/repo/Source/igtlUnit.cxx new file mode 100644 index 0000000..5683d54 --- /dev/null +++ b/openigtlink/repo/Source/igtlUnit.cxx @@ -0,0 +1,133 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlUnit.h" +#include "igtl_unit.h" + +// Disable warning C4996 (strncpy() may be unsafe) in Windows. +#define _CRT_SECURE_NO_WARNINGS + +namespace igtl { + +Unit::Unit(): + Object() +{ + Init(); +} + + +Unit::~Unit() +{ +} + + +void Unit::Init() +{ + this->m_Prefix = SI_PREFIX_NONE; + this->m_NUnits = 0; + + for (int i = 0; i < 6; i ++) + { + this->m_Unit[i] = SI_BASE_NONE; + this->m_Exp[i] = 0; + } +} + + +int Unit::SetPrefix(int prefix) +{ + if (prefix >= SI_PREFIX_NONE && prefix <= SI_PREFIX_FEMTO) + { + this->m_Prefix = prefix; + return 1; + } + else + { + return 0; + } +} + + +int Unit::Append(int unit, int exp) +{ + // Check number of units already appended + if (this->m_NUnits >= 6) + { + return 0; + } + + // Check range + if (unit < SI_BASE_NONE || unit >= SI_NUM_UNIT_TYPES) + { + return 0; + } + if (exp < -7 || exp > 7) + { + return 0; + } + + // Append + this->m_Unit[this->m_NUnits] = (igtlUint8)unit; + this->m_Exp[this->m_NUnits] = (igtlInt8)exp; + this->m_NUnits++; + return 1; +} + + +igtlUnit Unit::Pack() +{ + igtl_unit_data data; + + igtl_unit_init(&data); + + data.prefix = this->m_Prefix; + for (int i = 0; i < 6; i ++) + { + data.unit[i] = this->m_Unit[i]; + data.exp[i] = this->m_Exp[i]; + } + + return (igtlUnit) igtl_unit_pack(&data); +} + + +int Unit::Unpack(igtlUnit unit) +{ + igtl_unit_data data; + + if (igtl_unit_unpack((igtl_unit)unit, &data) == 0) + { + return 0; + } + + Init(); + + this->m_Prefix = data.prefix; + for (int i = 0; i < 6; i ++) + { + this->m_Unit[i] = data.unit[i]; + this->m_Exp[i] = data.exp[i]; + } + + return 1; + +} + + +} // namespace igtl + + + + + diff --git a/openigtlink/repo/Source/igtlUnit.h b/openigtlink/repo/Source/igtlUnit.h new file mode 100644 index 0000000..336665a --- /dev/null +++ b/openigtlink/repo/Source/igtlUnit.h @@ -0,0 +1,152 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igtlUnit_h +#define __igtlUnit_h + +#include "igtlWin32Header.h" + +#include "igtlMacro.h" +#include "igtlObject.h" +#include "igtlObjectFactory.h" +#include "igtlTypes.h" + +namespace igtl +{ + +typedef igtlUint64 igtlUnit; + +/// The Unit class provides a general way to describe unites defined in International System of Unites (SI) +/// in its 8-byte (or 64-bit) field. The field is designed to specifiy a unit consisting of SI-prefix +/// (e.g. milli, micro, kilo etc...) and combination of SI-base and/or SI-derived unites. +/// The bites in the field are assigned as follows: +/// +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-... +/// |PREFIX | UNIT0 | EXP0 | UNIT1 | EXP1 | UNIT2 | EXP2 +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-... +/// 0 1 2 3 4 +/// +/// ...-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// EXP2 | UNIT3 | EXP3 | UNIT4 | EXP4 | UNIT5 | EXP5 | +/// ...-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// 4 5 6 7 +class IGTLCommon_EXPORT Unit : public Object +{ +public: + + /// SI Prefix + enum { + SI_PREFIX_NONE = 0x0, /* None */ + SI_PREFIX_DEKA = 0x1, /* deka (deca) (1e1) */ + SI_PREFIX_HECTO = 0x2, /* hecto (1e2) */ + SI_PREFIX_KILO = 0x3, /* kilo (1e3) */ + SI_PREFIX_MEGA = 0x4, /* mega (1e6) */ + SI_PREFIX_GIGA = 0x5, /* giga (1e9) */ + SI_PREFIX_TERA = 0x6, /* tera (1e12) */ + SI_PREFIX_PETA = 0x7, /* peta (1e15) */ + SI_PREFIX_DECI = 0x9, /* deci (1e-1) */ + SI_PREFIX_CENTI = 0xA, /* centi (1e-2) */ + SI_PREFIX_MILLI = 0xB, /* milli (1e-3) */ + SI_PREFIX_MICRO = 0xC, /* micro (1e-6) */ + SI_PREFIX_NANO = 0xD, /* nano (1e-9) */ + SI_PREFIX_PICO = 0xE, /* pico (1e-12) */ + SI_PREFIX_FEMTO = 0xF, /* femto (1e-15) */ + }; + + /// SI Units + enum { + // SI Base Units + SI_BASE_NONE = 0x00, + SI_BASE_METER = 0x01, /* meter */ + SI_BASE_GRAM = 0x02, /* gram */ + SI_BASE_SECOND = 0x03, /* second */ + SI_BASE_AMPERE = 0x04, /* ampere */ + SI_BASE_KELVIN = 0x05, /* kelvin */ + SI_BASE_MOLE = 0x06, /* mole */ + SI_BASE_CANDELA = 0x07, /* candela */ + + // SI Derived Units + SI_DERIVED_RADIAN = 0x08, /* radian meter/meter */ + SI_DERIVED_STERADIAN = 0x09, /* steradian meter^2/meter^2 */ + SI_DERIVED_HERTZ = 0x0A, /* hertz /second */ + SI_DERIVED_NEWTON = 0x0B, /* newton meter-kilogram/second^2 */ + SI_DERIVED_PASCAL = 0x0C, /* pascal kilogram/meter-second^2 */ + SI_DERIVED_JOULE = 0x0D, /* joule meter^2-kilogram/second^2 */ + SI_DERIVED_WATT = 0x0E, /* watt meter^2-kilogram/second^3 */ + SI_DERIVED_COULOMB = 0x0F, /* coulomb second-ampere */ + SI_DERIVED_VOLT = 0x10, /* volt meter^2-kilogram/second^3-ampere */ + SI_DERIVED_FARAD = 0x11, /* farad second^4-ampere^2/meter^2-kilogram */ + SI_DERIVED_OHM = 0x12, /* ohm meter^2-kilogram/second^3-ampere^2 */ + SI_DERIVED_SIEMENS = 0x13, /* siemens second^3-ampere^2/meter^2-kilogram */ + SI_DERIVED_WEBER = 0x14, /* weber meter^2-kilogram/second^2-ampere */ + SI_DERIVED_TESLA = 0x15, /* tesla kilogram/second^2-ampere */ + SI_DERIVED_HENRY = 0x16, /* henry meter^2-kilogram/second^2-ampere^2 */ + SI_DERIVED_LUMEN = 0x17, /* lumen candela-steradian */ + SI_DERIVED_LUX = 0x18, /* lux candela-steradian/meter^2 */ + SI_DERIVED_BECQUEREL = 0x19, /* becquerel /second */ + SI_DERIVED_GRAY = 0x1A, /* gray meter^2/second^2 */ + SI_DERIVED_SIEVERT = 0x1B, /* sievert meter^2/second^2 */ + + SI_NUM_UNIT_TYPES = 0x1C, + }; + + + +public: + igtlTypeMacro(Unit, Object); + igtlNewMacro(Self); + + /// Initializes the class. + void Init(); + + /// Sets the SI prefix. + int SetPrefix(int prefix); + + /// Appends a unit with exponential + int Append(int unit, int exp); + + /// Packs (or serializes) the unit into a 64-bit value. + igtlUnit Pack(); + + /// Unpacks the unit from a 64-bit value. + int Unpack(igtlUnit unit); + +protected: + + /// constructor + Unit(); + + /// destructor + virtual ~Unit(); + +private: + + /// Prefix. + igtlUint8 m_Prefix; + + /// Either SI-Base or SI-Derived. + igtlUint8 m_Unit[6]; + + /// Must be within [-7, 7]. + igtlInt8 m_Exp[6]; + + /// Number of units appended. + igtlInt32 m_NUnits; + +}; + +} + +#endif // __igtlUnit_h + diff --git a/openigtlink/repo/Source/igtlWin32Header.h b/openigtlink/repo/Source/igtlWin32Header.h new file mode 100644 index 0000000..581bbc6 --- /dev/null +++ b/openigtlink/repo/Source/igtlWin32Header.h @@ -0,0 +1,157 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkWin32Header.h,v $ + Language: C++ + Date: $Date: 2010-01-17 13:38:05 -0500 (Sun, 17 Jan 2010) $ + Version: $Revision: 5577 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + Portions of this code are covered under the VTK copyright. + See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef __igtlWin32Header_h +#define __igtlWin32Header_h + +#include "igtlConfigure.h" + +// add in the Windows variants + +#if defined(__CYGWIN__) +#ifndef WIN32 +#define WIN32 1 +#endif +#ifndef _WIN32 +#define _WIN32 1 +#endif +#endif + +#if defined(_WIN32) + // Include the windows header here only if requested by user code. +# if defined(IGTL_INCLUDE_WINDOWS_H) +# include + // Define types from the windows header file. + typedef DWORD igtlWindowsDWORD; + typedef PVOID igtlWindowsPVOID; + typedef LPVOID igtlWindowsLPVOID; + typedef HANDLE igtlWindowsHANDLE; + typedef LPTHREAD_START_ROUTINE igtlWindowsLPTHREAD_START_ROUTINE; +# else + // Define types from the windows header file. + typedef unsigned long igtlWindowsDWORD; + typedef void* igtlWindowsPVOID; + typedef igtlWindowsPVOID igtlWindowsLPVOID; + typedef igtlWindowsPVOID igtlWindowsHANDLE; + typedef igtlWindowsDWORD (__stdcall *igtlWindowsLPTHREAD_START_ROUTINE)(igtlWindowsLPVOID); +# endif + +#if ( _MSC_VER >= 1300 ) // Visual studio .NET +#pragma warning ( disable : 4311 ) +#pragma warning ( disable : 4312 ) +# define igtlGetWindowLong GetWindowLongPtr +# define igtlSetWindowLong SetWindowLongPtr +# define igtlLONG LONG_PTR +# define igtlGWL_WNDPROC GWLP_WNDPROC +# define igtlGWL_HINSTANCE GWLP_HINSTANCE +# define igtlGWL_USERDATA GWLP_USERDATA +#else // older or non-Visual studio +# define igtlGetWindowLong GetWindowLong +# define igtlSetWindowLong SetWindowLong +# define igtlLONG LONG +# define igtlGWL_WNDPROC GWL_WNDPROC +# define igtlGWL_HINSTANCE GWL_HINSTANCE +# define igtlGWL_USERDATA GWL_USERDATA +#endif // +#endif + + +#if defined(_MSC_VER) + // Enable MSVC compiler warning messages that are useful but off by default. +# pragma warning ( default : 4263 ) /* no override, call convention differs */ + // Disable MSVC compiler warning messages that often occur in valid code. +# if !defined(IGTL_DISPLAY_WIN32_WARNINGS) +# pragma warning ( disable : 4003 ) /* not enough actual parameters for macro */ +# pragma warning ( disable : 4097 ) /* typedef is synonym for class */ +# pragma warning ( disable : 4127 ) /* conditional expression is constant */ +# pragma warning ( disable : 4244 ) /* possible loss in conversion */ +# pragma warning ( disable : 4251 ) /* missing DLL-interface */ +# pragma warning ( disable : 4305 ) /* truncation from type1 to type2 */ +# pragma warning ( disable : 4309 ) /* truncation of constant value */ +# pragma warning ( disable : 4514 ) /* unreferenced inline function */ +# pragma warning ( disable : 4706 ) /* assignment in conditional expression */ +# pragma warning ( disable : 4710 ) /* function not inlined */ +# pragma warning ( disable : 4786 ) /* identifier truncated in debug info */ +# pragma warning ( disable : 4996 ) /* 'strncpy': This function or variable may be unsafe. */ +# endif + +// typename keyword in default template arguments is not accepted by +// MSVC. This macro should only be used in such places. +# if !defined(CABLE_CONFIGURATION) && (_MSC_VER < 1310) +# define IGTL_TYPENAME +# else +# define IGTL_TYPENAME typename +# endif +#else +# define IGTL_TYPENAME typename +#endif + +// MSVC 6.0 in release mode will warn about code it produces with its +// optimizer. Disable the warnings specifically for this +// configuration. Real warnings will be revealed by a debug build or +// by other compilers. +#if defined(_MSC_VER) && (_MSC_VER < 1300) && defined(NDEBUG) +# pragma warning ( disable : 4701 ) /* Variable may be used uninitialized. */ +# pragma warning ( disable : 4702 ) /* Unreachable code. */ +#endif + +#if defined(__BORLANDC__) + // Disable Borland compiler warning messages that often occur in valid code. +# if !defined(IGTL_DISPLAY_WIN32_WARNINGS) +# pragma warn -8004 /* assigned a value that is never used */ +# pragma warn -8008 /* condition is always false */ +# pragma warn -8026 /* funcs w/class-by-value args not expanded inline */ +# pragma warn -8027 /* functions w/ do/for/while not expanded inline */ +# pragma warn -8060 /* possibly incorrect assignment */ +# pragma warn -8066 /* unreachable code */ +# pragma warn -8072 /* suspicious pointer arithmetic */ +# endif +#endif + +// IGTL_EXPORT can not be used +#define IGTL_EXPORT + +#if (defined(_WIN32) || defined(WIN32)) && !defined(IGTLSTATIC) +# ifdef IGTLCommon_EXPORTS +# define IGTLCommon_EXPORT __declspec(dllexport) +# else +# define IGTLCommon_EXPORT __declspec(dllimport) +# endif /* IGTLCommon_EXPORT */ +#else +/* unix needs nothing */ +#define IGTLCommon_EXPORT +#endif + + + + +#endif diff --git a/openigtlink/repo/Source/igtlWindows.h b/openigtlink/repo/Source/igtlWindows.h new file mode 100644 index 0000000..0414013 --- /dev/null +++ b/openigtlink/repo/Source/igtlWindows.h @@ -0,0 +1,48 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/*========================================================================= + + Program: Insight Segmentation & Registration Toolkit + Module: $RCSfile: itkWindows.h,v $ + Language: C++ + Date: $Date: 2008-12-22 19:05:42 -0500 (Mon, 22 Dec 2008) $ + Version: $Revision: 3460 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +/** This file is used to create the smallest windows.h possible. + * Also it removes a few annoying #define's in windows.h. */ +#ifndef __igtlWindows_h +#define __igtlWindows_h + +#ifndef NOMINMAX + #define NOMINMAX +#endif + +#ifdef WIN32_LEAN_AND_MEAN + #undef WIN32_LEAN_AND_MEAN +#endif + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#endif diff --git a/openigtlink/repo/Source/igtlutil/CMakeLists.txt b/openigtlink/repo/Source/igtlutil/CMakeLists.txt new file mode 100644 index 0000000..6427143 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/CMakeLists.txt @@ -0,0 +1,121 @@ +PROJECT(igtlutil) + +#----------------------------------------------------------------------------- +# Include directories +SET(igtlutil_INCLUDE_DIRS + ${OpenIGTLink_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ) + +IF(OpenIGTLink_BUILD_SHARED_LIBS) + SET(igtlutil_BUILD_SHARED_LIBS ${OpenIGTLink_BUILD_SHARED_LIBS}) +ENDIF() + +IF(OpenIGTLink_BUILD_GENERATE_PIC) + SET(igtlutil_BUILD_GENERATE_PIC ${OpenIGTLink_BUILD_GENERATE_PIC}) + SET(IGTLSTATIC 1) +ENDIF() + +SET(igtlutil_HEADS + igtl_header.h + igtl_image.h + igtl_position.h + igtl_transform.h + igtl_types.h + igtl_util.h + igtl_capability.h + ) + +SET(igtlutil_SOURCES + igtl_header.c + igtl_image.c + igtl_position.c + igtl_transform.c + igtl_util.c + igtl_capability.c + ) + +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "1") + SET(igtlutil_HEADS + ${igtlutil_HEADS} + igtl_colortable.h + igtl_imgmeta.h + igtl_lbmeta.h + igtl_point.h + igtl_tdata.h + igtl_qtdata.h + igtl_trajectory.h + igtl_unit.h + igtl_sensor.h + igtl_string.h + igtl_ndarray.h + igtl_bind.h + igtl_qtrans.h + igtl_polydata.h + ) + SET(igtlutil_SOURCES + ${igtlutil_SOURCES} + igtl_colortable.c + igtl_imgmeta.c + igtl_lbmeta.c + igtl_point.c + igtl_tdata.c + igtl_qtdata.c + igtl_trajectory.c + igtl_unit.c + igtl_sensor.c + igtl_string.c + igtl_ndarray.c + igtl_bind.c + igtl_qtrans.c + igtl_polydata.c + ) +ENDIF() + +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "2") + SET(igtlutil_HEADS + ${igtlutil_HEADS} + igtl_command.h + ) + SET(igtlutil_SOURCES + ${igtlutil_SOURCES} + igtl_command.c + ) +ENDIF() + +IF(MSVC OR ${CMAKE_GENERATOR} MATCHES "Xcode") + ADD_LIBRARY(igtlutil + ${igtlutil_SOURCES} + ${igtlutil_HEADS} + ) +ELSE() + ADD_LIBRARY(igtlutil + ${igtlutil_SOURCES} + ) +ENDIF() + +FOREACH(p IN LISTS igtlutil_INCLUDE_DIRS) + target_include_directories(igtlutil PUBLIC $) +ENDFOREACH() +target_include_directories(igtlutil PUBLIC $) + +IF(MSVC) + target_compile_options(igtlutil PRIVATE /MP) +ENDIF() + +SET_TARGET_PROPERTIES(igtlutil PROPERTIES + VERSION ${OpenIGTLink_VERSION_MAJOR}.${OpenIGTLink_VERSION_MINOR}.${OpenIGTLink_VERSION_PATCH} + SOVERSION ${OpenIGTLink_VERSION_MAJOR} +) + +INSTALL(FILES ${igtlutil_HEADS} + DESTINATION ${igtlutil_INSTALL_INCLUDE_DIR} + COMPONENT Development) + +INSTALL(TARGETS igtlutil EXPORT OpenIGTLink + RUNTIME DESTINATION ${OpenIGTLink_INSTALL_BIN_DIR} COMPONENT RuntimeLibraries + LIBRARY DESTINATION ${OpenIGTLink_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries + ARCHIVE DESTINATION ${OpenIGTLink_INSTALL_LIB_DIR} COMPONENT Development) + +SET(igtlutil_INCLUDE_DIRS ${igtlutil_INCLUDE_DIRS} PARENT_SCOPE) diff --git a/openigtlink/repo/Source/igtlutil/igtl_bind.c b/openigtlink/repo/Source/igtlutil/igtl_bind.c new file mode 100644 index 0000000..2862fe3 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_bind.c @@ -0,0 +1,712 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_bind.h" +#include "igtl_util.h" + + +void igtl_export igtl_bind_init_info(igtl_bind_info * bind_info) +{ + if (bind_info) + { + bind_info->ncmessages = 0; + bind_info->child_info_array = NULL; + bind_info->resol = 0; + bind_info->request_all = 0; + bind_info->status = 0; + } +} + + +int igtl_export igtl_bind_alloc_info(igtl_bind_info * bind_info, igtl_uint16 ncmessages) +{ + size_t size; + + if (bind_info == NULL) + { + return 0; + } + + size = (size_t) ncmessages * sizeof(igtl_bind_child_info); + bind_info->child_info_array = malloc(size); + + if (bind_info->child_info_array != NULL) + { + bind_info->ncmessages = ncmessages; + memset(bind_info->child_info_array, 0, size); + return 1; + } + else + { + bind_info->ncmessages = 0; + return 0; + } +} + + +int igtl_export igtl_bind_free_info(igtl_bind_info * bind_info) +{ + + if (bind_info == NULL) + { + return 0; + } + + if (bind_info->ncmessages == 0 || bind_info->child_info_array == NULL) + { + bind_info->ncmessages = 0; + return 1; + } + + free(bind_info->child_info_array); + return 1; + +} + + +/* + * Function to unpack BIND message + */ +int igtl_bind_unpack_normal(void * byte_array, igtl_bind_info * info) +{ + igtl_uint16 i; + igtl_uint16 ncmessages; + igtl_uint16 nametable_size; + size_t namelen; + char * ptr; + char * ptr2; + igtl_uint64 tmp64; + + if (byte_array == NULL || info == NULL) + { + return 0; + } + + /* Number of child messages */ + ptr = (char *) byte_array; + if (igtl_is_little_endian()) + { + ncmessages = BYTE_SWAP_INT16(*((igtl_uint16*)ptr)); + } + else + { + ncmessages = *((igtl_uint16*)ptr); + } + + /* Allocate an array of bind_info, if neccessary */ + if (ncmessages != info->ncmessages) + { + if (igtl_bind_alloc_info(info, ncmessages) == 0) + { + return 0; + } + } + + /* Pointer to the first element in the BIND header section */ + ptr += sizeof(igtl_uint16); + + /* Extract types and body sizes from the BIND header section */ + for (i = 0; i < ncmessages; i ++) + { + /* Type of child message */ + strncpy(info->child_info_array[i].type, (char*)ptr, IGTL_HEADER_TYPE_SIZE); + info->child_info_array[i].type[IGTL_HEADER_TYPE_SIZE] = '\0'; + + /* Body size of child message */ + ptr += IGTL_HEADER_TYPE_SIZE; + if (igtl_is_little_endian()) + { + memcpy(&tmp64, ptr, sizeof(igtl_uint64)); + info->child_info_array[i].size = BYTE_SWAP_INT64(tmp64); + } + else + { + memcpy(&(info->child_info_array[i].size), ptr, sizeof(igtl_uint64)); + } + + ptr += sizeof(igtl_uint64); + } + + /* Name table size */ + if (igtl_is_little_endian()) + { + nametable_size = BYTE_SWAP_INT16(*((igtl_uint16 *) ptr)); + } + else + { + nametable_size = *((igtl_uint16 *) ptr); + } + + /* + * Check if the name table field is aligned to WORD (The length of + * the field must be even. + */ + if (nametable_size % 2 != 0) + { + return 0; + } + + ptr += sizeof(igtl_uint16); + ptr2 = ptr; + + /* Extract device names from the name table section */ + if (nametable_size > 0) + { + for (i = 0; i < ncmessages; i ++) + { + strncpy(info->child_info_array[i].name, ptr, IGTL_HEADER_NAME_SIZE); + info->child_info_array[i].name[IGTL_HEADER_NAME_SIZE] = '\0'; + namelen = strlen(info->child_info_array[i].name); + ptr += namelen + 1; + } + } + + ptr = ptr2 + nametable_size; + + /* Set pointers to the child message bodies */ + for (i = 0; i < ncmessages; i ++) + { + info->child_info_array[i].ptr = ptr; + /* Note: a padding byte is added, if the size of the child message body + is odd. */ + ptr += info->child_info_array[i].size + (info->child_info_array[i].size % 2); + } + + /** TODO: check the total size of the message? **/ + + return 1; +} + + +/* + * Function to unpack GET_BIND and STT_BIND messages + */ +int igtl_bind_unpack_request(void * byte_array, igtl_bind_info * info, igtl_uint64 size) +{ + igtl_uint16 i; + igtl_uint16 ncmessages; + igtl_uint16 nametable_size; + size_t namelen; + char * ptr; + char * ptr2; + + if (size == 0) + { + info->request_all = 1; + return 1; + } + + info->request_all = 0; + + if (byte_array == NULL || info == NULL) + { + return 0; + } + + /* Number of child messages */ + ptr = (char *) byte_array; + if (igtl_is_little_endian()) + { + ncmessages = BYTE_SWAP_INT16(*((igtl_uint16*)ptr)); + } + else + { + ncmessages = *((igtl_uint16*)ptr); + } + + /* Allocate an array of bind_info, if neccessary */ + if (ncmessages != info->ncmessages) + { + if (igtl_bind_alloc_info(info, ncmessages) == 0) + { + return 0; + } + } + + /* Pointer to the first element in the BIND header section */ + ptr += sizeof(igtl_uint16); + + /* Extract types and body sizes from the BIND header section */ + for (i = 0; i < ncmessages; i ++) + { + /* Type of child message */ + strncpy(info->child_info_array[i].type, (char*)ptr, IGTL_HEADER_TYPE_SIZE); + info->child_info_array[i].type[IGTL_HEADER_TYPE_SIZE] = '\0'; + ptr += IGTL_HEADER_TYPE_SIZE; + } + + /* Name table size */ + if (igtl_is_little_endian()) + { + nametable_size = BYTE_SWAP_INT16(*((igtl_uint16 *) ptr)); + } + else + { + nametable_size = *((igtl_uint16 *) ptr); + } + + /* + * Check if the name table field is aligned to WORD (The length of + * the field must be even. + */ + if (nametable_size % 2 != 0) + { + return 0; + } + + ptr += sizeof(igtl_uint16); + ptr2 = ptr; + + /* Extract device names from the name table section */ + if (nametable_size > 0) + { + for (i = 0; i < ncmessages; i ++) + { + strncpy(info->child_info_array[i].name, ptr, IGTL_HEADER_NAME_SIZE); + info->child_info_array[i].name[IGTL_HEADER_NAME_SIZE] = '\0'; + namelen = strlen(info->child_info_array[i].name); + ptr += namelen + 1; + } + } + + /** TODO: check the total size of the message? **/ + + return 1; +} + + +int igtl_export igtl_bind_unpack(int type, void * byte_array, igtl_bind_info * info, igtl_uint64 size) +{ + char * ptr; + + switch (type) + { + + case IGTL_TYPE_PREFIX_NONE: + return igtl_bind_unpack_normal(byte_array, info); + break; + + case IGTL_TYPE_PREFIX_GET: + return igtl_bind_unpack_request(byte_array, info, size); + break; + + case IGTL_TYPE_PREFIX_STT: + /* + * STT_BIND message has the same format as GET_BIND, except that it + * has the time resolution field. + */ + /* Obtain time resolution */ + ptr = byte_array; + if (igtl_is_little_endian()) + { + memcpy(&(info->resol), ptr, sizeof(igtl_uint64)); + info->resol = BYTE_SWAP_INT64(info->resol); + } + else + { + memcpy(&(info->resol), ptr, sizeof(igtl_uint64)); + } + /* Unpack rest of the message */ + ptr += sizeof(igtl_uint64); + return igtl_bind_unpack_request(ptr, info, size-sizeof(igtl_uint64)); + break; + + case IGTL_TYPE_PREFIX_STP: + return 1; + break; + + case IGTL_TYPE_PREFIX_RTS: + info->status = * (igtl_uint8 *) byte_array; + return 1; + break; + + default: + return 0; + break; + } +} + + +/* + * Function to unpack BIND message + */ +int igtl_bind_pack_normal(igtl_bind_info * info, void * byte_array) +{ + char * ptr; + igtl_uint32 i; + igtl_uint32 nc; + igtl_uint16 * nts; + size_t wb; + size_t len; + igtl_uint16 tmp16; + igtl_uint64 tmp64; + + ptr = (char *) byte_array; + nc = info->ncmessages; + + /* Validate info */ + if (info->ncmessages == 0 || info->child_info_array == NULL) + { + return 0; + } + + /* Number of child messages */ + if (igtl_is_little_endian()) + { + /* *((igtl_uint16*) ptr) = BYTE_SWAP_INT16(info->ncmessages); */ + tmp16 = BYTE_SWAP_INT16(info->ncmessages); + memcpy(ptr, &tmp16, sizeof(igtl_uint16)); + } + else + { + /* *((igtl_uint16*) ptr) = info->ncmessages; */ + memcpy(ptr, &(info->ncmessages), sizeof(igtl_uint16)); + } + ptr += sizeof(igtl_uint16); + + + /* BIND header section */ + for (i = 0; i < nc; i ++) + { + /* Fill with 0 */ + memset(ptr, 0, IGTL_HEADER_TYPE_SIZE); + strncpy((char*)ptr, info->child_info_array[i].type, IGTL_HEADER_TYPE_SIZE); + ptr += IGTL_HEADER_TYPE_SIZE; + + /* 2011-04-29 + * Since ptr is not alined to double-word order at this point, + * "* ((igtl_uint64 *) ptr) = " may fail in some archtecture. + * In the following section, memcpy() is called instaed of using * ((igtl_uint64 *) ptr) + * expression. + */ + + if (igtl_is_little_endian()) + { + tmp64 = BYTE_SWAP_INT64(info->child_info_array[i].size); + memcpy(ptr, &tmp64, sizeof(igtl_uint64)); + } + else + { + memcpy(ptr, &(info->child_info_array[i].size), sizeof(igtl_uint64)); + } + ptr += sizeof(igtl_uint64); + } + + + /* Name table section */ + nts = (igtl_uint16 *) ptr; /* save address for name table size field */ + ptr += sizeof(igtl_uint16); + + wb = 0; + for (i = 0; i < nc; i ++) + { + len = strlen(info->child_info_array[i].name); + if (len > IGTL_HEADER_NAME_SIZE) + { + return 0; + } + /* copy string + NULL-terminator */ + strncpy(ptr, info->child_info_array[i].name, len+1); + ptr += (len + 1); + wb += len + 1; + } + + /* Add padding if the size of the name table section is not even */ + if (wb % 2 > 0) + { + *((igtl_uint8*)ptr) = 0; + ptr ++; + wb ++; + } + + /* Substitute name table size */ + *nts = (igtl_uint16) wb; + if (igtl_is_little_endian()) + { + *nts = BYTE_SWAP_INT16(*nts); + } + + return 1; + +} + + +/* + * Function to unpack STT_BIND and GET_BIND messages + */ +int igtl_bind_pack_request(igtl_bind_info * info, void * byte_array) +{ + char * ptr; + igtl_uint32 i; + igtl_uint32 nc; + igtl_uint16 * nts; + size_t wb; + size_t len; + igtl_uint16 tmp16; + + ptr = (char *) byte_array; + nc = info->ncmessages; + + /* If requesting all available, no body is generated. */ + if (info->request_all == 1) + { + return 1; + } + + /* Validate info */ + if (info->ncmessages == 0 || info->child_info_array == NULL) + { + return 0; + } + + /* Number of child messages */ + if (igtl_is_little_endian()) + { + /* *((igtl_uint16*) ptr) = BYTE_SWAP_INT16(info->ncmessages); */ + tmp16 = BYTE_SWAP_INT16(info->ncmessages); + memcpy(ptr, &tmp16, sizeof(igtl_uint16)); + } + else + { + /* *((igtl_uint16*) ptr) = info->ncmessages; */ + memcpy(ptr, &(info->ncmessages), sizeof(igtl_uint16)); + } + ptr += sizeof(igtl_uint16); + + + /* BIND header section */ + for (i = 0; i < nc; i ++) + { + /*memset(ptr, 0, IGTL_HEADER_TYPE_SIZE); */ /* Fill with 0 */ + strncpy((char*)ptr, info->child_info_array[i].type, IGTL_HEADER_TYPE_SIZE); + ptr += IGTL_HEADER_TYPE_SIZE; + } + + /* Name table section */ + nts = (igtl_uint16 *) ptr; /* save address for name table size field */ + ptr += sizeof(igtl_uint16); + + wb = 0; + for (i = 0; i < nc; i ++) + { + len = strlen(info->child_info_array[i].name); + if (len > IGTL_HEADER_NAME_SIZE) + { + return 0; + } + /* copy string + NULL-terminator */ + strncpy(ptr, info->child_info_array[i].name, len+1); + ptr += (len + 1); + wb += len + 1; + } + + /* Substitute name table size */ + *nts = (igtl_uint16) wb; + if (igtl_is_little_endian()) + { + *nts = BYTE_SWAP_INT16(*nts); + } + + return 1; + +} + + +int igtl_export igtl_bind_pack(igtl_bind_info * info, void * byte_array, int type) +{ + char * ptr; + igtl_uint64 tmp64; + + switch (type) + { + case IGTL_TYPE_PREFIX_NONE: + return igtl_bind_pack_normal(info, byte_array); + break; + + case IGTL_TYPE_PREFIX_GET: + return igtl_bind_pack_request(info, byte_array); + break; + + case IGTL_TYPE_PREFIX_STT: + /* + * STT_BIND message has the same format as GET_BIND, except that it + * has the time resolution field. + */ + ptr = (char *) byte_array; + + /* Get time resolution */ + if (igtl_is_little_endian()) + { + memcpy(&tmp64, ptr, sizeof(igtl_uint64)); + info->resol = BYTE_SWAP_INT64(tmp64); + } + else + { + memcpy(&(info->resol), ptr, sizeof(igtl_uint64)); + } + ptr += sizeof(igtl_uint64); + + /* Generate rest of the message */ + return igtl_bind_pack_request(info, ptr); + break; + + case IGTL_TYPE_PREFIX_STP: + return 1; + break; + + case IGTL_TYPE_PREFIX_RTS: + * (igtl_uint8 * ) byte_array = info->status; + return 1; + break; + + default: + return 0; + break; + } +} + + +/* + * Function to calculate size of BIND message header + */ +igtl_uint64 igtl_bind_get_size_normal(igtl_bind_info * info) +{ + igtl_uint64 size; + igtl_uint32 ntable_size; + igtl_uint16 i; + igtl_uint16 nc; + + nc = info->ncmessages; + + /* Size of NCMESSAGES section */ + size = sizeof(igtl_uint16); + + /* Add size of BIND header section */ + size += (IGTL_HEADER_TYPE_SIZE+sizeof(igtl_uint64)) * nc; + + /* Add size of table size field*/ + size += sizeof(igtl_uint16); + + /* Calculate size of name table */ + ntable_size = 0; + for (i = 0; i < nc; i ++) + { + /* string length + NULL separator */ + ntable_size += strlen(info->child_info_array[i].name) + 1; + } + if (ntable_size %2 > 0) + { + ntable_size += 1; + } + size += ntable_size; + + return size; +} + + +/* + * Function to calculate size of GET_BIND/STT_BIND messages + */ +igtl_uint64 igtl_bind_get_size_request(igtl_bind_info * info) +{ + igtl_uint64 size; + igtl_uint32 ntable_size; + igtl_uint16 i; + igtl_uint16 nc; + + nc = info->ncmessages; + + /* Size of NCMESSAGES section */ + size = sizeof(igtl_uint16); + + /* Add size of BIND header section */ + size += (IGTL_HEADER_TYPE_SIZE+sizeof(igtl_uint64)) * nc; + + /* Add size of table size field*/ + size += sizeof(igtl_uint16); + + /* Calculate size of name table */ + ntable_size = 0; + for (i = 0; i < nc; i ++) + { + /* string length + NULL separator */ + ntable_size += strlen(info->child_info_array[i].name) + 1; + } + + return size; + +} + + +igtl_uint64 igtl_export igtl_bind_get_size(igtl_bind_info * info, int type) +{ + switch (type) + { + case IGTL_TYPE_PREFIX_NONE: + return igtl_bind_get_size_normal(info); + break; + + case IGTL_TYPE_PREFIX_GET: + return igtl_bind_get_size_request(info); + break; + + case IGTL_TYPE_PREFIX_STT: + /* + * STT_BIND message has the same format as GET_BIND, except that it + * has the time resolution field. + */ + return igtl_bind_get_size_request(info) + sizeof(igtl_uint64); + break; + + case IGTL_TYPE_PREFIX_STP: + return 0; + break; + + case IGTL_TYPE_PREFIX_RTS: + return sizeof(igtl_uint8); + break; + + default: + return 0; + break; + } +} + + +igtl_uint64 igtl_export igtl_bind_get_crc(igtl_bind_info * info, int type, void* bind_message) +{ + igtl_uint64 crc; + igtl_uint64 bind_length; + igtl_uint16 i; + igtl_uint16 nc; + + bind_length = (igtl_uint64)igtl_bind_get_size(info, type); + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) bind_message, (int)bind_length, crc); + + if (type == IGTL_TYPE_PREFIX_NONE) + { + nc = info->ncmessages; + for (i = 0; i < nc; i ++) + { + crc = crc64((unsigned char*) info->child_info_array[i].ptr, (int)info->child_info_array[i].size, crc); + } + } + + return crc; +} + diff --git a/openigtlink/repo/Source/igtlutil/igtl_bind.h b/openigtlink/repo/Source/igtlutil/igtl_bind.h new file mode 100644 index 0000000..16cbd66 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_bind.h @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_BIND_H +#define __IGTL_BIND_H + +#include "igtl_win32header.h" +#include "igtl_header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_win32header.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** The igtl_bind_info structure holds information about a child message in an OpenIGTLink + * BIND message. The structure is used for functions defined in igtl_bind.h */ +typedef struct { + char type[IGTL_HEADER_TYPE_SIZE+1]; /* Data type (OpenIGTLink Device Type string) */ + char name[IGTL_HEADER_NAME_SIZE+1]; /* Device name */ + igtl_uint64 size; /* Data size */ + void* ptr; /* Pointer to the child message */ +} igtl_bind_child_info; + +typedef struct { + igtl_uint16 ncmessages; /* Number of child message */ + igtl_bind_child_info * child_info_array; /* Array of igtl_bind_child_info */ + igtl_uint64 resol; /* Time resolution (used for STT_BIND) */ + igtl_uint8 request_all; /* Flag to request all available data + (used for GET_BIND and STT_BIND) */ + igtl_uint8 status; /* Status for RTS message */ +} igtl_bind_info; + + +/** Initializes igtl_bind_info */ +void igtl_export igtl_bind_init_info(igtl_bind_info * bind_info); + +/** Allocates an array of igtl_bind_child_info in bind_info with length of 'ncmessages.' + * Returns 1 if the array is successfully allocated/freed */ +int igtl_export igtl_bind_alloc_info(igtl_bind_info * bind_info, igtl_uint16 ncmessages); + +/** Frees an array of igtl_bind_child_info in bind_info with length of 'ncmessages.' + * Returns 1 if the array is successfully allocated/freed */ +int igtl_export igtl_bind_free_info(igtl_bind_info * bind_info); + +/** Unpacks BIND message. Extracts information about child messages in a byte array of + * BIND messages and store it in a igtl_bind_info structure. + * 'type' argument specifies a message type prefix + * (none, GET_, STT_, STP_ or RTS_) by IGTL_TYPE_PREFIX_* macro. + * Returns 1 if success, otherwise 0. */ +int igtl_export igtl_bind_unpack(int type, void * byte_array, igtl_bind_info * info, igtl_uint64 size); + +/** Packs BIND message. Converts an igtl_bind_info structure to a byte array. + * 'byte_array' should be allocated prior to calling igtl_bind_pack() with memory size + * calculated by igtl_bind_get_size(). 'type' argument specifies a message type prefix + * (none, GET_, STT_, STP_ or RTS_) by IGTL_TYPE_PREFIX_* macro. + * Returns 1 if success, otherwise 0. */ +int igtl_export igtl_bind_pack(igtl_bind_info * info, void * byte_array, int type); + +/** igtl_bind_get_size() calculates the size of bind header, consisting of + * BIND hearder section (including number of child messages) and + * name table section based on a igtl_bind_header. + * The size returned from this function does not include size of child message data. + * 'type' argument specifies a message type prefix + * (none, GET_, STT_, STP_ or RTS_) by IGTL_TYPE_PREFIX_* macro. */ +igtl_uint64 igtl_export igtl_bind_get_size(igtl_bind_info * info, int type); + +/** Calculates CRC of BIND message. Note that 'info' is used only for + * getting size of the message. */ +igtl_uint64 igtl_export igtl_bind_get_crc(igtl_bind_info * info, int type, void* bind_message); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_BIND_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_capability.c b/openigtlink/repo/Source/igtlutil/igtl_capability.c new file mode 100644 index 0000000..0ac8367 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_capability.c @@ -0,0 +1,182 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_capability.h" +#include "igtl_util.h" +#include "igtl_header.h" + +void igtl_export igtl_capability_init_info(igtl_capability_info * info) +{ + if (info) + { + info->ntypes = 0; + info->typenames = NULL; + } +} + + +int igtl_export igtl_capability_alloc_info(igtl_capability_info * info, int ntypes) +{ + unsigned int i; + unsigned char * ptr; + + if (info == NULL) + { + return 0; + } + + info->ntypes = ntypes; + + info->typenames = malloc(sizeof(unsigned char*) * info->ntypes); + if (info->typenames == NULL) + { + /* failed to allocate memory */ + return 0; + } + + ptr = malloc(sizeof(unsigned char) * (IGTL_HEADER_TYPE_SIZE+1) * info->ntypes); + if (ptr == NULL) + { + free(info->typenames); + info->ntypes = 0; + return 0; + } + + for (i = 0; i < info->ntypes; i ++) + { + info->typenames[i] = ptr; + ptr += sizeof(unsigned char) * (IGTL_HEADER_TYPE_SIZE+1); + } + + return 1; +} + + +int igtl_export igtl_capability_free_info(igtl_capability_info * info) +{ + + if (info == NULL) + { + return 0; + } + + if (info->typenames == NULL) + { + return 0; + } + + free(info->typenames[0]); + free(info->typenames); + info->ntypes = 0; + + return 1; +} + + +igtl_uint32 igtl_export igtl_capability_get_length(igtl_capability_info * info) +{ + + if (info == NULL) + { + return 0; + } + + return (info->ntypes * IGTL_HEADER_TYPE_SIZE); +} + + +int igtl_export igtl_capability_unpack(void * byte_array, igtl_capability_info * info, igtl_uint64 pack_size) +{ + int ntypes; + int i; + unsigned char * ptr; + + if (pack_size % IGTL_HEADER_TYPE_SIZE > 0) + { + /* In valid body size */ + return 0; + } + + if (info == NULL) + { + return 0; + } + + ntypes = (int)((int)pack_size / IGTL_HEADER_TYPE_SIZE); + + /* Adjust the size of info->typenames */ + if (info->ntypes != ntypes) + { + igtl_capability_free_info(info); + igtl_capability_alloc_info(info, ntypes); + } + + ptr = byte_array; + for (i = 0; i < ntypes; i ++) + { + strncpy((char*)info->typenames[i], (char*)ptr, IGTL_HEADER_TYPE_SIZE); + info->typenames[i][IGTL_HEADER_TYPE_SIZE] = '\0'; + ptr += IGTL_HEADER_TYPE_SIZE; + } + + return 1; + +} + + +int igtl_export igtl_capability_pack(igtl_capability_info * info, void * byte_array) +{ + unsigned int i; + unsigned char * ptr; + + if (info == NULL) + { + return 0; + } + + if (byte_array == NULL) + { + return 0; + } + + ptr = byte_array; + + for (i = 0; i < info->ntypes; i ++) + { + strncpy((char*)ptr, (char*)info->typenames[i], IGTL_HEADER_TYPE_SIZE); + ptr += IGTL_HEADER_TYPE_SIZE; + } + + return 1; + +} + +igtl_uint64 igtl_export igtl_capability_get_crc(igtl_capability_info * info, void* capability) +{ + igtl_uint64 crc; + igtl_uint64 message_length; + + message_length = (igtl_uint32)igtl_capability_get_length(info); + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) capability, (int)message_length, crc); + + return crc; +} + + + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_capability.h b/openigtlink/repo/Source/igtlutil/igtl_capability.h new file mode 100644 index 0000000..50872b5 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_capability.h @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_CAPABILITY_H +#define __IGTL_CAPABILITY_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_win32header.h" + +#define IGTL_CAPABILITY_HEADER_SIZE 4 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + igtl_uint32 ntypes; + unsigned char ** typenames; +} igtl_capability_info; + + +/** Initializes igtl_ndarray_info */ +void igtl_export igtl_capability_init_info(igtl_capability_info * info); + +/** Allocates ndarray info. Allocate size array and ND-array pointed from igtl_ndarray_info. + * 'type' and 'dim' in igtl_ndarray_info must be specified before + * calling igtl_ndarray_alloc_info(). */ +int igtl_export igtl_capability_alloc_info(igtl_capability_info * info, int ntypes); + +/** Frees ndarray info. */ +int igtl_export igtl_capability_free_info(igtl_capability_info * info); + +/** Calculates capability data size of the pixel array, which will be + * transferred with the specified header. */ +igtl_uint32 igtl_export igtl_capability_get_length(igtl_capability_info * info); + +/** Unpacks CAPABILITY message. Extracts information in a byte array of CAPABILITY + * messages and store it in a igtl_capability_info structure. 'type' argument specifies + * a message type prefix (none, GET_, STT_, STP_ or RTS_) by IGTL_TYPE_PREFIX_* macro. + * Returns 1 if success, otherwise 0. */ +int igtl_export igtl_capability_unpack(void * byte_array, igtl_capability_info * info, igtl_uint64 pack_size); + +/** Packs CAPABILITY message. Converts an igtl_capability_info structure to a byte array. + * 'byte_array' should be allocated prior to calling igtl_capability_pack() with memory size + * calculated by igtl_capability_get_size(). 'type' argument specifies a message type prefix + * (none, or GET_) by IGTL_TYPE_PREFIX_* macro. Returns 1 if success, otherwise 0. */ +int igtl_export igtl_capability_pack(igtl_capability_info * info, void * byte_array); + +/** Calculates CRC of image data body including header + * and array of pixel data. */ +igtl_uint64 igtl_export igtl_capability_get_crc(igtl_capability_info* info, void* capability); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_CAPABILITY_H */ + + + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_colortable.c b/openigtlink/repo/Source/igtlutil/igtl_colortable.c new file mode 100644 index 0000000..f32c308 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_colortable.c @@ -0,0 +1,86 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtl_util.h" +#include "igtl_colortable.h" + +igtl_uint64 igtl_export igtl_colortable_get_table_size(igtl_colortable_header* header) +{ + igtl_int32 n; + igtl_int32 s; + + if (header->indexType == IGTL_COLORTABLE_INDEX_UINT8) + { + n = 256; + } + else /* IGTL_COLORTABLE_INDEX_UINT64 */ + { + n = 256*256; + } + + if (header->mapType == IGTL_COLORTABLE_MAP_UINT8) + { + s = 1; + } + else if (header->mapType == IGTL_COLORTABLE_MAP_UINT16) + { + s = 2; + } + else /* IGTL_COLORTABLE_MAP_RGB */ + { + s = 3; + } + + return (igtl_uint64) n*s; +} + + +void igtl_export igtl_colortable_convert_byte_order(igtl_colortable_header* header, void* table) +{ + int i; + int n; + igtl_uint16* tmp; + + if (igtl_is_little_endian()) + { + if (header->mapType == IGTL_COLORTABLE_MAP_UINT16) + { + n = (header->indexType == IGTL_COLORTABLE_INDEX_UINT16)? 256*256 : 256; + tmp = (igtl_uint16*) table; + for (i = 0; i < n; i ++) + { + tmp[i] = BYTE_SWAP_INT16(tmp[i]); + } + } + } +} + + +igtl_uint64 igtl_export igtl_colortable_get_crc(igtl_colortable_header* header, void* table) +{ + igtl_uint64 crc; + igtl_uint64 data_size; + + /* calculate header size using igtl_colortable_get_table_size(). + * This funciton can be called after byte order conversion, since + * both index and map type field are uint8 and not affected by byte conversion. + */ + + data_size = igtl_colortable_get_table_size(header); + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) header, IGTL_COLORTABLE_HEADER_SIZE, crc); + crc = crc64((unsigned char*) table, (int)data_size, crc); + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_colortable.h b/openigtlink/repo/Source/igtlutil/igtl_colortable.h new file mode 100644 index 0000000..e4d49e7 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_colortable.h @@ -0,0 +1,64 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_COLORTABLE_H +#define __IGTL_COLORTABLE_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" + +#define IGTL_COLORTABLE_HEADER_SIZE 2 + +#define IGTL_COLORTABLE_INDEX_UINT8 3 +#define IGTL_COLORTABLE_INDEX_UINT16 5 +#define IGTL_COLORTABLE_MAP_UINT8 3 +#define IGTL_COLORTABLE_MAP_UINT16 5 +#define IGTL_COLORTABLE_MAP_RGB 19 + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** Status data header for OpenIGTLinik protocol */ +typedef struct { + igtl_int8 indexType; /* Index Type: 3:uint8 5:uint16 */ + igtl_int8 mapType; /* 3: uint8 5:uint16 19:RGB color */ +} igtl_colortable_header; + +#pragma pack() + +/** igtl_colortable_get_data_size(n) calculates the size of body based on the index + * and map types. The size of body is used in the message header. + * igtl_colortable_get_data_n(size) calculates the number of images in the body, based on + * the body size. This function may be used when a client program parses a COLORTABLE message. */ +igtl_uint64 igtl_export igtl_colortable_get_table_size(igtl_colortable_header* header); + +/** Converts endianness of each element in an array of + * igtl_igtl_colortable_header and color table from host byte order to network byte order, + * or vice versa (if necessary). The function automatically determins the endian type of the host. */ +void igtl_export igtl_colortable_convert_byte_order(igtl_colortable_header* header, void* table); + +/** Calculates CRC of color table message */ +igtl_uint64 igtl_export igtl_colortable_get_crc(igtl_colortable_header* header, void* table); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_COLORTABLE_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_command.c b/openigtlink/repo/Source/igtlutil/igtl_command.c new file mode 100644 index 0000000..0823110 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_command.c @@ -0,0 +1,50 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_command.h" +#include "igtl_util.h" + + +void igtl_export igtl_command_convert_byte_order(igtl_command_header* header) +{ + + if (igtl_is_little_endian()) + { + header->commandId = BYTE_SWAP_INT32(header->commandId); + header->encoding = BYTE_SWAP_INT16(header->encoding); + header->length = BYTE_SWAP_INT32(header->length); + } +} + + +igtl_uint64 igtl_export igtl_command_get_crc(igtl_command_header * header, void* command) +{ + igtl_uint64 crc; + igtl_uint32 command_length; + + /* convert byte order to get command length */ + igtl_command_convert_byte_order(header); + command_length = (igtl_uint32)(header->length); + igtl_command_convert_byte_order(header); + + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) header, IGTL_COMMAND_HEADER_SIZE, crc); + crc = crc64((unsigned char*) command, command_length, crc); + + return crc; +} + diff --git a/openigtlink/repo/Source/igtlutil/igtl_command.h b/openigtlink/repo/Source/igtlutil/igtl_command.h new file mode 100644 index 0000000..77a8fac --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_command.h @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_COMMAND_H +#define __IGTL_COMMAND_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_win32header.h" + +#define IGTL_COMMAND_HEADER_SIZE 138 +#define IGTL_COMMAND_NAME_SIZE 128 + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memory */ + +typedef struct { + igtl_uint32 commandId; /* The unique ID of this command */ + igtl_uint8 commandName[IGTL_COMMAND_NAME_SIZE]; /* The name of this command */ + igtl_uint16 encoding; /* Character encoding type as MIBenum value (defined by IANA). Default=3 */ + /* Please refer http://www.iana.org/assignments/character-sets for detail */ + igtl_uint32 length; /* Length of command */ +} igtl_command_header; + +#pragma pack() + +/** Converts endian-ness from host byte order to network byte order, + * or vice versa. NOTE: It is developer's responsibility to have the command body with BOM + * (byte order mark) or in big endian order. */ +void igtl_export igtl_command_convert_byte_order(igtl_command_header * header); + +/** Calculates CRC of image data body including header + * and array of pixel data. */ +igtl_uint64 igtl_export igtl_command_get_crc(igtl_command_header * header, void* command); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_COMMAND_H */ \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlutil/igtl_header.c b/openigtlink/repo/Source/igtlutil/igtl_header.c new file mode 100644 index 0000000..b777d46 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_header.c @@ -0,0 +1,40 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtl_util.h" +#include "igtl_header.h" + +void igtl_export igtl_header_convert_byte_order(igtl_header * header) +{ + if (igtl_is_little_endian()) + { + header->header_version = BYTE_SWAP_INT16(header->header_version); + header->timestamp = BYTE_SWAP_INT64(header->timestamp); + header->body_size = BYTE_SWAP_INT64(header->body_size); + header->crc = BYTE_SWAP_INT64(header->crc); + } +} + +#if OpenIGTLink_HEADER_VERSION >= 2 +void igtl_export igtl_extended_header_convert_byte_order(igtl_extended_header * extended_header) +{ + if (igtl_is_little_endian()) + { + extended_header->extended_header_size = BYTE_SWAP_INT16(extended_header->extended_header_size); + extended_header->meta_data_header_size = BYTE_SWAP_INT16(extended_header->meta_data_header_size); + extended_header->meta_data_size = BYTE_SWAP_INT32(extended_header->meta_data_size); + extended_header->message_id = BYTE_SWAP_INT32(extended_header->message_id); + } +} +#endif diff --git a/openigtlink/repo/Source/igtlutil/igtl_header.h b/openigtlink/repo/Source/igtlutil/igtl_header.h new file mode 100644 index 0000000..d731eac --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_header.h @@ -0,0 +1,101 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_HEADER_H +#define __IGTL_HEADER_H + +#define IGTL_HEADER_VERSION_1 1 +#define IGTL_HEADER_VERSION_2 2 +#define IGTL_HEADER_SIZE 58 +#define IGTL_EXTENDED_HEADER_SIZE 12 + +#define IGTL_HEADER_TYPE_SIZE 12 +#define IGTL_HEADER_NAME_SIZE 20 + +/* Following macros will be obsolete. Included for old programs*/ +#define IGTL_HEADER_TYPESIZE IGTL_HEADER_TYPE_SIZE +#define IGTL_HEADER_NAMESIZE IGTL_HEADER_NAME_SIZE +#define IGTL_HEADER_DEVSIZE IGTL_HEADER_NAME_SIZE + +/* Device name prefix macro */ +#define IGTL_TYPE_PREFIX_NONE 0 +#define IGTL_TYPE_PREFIX_GET 1 +#define IGTL_TYPE_PREFIX_STT 2 +#define IGTL_TYPE_PREFIX_STP 3 +#define IGTL_TYPE_PREFIX_RTS 4 +#define IGTL_NUM_TYPE_PREFIX 5 + +#include "igtl_types.h" +#include "igtl_win32header.h" +#include "igtlConfigure.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(2) /* For 2-byte boundary in memory */ + +/** Message header of OpenIGTLink message. + * igtl_header is an overall data header for OpenIGTLink protocol. + * It is transfered at beginning of every OpenIGTLink message to give + * type and size of following data body to a receiver. + * These parameters allow the receiver to parse or skip the data body. */ +typedef struct { + igtl_uint16 header_version; /* header version number */ + char name[IGTL_HEADER_TYPE_SIZE]; /* data type name */ + char device_name[IGTL_HEADER_NAME_SIZE]; /* device name */ + igtl_uint64 timestamp; /* time stamp message */ + igtl_uint64 body_size; /* size of the body */ + igtl_uint64 crc; /* CRC */ +} igtl_header; + +#if OpenIGTLink_HEADER_VERSION >= 2 +/** Message extended header of OpenIGTLink message. + * igtl_extended_header is an overall data extended header for OpenIGTLink protocol. + * It is transfered with the data body to define the + * size of extended header and the meta data size */ +typedef struct { + igtl_uint16 extended_header_size; /* size of extended header */ + igtl_uint16 meta_data_header_size; /* size of the meta data header*/ + igtl_uint32 meta_data_size; /* size of meta data */ + igtl_uint32 message_id; /* message id */ +} igtl_extended_header; + +typedef struct { + igtl_uint16 key_size; + igtl_uint16 value_encoding; + igtl_uint32 value_size; +} igtl_metadata_header_entry; +#endif + +#pragma pack() + +/** igtl_header_convert_byte_order() convers endianness of each + * member variable in igtl_header structure from host byte order + * to network byte order, or vice versa. */ +void igtl_export igtl_header_convert_byte_order(igtl_header * header); + +#if OpenIGTLink_HEADER_VERSION >= 2 +/** igtl_extended_header_convert_byte_order() convers endianness of each + * member variable in igtl_header structure from host byte order + * to network byte order, or vice versa. */ +void igtl_export igtl_extended_header_convert_byte_order(igtl_extended_header * extended_header); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_HEADER_H */ + diff --git a/openigtlink/repo/Source/igtlutil/igtl_image.c b/openigtlink/repo/Source/igtlutil/igtl_image.c new file mode 100644 index 0000000..af5123b --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_image.c @@ -0,0 +1,258 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_image.h" +#include "igtl_util.h" + +igtl_uint64 igtl_export igtl_image_get_data_size(igtl_image_header * header) +{ + igtl_uint64 si; + igtl_uint64 sj; + igtl_uint64 sk; + igtl_uint64 sp; + igtl_uint64 data_size; + + si = header->subvol_size[0]; + sj = header->subvol_size[1]; + sk = header->subvol_size[2]; + + switch (header->scalar_type) + { + case IGTL_IMAGE_STYPE_TYPE_INT8: + case IGTL_IMAGE_STYPE_TYPE_UINT8: + sp = 1; + break; + case IGTL_IMAGE_STYPE_TYPE_INT16: + case IGTL_IMAGE_STYPE_TYPE_UINT16: + sp = 2; + break; + case IGTL_IMAGE_STYPE_TYPE_INT32: + case IGTL_IMAGE_STYPE_TYPE_UINT32: + sp = 4; + break; + default: + sp = 0; + break; + } + + data_size = si*sj*sk*sp; + return data_size; +} + + +void igtl_export igtl_image_set_matrix(float spacing[3], float origin[3], + float norm_i[3], float norm_j[3], float norm_k[3], + igtl_image_header * header) +{ + header->matrix[0] = (igtl_float32) (norm_i[0] * spacing[0]); + header->matrix[1] = (igtl_float32) (norm_i[1] * spacing[0]); + header->matrix[2] = (igtl_float32) (norm_i[2] * spacing[0]); + header->matrix[3] = (igtl_float32) (norm_j[0] * spacing[1]); + header->matrix[4] = (igtl_float32) (norm_j[1] * spacing[1]); + header->matrix[5] = (igtl_float32) (norm_j[2] * spacing[1]); + header->matrix[6] = (igtl_float32) (norm_k[0] * spacing[2]); + header->matrix[7] = (igtl_float32) (norm_k[1] * spacing[2]); + header->matrix[8] = (igtl_float32) (norm_k[2] * spacing[2]); + header->matrix[9] = (igtl_float32) (origin[0]); + header->matrix[10] = (igtl_float32) (origin[1]); + header->matrix[11] = (igtl_float32) (origin[2]); +} + +void igtl_export igtl_image_set_matrix_4x4(float _matrix [4][4], igtl_image_header * header) +{ + header->matrix[0] = _matrix[0][0]; + header->matrix[1] = _matrix[0][1]; + header->matrix[2] = _matrix[0][2]; + header->matrix[3] = _matrix[1][0]; + header->matrix[4] = _matrix[1][1]; + header->matrix[5] = _matrix[1][2]; + header->matrix[6] = _matrix[2][0]; + header->matrix[7] = _matrix[2][1]; + header->matrix[8] = _matrix[2][2]; + header->matrix[9] = _matrix[0][3]; + header->matrix[10] = _matrix[1][3]; + header->matrix[11] = _matrix[2][3]; +} + +void igtl_export igtl_image_get_matrix(float spacing[3], float origin[3], + float norm_i[3], float norm_j[3], float norm_k[3], + igtl_image_header * header) +{ + float tx; + float ty; + float tz; + float sx; + float sy; + float sz; + float nx; + float ny; + float nz; + float px; + float py; + float pz; + + tx = (float) header->matrix[0]; + ty = (float) header->matrix[1]; + tz = (float) header->matrix[2]; + sx = (float) header->matrix[3]; + sy = (float) header->matrix[4]; + sz = (float) header->matrix[5]; + nx = (float) header->matrix[6]; + ny = (float) header->matrix[7]; + nz = (float) header->matrix[8]; + px = (float) header->matrix[9]; + py = (float) header->matrix[10]; + pz = (float) header->matrix[11]; + + spacing[0] = sqrtf(tx*tx + ty*ty + tz*tz); + spacing[1] = sqrtf(sx*sx + sy*sy + sz*sz); + spacing[2] = sqrtf(nx*nx + ny*ny + nz*nz); + + if (spacing[0] != 0) + { + norm_i[0] = header->matrix[0] / spacing[0]; + norm_i[1] = header->matrix[1] / spacing[0]; + norm_i[2] = header->matrix[2] / spacing[0]; + } + if (spacing[1] != 0) + { + norm_j[0] = header->matrix[3] / spacing[1]; + norm_j[1] = header->matrix[4] / spacing[1]; + norm_j[2] = header->matrix[5] / spacing[1]; + } + if (spacing[2] != 0) + { + norm_k[0] = header->matrix[6] / spacing[2]; + norm_k[1] = header->matrix[7] / spacing[2]; + norm_k[2] = header->matrix[8] / spacing[2]; + } + + origin[0] = header->matrix[9]; + origin[1] = header->matrix[10]; + origin[2] = header->matrix[11]; + +} + + +void igtl_export igtl_image_get_matrix_4x4(float _matrix[4][4], igtl_image_header * header) +{ + _matrix[0][0] = header->matrix[0]; + _matrix[0][1] = header->matrix[1]; + _matrix[0][2] = header->matrix[2]; + _matrix[1][0] = header->matrix[3]; + _matrix[1][1] = header->matrix[4]; + _matrix[1][2] = header->matrix[5]; + _matrix[2][0] = header->matrix[6]; + _matrix[2][1] = header->matrix[7]; + _matrix[2][2] = header->matrix[8]; + + _matrix[0][3] = header->matrix[9]; + _matrix[1][3] = header->matrix[10]; + _matrix[2][3] = header->matrix[11]; + + _matrix[3][0] = 0; + _matrix[3][1] = 0; + _matrix[3][2] = 0; + _matrix[3][3] = 1; +} + + +void igtl_export igtl_image_convert_byte_order(igtl_image_header * header) +{ + int i; + igtl_uint32 tmp[12]; + + if (igtl_is_little_endian()) + { + + header->header_version = BYTE_SWAP_INT16(header->header_version); + + for (i = 0; i < 3; i ++) + { + header->size[i] = BYTE_SWAP_INT16(header->size[i]); + header->subvol_size[i] = BYTE_SWAP_INT16(header->subvol_size[i]); + header->subvol_offset[i] = BYTE_SWAP_INT16(header->subvol_offset[i]); + } + + memcpy(tmp, header->matrix, sizeof(igtl_uint32)*12); + + /* + * TODO: The following loop may cause segmentation fault, when it is compiled + * with '-ftree-vectorize' optimization option on 64-bit Linux. + * ('-ftree-vectorize' becomes active, when '-O3' optimization is specified.) + * -- code has been updated on June 24 -- needs test + */ + for (i = 0; i < 12; i ++) + { + tmp[i] = BYTE_SWAP_INT32(tmp[i]); + } + memcpy(header->matrix, tmp, sizeof(igtl_uint32)*12); + + } +} + + +igtl_uint64 igtl_export igtl_image_get_crc(igtl_image_header * header, void* image) +{ + igtl_uint64 crc; + igtl_uint64 img_size; + + /* calculate image size (we do not call igtl_image_get_data_size() + * because header has already been serialized. + */ + igtl_uint64 si; + igtl_uint64 sj; + igtl_uint64 sk; + igtl_uint64 sp; + + if (igtl_is_little_endian()) + { + si = BYTE_SWAP_INT16(header->subvol_size[0]); + sj = BYTE_SWAP_INT16(header->subvol_size[1]); + sk = BYTE_SWAP_INT16(header->subvol_size[2]); + } + else + { + si = header->subvol_size[0]; + sj = header->subvol_size[1]; + sk = header->subvol_size[2]; + } + switch (header->scalar_type) { + case IGTL_IMAGE_STYPE_TYPE_INT8: + case IGTL_IMAGE_STYPE_TYPE_UINT8: + sp = 1; + break; + case IGTL_IMAGE_STYPE_TYPE_INT16: + case IGTL_IMAGE_STYPE_TYPE_UINT16: + sp = 2; + break; + case IGTL_IMAGE_STYPE_TYPE_INT32: + case IGTL_IMAGE_STYPE_TYPE_UINT32: + sp = 4; + break; + default: + sp = 0; + break; + } + + img_size = si*sj*sk*sp; + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) header, IGTL_IMAGE_HEADER_SIZE, crc); + crc = crc64((unsigned char*) image, (int)img_size, crc); + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_image.h b/openigtlink/repo/Source/igtlutil/igtl_image.h new file mode 100644 index 0000000..ffbe674 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_image.h @@ -0,0 +1,118 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_IMAGE_H +#define __IGTL_IMAGE_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_win32header.h" + +#define IGTL_IMAGE_HEADER_VERSION 1 +#define IGTL_IMAGE_HEADER_SIZE 72 + +/* Data type */ +#define IGTL_IMAGE_DTYPE_SCALAR 1 +#define IGTL_IMAGE_DTYPE_VECTOR 3 + +/* Scalar type */ +#define IGTL_IMAGE_STYPE_TYPE_INT8 2 +#define IGTL_IMAGE_STYPE_TYPE_UINT8 3 +#define IGTL_IMAGE_STYPE_TYPE_INT16 4 +#define IGTL_IMAGE_STYPE_TYPE_UINT16 5 +#define IGTL_IMAGE_STYPE_TYPE_INT32 6 +#define IGTL_IMAGE_STYPE_TYPE_UINT32 7 +#define IGTL_IMAGE_STYPE_TYPE_FLOAT32 10 +#define IGTL_IMAGE_STYPE_TYPE_FLOAT64 11 + +/* Endian */ +#define IGTL_IMAGE_ENDIAN_BIG 1 +#define IGTL_IMAGE_ENDIAN_LITTLE 2 + +/* Image coordinate system */ +#define IGTL_IMAGE_COORD_RAS 1 +#define IGTL_IMAGE_COORD_LPS 2 + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** Image data consists of image data header, which is defined in this + * structure, folowed by array of image pixel data. + * igtl_image_header helps a receiver to load array of image pixel data. + * The header supports "partial volume update", where a fraction of volume + * image is transferred from a sender to receiver. This fraction called + * "sub-volume" in this protocol, and its size and starting index is + * specified in 'subvol_size' and 'subvol_offset'. + * In case of transferring entire image in one message, 'size' and + * 'subvol_size' should be same, and 'subvol_offset' equals (0, 0, 0). */ +typedef struct { + igtl_uint16 header_version; /* data format version number(1) */ + igtl_uint8 num_components; /* number of components per element*/ + igtl_uint8 scalar_type; /* scalar type */ + /*2:int8 3:uint8 4:int16 5:uint16 6:int32 7:uint32 10:float32 11:float64) */ + igtl_uint8 endian; /* endian type of image data */ + /* (1:big, 2:little) */ + igtl_uint8 coord; /* coordinate system (1:RAS 2:LPS) */ + igtl_uint16 size[3]; /* entire image volume size */ + igtl_float32 matrix[12]; /* orientation / origin of image */ + /* - matrix[0-2]: norm_i * pix_i */ + /* - matrix[3-5]: norm_j * pix_j */ + /* - matrix[6-8]: norm_k * pix_k */ + /* - matrix[9-11]:origin */ + /* where norm_* are normal vectors */ + /* along each index, and pix_* are */ + /* pixel size in each direction */ + + igtl_uint16 subvol_offset[3]; /* sub volume offset */ + igtl_uint16 subvol_size[3]; /* sub volume size */ +} igtl_image_header; + +#pragma pack() + + +/** Calculates size of the pixel array, which will be transferred with the specified header. */ +igtl_uint64 igtl_export igtl_image_get_data_size(igtl_image_header * header); + + +/** Generates image orientation/origin matrix from spacing, origin and normal vectors. */ +void igtl_export igtl_image_set_matrix(float spacing[3], float origin[3], + float norm_i[3], float norm_j[3], float norm_k[3], + igtl_image_header * header); + +void igtl_export igtl_image_get_matrix(float spacing[3], float origin[3], + float norm_i[3], float norm_j[3], float norm_k[3], + igtl_image_header * header); + +/** Sets the image orientation/origin matrix in 4x4 format */ +void igtl_export igtl_image_set_matrix_4x4(float _matrix[4][4],igtl_image_header * header); + +/** Gets the image orientation/origin matrix in 4x4 format */ +void igtl_export igtl_image_get_matrix_4x4(float _matrix[4][4],igtl_image_header * header); + +/** Converts endianness of each member variable in igtl_image_header from host + * byte order to network byte order, or vice versa. */ +void igtl_export igtl_image_convert_byte_order(igtl_image_header * header); + +/** Calculates CRC of image data body including header and array of pixel data. */ +igtl_uint64 igtl_export igtl_image_get_crc(igtl_image_header * header, void* image); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_IMAGE_H */ diff --git a/openigtlink/repo/Source/igtlutil/igtl_imgmeta.c b/openigtlink/repo/Source/igtlutil/igtl_imgmeta.c new file mode 100644 index 0000000..24184c3 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_imgmeta.c @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_imgmeta.h" +#include "igtl_util.h" + +void igtl_export igtl_imgmeta_convert_byte_order(igtl_imgmeta_element* metalist, int nitem) +{ + igtl_imgmeta_element* elem; + int i; + + for (i = 0; i < nitem; i ++) + { + elem = &(metalist[i]); + if (igtl_is_little_endian()) + { + elem->timestamp = BYTE_SWAP_INT64(elem->timestamp); + elem->size[0] = BYTE_SWAP_INT16(elem->size[0]); + elem->size[1] = BYTE_SWAP_INT16(elem->size[1]); + elem->size[2] = BYTE_SWAP_INT16(elem->size[2]); + } + } +} + + +igtl_uint64 igtl_export igtl_imgmeta_get_crc(igtl_imgmeta_element* metalist, int nitem) +{ + igtl_imgmeta_element* elem; + int i; + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + for (i = 0; i < nitem; i ++) + { + elem = &(metalist[i]); + crc = crc64((unsigned char*) elem, IGTL_IMGMETA_ELEMENT_SIZE, crc); + } + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_imgmeta.h b/openigtlink/repo/Source/igtlutil/igtl_imgmeta.h new file mode 100644 index 0000000..4076180 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_imgmeta.h @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_IMGMETA_H +#define __IGTL_IMGMETA_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_image.h" + +#define IGTL_IMGMETA_ELEMENT_SIZE 260 + +/* Scalar type */ +/* Use the same numbers as IMAGE */ +/* +#define IGTL_IMGMETA_STYPE_TYPE_INT8 2 +#define IGTL_IMGMETA_STYPE_TYPE_UINT8 3 +#define IGTL_IMGMETA_STYPE_TYPE_INT16 4 +#define IGTL_IMGMETA_STYPE_TYPE_UINT16 5 +#define IGTL_IMGMETA_STYPE_TYPE_INT32 6 +#define IGTL_IMGMETA_STYPE_TYPE_UINT32 7 +#define IGTL_IMGMETA_STYPE_TYPE_FLOAT32 10 +#define IGTL_IMGMETA_STYPE_TYPE_FLOAT64 11 +*/ + +#define IGTL_IMGMETA_LEN_NAME 64 +#define IGTL_IMGMETA_LEN_DEVICE_NAME 20 +#define IGTL_IMGMETA_LEN_MODALITY 32 +#define IGTL_IMGMETA_LEN_PATIENT_NAME 64 +#define IGTL_IMGMETA_LEN_PATIENT_ID 64 + + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** IMAGEMETA is a message type to transfer a list of images available in a server. + * A IMGMETA message may contain information of multiple images. + * The client determins the number of image meta by the size of the body included + * in the message header (see igtl_imgmeta_getdata_n() macro). */ +typedef struct { + char name[IGTL_IMGMETA_LEN_NAME]; /* name / description */ + char device_name[IGTL_IMGMETA_LEN_DEVICE_NAME]; /* device name to query the IMAGE and COLORT */ + char modality[IGTL_IMGMETA_LEN_MODALITY]; /* modality name */ + char patient_name[IGTL_IMGMETA_LEN_PATIENT_NAME]; /* patient name */ + char patient_id[IGTL_IMGMETA_LEN_PATIENT_ID]; /* patient ID (MRN etc.) */ + igtl_uint64 timestamp; /* scan time */ + igtl_uint16 size[3]; /* entire image volume size */ + igtl_uint8 scalar_type; /* scalar type. see scalar_type in IMAGE message */ + igtl_uint8 reserved; +} igtl_imgmeta_element; + +#pragma pack() + +/** igtl_imgmeta_get_data_size(n) macro calculates the size of body based on the number + * of images.The size of body is used in the message header. + * igtl_imgmeta_get_data_n(size) calculates the number of images in the body, based on + * the body size. This function may be used when a client program parses IMGMETA message. */ +#define igtl_imgmeta_get_data_size(n) ((n) * IGTL_IMGMETA_ELEMENT_SIZE) +#define igtl_imgmeta_get_data_n(size) ((size) / IGTL_IMGMETA_ELEMENT_SIZE) + +/** Converts endianness of each member variable in igtl_imgmeta_element from host + * byte order to network byte order, or vice versa. */ +void igtl_export igtl_imgmeta_convert_byte_order(igtl_imgmeta_element* metalist, int nitem); + +/** Clculates CRC of image meta data body. */ +igtl_uint64 igtl_export igtl_imgmeta_get_crc(igtl_imgmeta_element* metalist, int nitem); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_IMGMETA_H */ diff --git a/openigtlink/repo/Source/igtlutil/igtl_lbmeta.c b/openigtlink/repo/Source/igtlutil/igtl_lbmeta.c new file mode 100644 index 0000000..b68a19d --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_lbmeta.c @@ -0,0 +1,54 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_lbmeta.h" +#include "igtl_util.h" + + +void igtl_export igtl_lbmeta_convert_byte_order(igtl_lbmeta_element* metalist, int nitem) +{ + igtl_lbmeta_element* elem; + int i; + + for (i = 0; i < nitem; i ++) + { + elem = &(metalist[i]); + if (igtl_is_little_endian()) + { + elem->size[0] = BYTE_SWAP_INT16(elem->size[0]); + elem->size[1] = BYTE_SWAP_INT16(elem->size[1]); + elem->size[2] = BYTE_SWAP_INT16(elem->size[2]); + } + } +} + + +igtl_uint64 igtl_export igtl_lbmeta_get_crc(igtl_lbmeta_element* metalist, int nitem) +{ + igtl_lbmeta_element* elem; + int i; + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + for (i = 0; i < nitem; i ++) + { + elem = &(metalist[i]); + crc = crc64((unsigned char*) elem, IGTL_LBMETA_ELEMENT_SIZE, crc); + } + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_lbmeta.h b/openigtlink/repo/Source/igtlutil/igtl_lbmeta.h new file mode 100644 index 0000000..bf95700 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_lbmeta.h @@ -0,0 +1,113 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_LBMETA_H +#define __IGTL_LBMETA_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" + +#define IGTL_LBMETA_ELEMENT_SIZE 116 + +#define IGTL_LBMETA_LEN_NAME 64 +#define IGTL_LBMETA_LEN_DEVICE_NAME 20 +#define IGTL_LBMETA_LEN_OWNER 20 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Label meta data in OpenIGTLinik protocol + * + * LBMETA is a data type to send a list of label image data available in a server. + * In OpenIGTLink protocol, actual label data is transfered as an IMAGE message. + * LBMETA message lets the receiving client know which IMAGE data are available + * as label maps. + * Multiple labels in a LBMETA message can point the same IMAGE message, if there + * are multiple lables are recoreded in a single IMAGE mesage. For example, given + * the following label map as IMAGE data with name "LableImage1": + * + * 0 0 0 1 0 0 value | name / description + * 2 0 1 1 1 0 --------+---------------------------- + * 2 2 1 1 1 0 0 | None + * 2 2 2 1 0 0 1 | Liver + * 2 2 2 2 0 0 2 | Kidney + * + * To send the label information recorded in "LabelImage1," one can create + * a following LBMETA message: + * + * DATA | Contents + * ---------------+--------------------------- + * NAME 1 | Liver + * IMAGE NAME 1 | LabelImage + * Labe l | 1 + * RGBA 1 | 0xFF0000 + * SIZE 1 | (6, 5, 1) + * OWNER 1 | + * --------------+--------------------------- + * NAME 2 | Kidney + * IMAGE NAME 2 | LabelImage + * Labe 2 | 2 + * RGBA 2 | 0xFF2222 + * SIZE 2 | (6, 5, 1) + * OWNER 2 | + * --------------+--------------------------- + * + * ... .... + * + * --------------+--------------------------- + * + * The client determins the number of image meta by the size of the body included + * in the message header (see igtl_lbmeta_getdata_n() macro). + */ + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +typedef struct { + char name[IGTL_LBMETA_LEN_NAME]; /* name / description */ + char device_name[IGTL_LBMETA_LEN_DEVICE_NAME]; /* device name to query the IMAGE */ + igtl_uint8 label; /* label */ + igtl_uint8 reserved; + igtl_uint8 rgba[4]; /* Color in RGBA. default: (0, 0, 0, 0) */ + igtl_uint16 size[3]; /* Number of pixels in each direction */ + char owner[IGTL_LBMETA_LEN_OWNER];/* Device name of the owner image. (can be empty) */ +} igtl_lbmeta_element; + +#pragma pack() + + +/** igtl_lbmeta_get_data_size(n) calculates the size of body based on the number + * of images.The size of body is used in the message header.*/ +#define igtl_lbmeta_get_data_size(n) ((n) * IGTL_LBMETA_ELEMENT_SIZE) + +/** igtl_lbmeta_get_data_n(size) calculates the number of images in the body, based on + * the body size. This function may be used when a client program parses LBMETA message. */ +#define igtl_lbmeta_get_data_n(size) ((size) / IGTL_LBMETA_ELEMENT_SIZE) + +/** Converts endianness of each member variable in igtl_lbmeta_element + * from host byte order to network byte order, or vice versa. */ +void igtl_export igtl_lbmeta_convert_byte_order(igtl_lbmeta_element* metalist, int nitem); + +/** Calculates CRC of image meta data body. */ +igtl_uint64 igtl_export igtl_lbmeta_get_crc(igtl_lbmeta_element* metalist, int nitem); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_LBMETA_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_ndarray.c b/openigtlink/repo/Source/igtlutil/igtl_ndarray.c new file mode 100644 index 0000000..6790718 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_ndarray.c @@ -0,0 +1,385 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_ndarray.h" +#include "igtl_util.h" + + +void igtl_export igtl_ndarray_init_info(igtl_ndarray_info * info) +{ + info->type = 0; + info->dim = 0; + info->size = NULL; + info->array = NULL; +} + + +/* Calculate number of bytes / element */ +igtl_uint32 igtl_ndarray_get_nbyte(int type) +{ + igtl_uint32 bytes; + + switch (type) + { + case IGTL_NDARRAY_STYPE_TYPE_INT8: + case IGTL_NDARRAY_STYPE_TYPE_UINT8: + bytes = 1; + break; + case IGTL_NDARRAY_STYPE_TYPE_INT16: + case IGTL_NDARRAY_STYPE_TYPE_UINT16: + bytes = 2; + break; + case IGTL_NDARRAY_STYPE_TYPE_INT32: + case IGTL_NDARRAY_STYPE_TYPE_UINT32: + case IGTL_NDARRAY_STYPE_TYPE_FLOAT32: + bytes = 4; + break; + case IGTL_NDARRAY_STYPE_TYPE_FLOAT64: + bytes = 8; + break; + case IGTL_NDARRAY_STYPE_TYPE_COMPLEX: + bytes = 16; + break; + default: + bytes = 0; + break; + } + + return bytes; +} + + +int igtl_export igtl_ndarray_alloc_info(igtl_ndarray_info * info, const igtl_uint16 * size) +{ + int i; + igtl_uint64 len; + + if (info->size == NULL && info->array == NULL) + { + info->size = malloc(sizeof(igtl_uint16) * (igtl_uint16) info->dim); + if (info->size == NULL) + { + return 0; + } + len = 1; + + for (i = 0; i < info->dim; i ++) + { + info->size[i] = size[i]; + len *= size[i]; + } + + info->array = malloc((size_t)(igtl_ndarray_get_nbyte(info->type) * len)); + + if (info->array == NULL) + { + free(info->size); + return 0; + } + + return 1; + } + else + { + return 0; + } +} + + +int igtl_export igtl_ndarray_free_info(igtl_ndarray_info * info) +{ + if (info->size) + { + free(info->size); + } + if (info->array) + { + free(info->array); + } + + return 1; +} + + +int igtl_export igtl_ndarray_unpack(int type, void * byte_array, igtl_ndarray_info * info, igtl_uint64 pack_size) +{ + char * ptr; + igtl_uint16 dim; + igtl_uint16 * size; + igtl_uint16 i; + igtl_uint64 len; + + igtl_uint16 * ptr16_src; + igtl_uint16 * ptr16_src_end; + igtl_uint16 * ptr16_dst; + + igtl_uint32 * ptr32_src; + igtl_uint32 * ptr32_src_end; + igtl_uint32 * ptr32_dst; + + igtl_uint64 * ptr64_src; + igtl_uint64 * ptr64_src_end; + igtl_uint64 * ptr64_dst; + + + if (byte_array == NULL || info == NULL) + { + return 0; + } + + igtl_ndarray_init_info(info); + ptr = (char *) byte_array; + + /*** Type field ***/ + info->type = * (igtl_uint8 *) ptr; + ptr ++; + + /*** Dimension field ***/ + info->dim = * (igtl_uint8 *) ptr; + ptr ++; + + /*** Size array field ***/ + size = (igtl_uint16 *) ptr; + dim = info->dim; + if (igtl_is_little_endian()) + { + /* Change byte order -- this overwrites memory area for the pack !!*/ + for (i = 0; i < dim; i ++) + { + size[i] = BYTE_SWAP_INT16(size[i]); + } + } + + igtl_ndarray_alloc_info(info, size); + + memcpy(info->size, size, sizeof(igtl_uint16) * dim); + if (igtl_is_little_endian()) + { + /* Resotore the overwritten memory area */ + /* Don't use size[] array after this !! */ + for (i = 0; i < dim; i ++) + { + size[i] = BYTE_SWAP_INT16(size[i]); + } + } + ptr += sizeof(igtl_uint16) * dim; + + /*** N-D array field ***/ + /* Calculate number of elements in N-D array */ + len = 1; + for (i = 0; i < dim; i ++) + { + len *= info->size[i]; + } + + /* Copy array */ + if (igtl_ndarray_get_nbyte(info->type) == 1 || !igtl_is_little_endian()) + { + /* If single-byte data type is used or the program runs on a big-endian machine, + just copy the array from the pack to the strucutre */ + memcpy(info->array, ptr, (size_t)(len * igtl_ndarray_get_nbyte(info->type))); + } + else if (igtl_ndarray_get_nbyte(info->type) == 2) /* 16-bit */ + { + ptr16_src = (igtl_uint16 *) ptr; + ptr16_src_end = ptr16_src + len; + ptr16_dst = (igtl_uint16 *) info->array; + while (ptr16_src < ptr16_src_end) + { + *ptr16_dst = BYTE_SWAP_INT16(*ptr16_src); + ptr16_dst ++; + ptr16_src ++; + } + } + else if (igtl_ndarray_get_nbyte(info->type) == 4) /* 32-bit */ + { + ptr32_src = (igtl_uint32 *) ptr; + ptr32_src_end = ptr32_src + len; + ptr32_dst = (igtl_uint32 *) info->array; + while (ptr32_src < ptr32_src_end) + { + *ptr32_dst = BYTE_SWAP_INT32(*ptr32_src); + ptr32_dst ++; + ptr32_src ++; + } + } + else /* 64-bit or Complex type */ + { + ptr64_src = (igtl_uint64 *) ptr; + /* Adding number of elements to the pointer -- 64-bit: len * 1; Complex: len * 2*/ + ptr64_src_end = ptr64_src + len * igtl_ndarray_get_nbyte(info->type)/8; + ptr64_dst = (igtl_uint64 *) info->array; + while (ptr64_src < ptr64_src_end) + { + *ptr64_dst = BYTE_SWAP_INT64(*ptr64_src); + ptr64_dst ++; + ptr64_src ++; + } + } + + /* TODO: check if the pack size is valid */ + + return 1; + +} + + +int igtl_export igtl_ndarray_pack(igtl_ndarray_info * info, void * byte_array, int type) +{ + char * ptr; + igtl_uint16 dim; + igtl_uint16 * size; + igtl_uint16 i; + igtl_uint64 len; + + igtl_uint16 * ptr16_src; + igtl_uint16 * ptr16_src_end; + igtl_uint16 * ptr16_dst; + + igtl_uint32 * ptr32_src; + igtl_uint32 * ptr32_src_end; + igtl_uint32 * ptr32_dst; + + igtl_uint64 * ptr64_src; + igtl_uint64 * ptr64_src_end; + igtl_uint64 * ptr64_dst; + + + if (byte_array == NULL || info == NULL) + { + return 0; + } + + ptr = (char *) byte_array; + + /*** Type field ***/ + * (igtl_uint8 *) ptr = info->type; + ptr ++; + + /*** Dimension field ***/ + * (igtl_uint8 *) ptr = info->dim; + ptr ++; + + /*** Size array field ***/ + size = (igtl_uint16 *) ptr; + if (igtl_is_little_endian()) + { + for (i = 0; i < info->dim; i ++) + { + size[i] = BYTE_SWAP_INT16(info->size[i]); + } + } + else + { + memcpy(ptr, info->size, sizeof(igtl_uint16) * info->dim); + } + + dim = info->dim; + ptr += sizeof(igtl_uint16) * dim; + + /*** N-D array field ***/ + /* Calculate number of elements in N-D array */ + len = 1; + for (i = 0; i < dim; i ++) + { + len *= info->size[i]; + } + + /* Copy array */ + if (igtl_ndarray_get_nbyte(info->type) == 1 || !igtl_is_little_endian()) + { + /* If single-byte data type is used or the program runs on a big-endian machine, + just copy the array from the pack to the strucutre */ + memcpy(ptr, info->array, (size_t) (len * igtl_ndarray_get_nbyte(info->type))); + } + else if (igtl_ndarray_get_nbyte(info->type) == 2) /* 16-bit */ + { + ptr16_src = (igtl_uint16 *) info->array; + ptr16_src_end = ptr16_src + len; + ptr16_dst = (igtl_uint16 *) ptr; + while (ptr16_src < ptr16_src_end) + { + *ptr16_dst = BYTE_SWAP_INT16(*ptr16_src); + ptr16_dst ++; + ptr16_src ++; + } + } + else if (igtl_ndarray_get_nbyte(info->type) == 4) /* 32-bit */ + { + ptr32_src = (igtl_uint32 *) info->array; + ptr32_src_end = ptr32_src + len; + ptr32_dst = (igtl_uint32 *) ptr; + while (ptr32_src < ptr32_src_end) + { + *ptr32_dst = BYTE_SWAP_INT32(*ptr32_src); + ptr32_dst ++; + ptr32_src ++; + } + } + else /* 64-bit or Complex type */ + { + ptr64_src = (igtl_uint64 *) info->array; + /* Adding number of elements to the pointer -- 64-bit: len * 1; Complex: len * 2*/ + ptr64_src_end = ptr64_src + len * igtl_ndarray_get_nbyte(info->type)/8; + ptr64_dst = (igtl_uint64 *) ptr; + while (ptr64_src < ptr64_src_end) + { + *ptr64_dst = BYTE_SWAP_INT64(*ptr64_src); + ptr64_dst ++; + ptr64_src ++; + } + } + + return 1; + +} + + +igtl_uint64 igtl_export igtl_ndarray_get_size(igtl_ndarray_info * info, int type) +{ + igtl_uint64 len; + igtl_uint64 data_size; + igtl_uint16 i; + igtl_uint16 dim; + + dim = info->dim; + len = 1; + for (i = 0; i < dim; i ++) + { + len *= (igtl_uint64)info->size[i]; + } + + data_size = sizeof(igtl_uint8) * 2 + sizeof(igtl_uint16) * (igtl_uint64) dim + + len * igtl_ndarray_get_nbyte(info->type); + + return data_size; + +} + + +igtl_uint64 igtl_export igtl_ndarray_get_crc(igtl_ndarray_info * info, int type, void* data) +{ + igtl_uint64 crc; + igtl_uint64 data_size; + + data_size = igtl_ndarray_get_size(info, type); + + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) data, data_size, crc); + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_ndarray.h b/openigtlink/repo/Source/igtlutil/igtl_ndarray.h new file mode 100644 index 0000000..99d8643 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_ndarray.h @@ -0,0 +1,94 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_NDARRAY_H +#define __IGTL_NDARRAY_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_win32header.h" + +#define IGTL_NDARRAY_HEADER_SIZE 2 + +/* Scalar type */ +#define IGTL_NDARRAY_STYPE_TYPE_INT8 2 +#define IGTL_NDARRAY_STYPE_TYPE_UINT8 3 +#define IGTL_NDARRAY_STYPE_TYPE_INT16 4 +#define IGTL_NDARRAY_STYPE_TYPE_UINT16 5 +#define IGTL_NDARRAY_STYPE_TYPE_INT32 6 +#define IGTL_NDARRAY_STYPE_TYPE_UINT32 7 +#define IGTL_NDARRAY_STYPE_TYPE_FLOAT32 10 +#define IGTL_NDARRAY_STYPE_TYPE_FLOAT64 11 +#define IGTL_NDARRAY_STYPE_TYPE_COMPLEX 13 + +#define IGTL_NDARRAY_HOST_TO_NETWORK 0 +#define IGTL_NDARRAY_NETWORK_TO_HOST 1 + + +#ifdef __cplusplus +extern "C" { +#endif + +/** NDARRAY is a data type, which is designed to transfer N-dimensional numerical array. + * The message body consists of N-D array header, size table, and N-D array body. */ +typedef struct { + igtl_uint8 type; /* Scalar type (2:int8 3:uint8 4:int16 5:uint16 6:int32 + 7:uint32 10:float32 11:float64 13:complex) */ + igtl_uint8 dim; /* Dimension of array */ + igtl_uint16 * size; /* Array size */ + void * array; +} igtl_ndarray_info; + + +/** Initializes igtl_ndarray_info */ +void igtl_export igtl_ndarray_init_info(igtl_ndarray_info * info); + +/** Allocates size array and ND-array pointed from igtl_ndarray_info. + * 'type' and 'dim' in igtl_ndarray_info must be specified before + * calling igtl_ndarray_alloc_info(). + * + * For example: Given info->type = 10 (i.e. 4 bytes), info->dim = 2 and size[dim] = {2, 3}, + * the amount of memory allocated is 2 * 3 * 4 = 24 bytes. + */ +int igtl_export igtl_ndarray_alloc_info(igtl_ndarray_info * info, const igtl_uint16 * size); + +/** Frees ndarray */ +int igtl_export igtl_ndarray_free_info(igtl_ndarray_info * info); + +/** Unpacks and extracts information in a byte array of NDARRAY messages and store + * it in a igtl_ndarray_info structure. 'type' argument specifies + * a message type prefix (none, GET_, STT_, STP_ or RTS_) by IGTL_TYPE_PREFIX_* macro. + * Returns 1 if success, otherwise 0. */ +int igtl_export igtl_ndarray_unpack(int type, void * byte_array, igtl_ndarray_info * info, igtl_uint64 pack_size); + +/** Converts an igtl_ndarray_info structure to a byte array. + * 'byte_array' should be allocated prior to calling igtl_ndarray_pack() with memory size + * calculated by igtl_ndarray_get_size(). 'type' argument specifies a message type prefix + * (none, or GET_) by IGTL_TYPE_PREFIX_* macro. Returns 1 if success, otherwise 0. */ +int igtl_export igtl_ndarray_pack(igtl_ndarray_info * info, void * byte_array, int type); + +/** Calculates size of N-D array body including + * size table (defined by UINT16[dim]) and array data. */ +igtl_uint64 igtl_export igtl_ndarray_get_size(igtl_ndarray_info * info, int type); + +/** Calculates CRC of image data body including header and array of pixel data. */ +igtl_uint64 igtl_export igtl_ndarray_get_crc(igtl_ndarray_info * info, int type, void* byte_array); + + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_NDARRAY_H */ diff --git a/openigtlink/repo/Source/igtlutil/igtl_point.c b/openigtlink/repo/Source/igtlutil/igtl_point.c new file mode 100644 index 0000000..48cdc78 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_point.c @@ -0,0 +1,59 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_point.h" +#include "igtl_util.h" + +void igtl_export igtl_point_convert_byte_order(igtl_point_element* pointlist, int nitem) +{ + igtl_point_element* elem; + int i; + int j; + igtl_int32* tmp; + + for (i = 0; i < nitem; i ++) + { + elem = &(pointlist[i]); + if (igtl_is_little_endian()) + { + for (j = 0; j < 3; j ++) + { + tmp = (igtl_int32*)&(elem->position[j]); + *tmp = BYTE_SWAP_INT32(*tmp); + } + tmp = (igtl_int32*)&(elem->radius); + *tmp = BYTE_SWAP_INT32(*tmp); + } + } +} + + +igtl_uint64 igtl_export igtl_point_get_crc(igtl_point_element* pointlist, int nitem) +{ + igtl_point_element* elem; + int i; + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + for (i = 0; i < nitem; i ++) + { + elem = &(pointlist[i]); + crc = crc64((unsigned char*) elem, IGTL_POINT_ELEMENT_SIZE, crc); + } + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_point.h b/openigtlink/repo/Source/igtlutil/igtl_point.h new file mode 100644 index 0000000..346fbca --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_point.h @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_POINT_H +#define __IGTL_POINT_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" + +#define IGTL_POINT_ELEMENT_SIZE 136 + +#define IGTL_POINT_LEN_NAME 64 +#define IGTL_POINT_LEN_GROUP_NAME 32 +#define IGTL_POINT_LEN_OWNER 20 + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** Status data header for OpenIGTLinik protocol */ +typedef struct { + char name[IGTL_POINT_LEN_NAME]; /* Name or description of the point */ + char group_name[IGTL_POINT_LEN_GROUP_NAME]; /* Can be "Labeled Point", "Landmark", Fiducial", ... */ + igtl_uint8 rgba[4]; /* Color in R/G/B/A */ + igtl_float32 position[3]; /* Coordinate of the point */ + igtl_float32 radius; /* Radius of the point. Can be 0. */ + char owner[IGTL_POINT_LEN_OWNER];/* Device name of the ower image */ +} igtl_point_element; + +#pragma pack() + +/** igtl_point_get_data_size(n) calculates the size of body based on the number + * of points. The size of body is used in the message header.*/ +#define igtl_point_get_data_size(n) ((n) * IGTL_POINT_ELEMENT_SIZE) + +/** igtl_point_get_data_n(size) calculates the number of images in the body, based on + * the body size. This function may be used when a client program parses a POINT message. */ +#define igtl_point_get_data_n(size) ((size) / IGTL_POINT_ELEMENT_SIZE) + +/** Converts endianness of each element in an array of + * igtl_igtl_point_element from host byte order to network byte order, + * or vice versa. */ +void igtl_export igtl_point_convert_byte_order(igtl_point_element* pointlist, int nelem); + +/** Calculates CRC of point message */ +igtl_uint64 igtl_export igtl_point_get_crc(igtl_point_element* pointlist, int nelem); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_POINT_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_polydata.c b/openigtlink/repo/Source/igtlutil/igtl_polydata.c new file mode 100644 index 0000000..4b1ddfb --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_polydata.c @@ -0,0 +1,751 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_polydata.h" +#include "igtl_util.h" + + +void igtl_export igtl_polydata_init_info(igtl_polydata_info * info) +{ + if (info) + { + info->header.npoints = 0; + info->header.nvertices = 0; + info->header.size_vertices = 0; + info->header.nlines = 0; + info->header.size_lines = 0; + info->header.npolygons = 0; + info->header.size_polygons = 0; + info->header.ntriangle_strips = 0; + info->header.size_triangle_strips = 0; + info->header.nattributes = 0; + info->points = NULL; + info->vertices = NULL; + info->lines = NULL; + info->polygons = NULL; + info->triangle_strips = NULL; + info->attributes = NULL; + } +} + + +int igtl_export igtl_polydata_alloc_info(igtl_polydata_info * info) +{ + /*size_t size;*/ + unsigned int i; + + if (info == NULL) + { + return 0; + } + + /** Points **/ + if (info->points) + { + free(info->points); + info->points = NULL; + } + if (info->header.npoints > 0) + { + info->points = malloc(info->header.npoints * sizeof(igtl_float32) * 3); + if (info->points == NULL) + { + return 0; + } + } + + /** Vertices **/ + if (info->vertices) + { + free(info->vertices); + info->vertices = NULL; + } + if (info->header.nvertices > 0) + { + info->vertices = malloc(info->header.size_vertices); + if (info->vertices == NULL) + { + return 0; + } + } + + /** Lines **/ + if (info->lines) + { + free(info->lines); + info->lines = NULL; + } + if (info->header.nlines > 0) + { + info->lines = malloc(info->header.size_lines); + if (info->lines == NULL) + { + return 0; + } + } + + /** Polygons **/ + if (info->polygons) + { + free(info->polygons); + } + if (info->header.npolygons > 0) + { + info->polygons = malloc(info->header.size_polygons); + if (info->polygons == NULL) + { + return 0; + } + } + + /** Triangle strips **/ + if (info->triangle_strips) + { + free(info->triangle_strips); + } + if (info->header.ntriangle_strips > 0) + { + info->triangle_strips = malloc(info->header.size_triangle_strips); + if (info->triangle_strips == NULL) + { + return 0; + } + } + + /** Attributes **/ + if (info->attributes) + { + for (i = 0; i < info->header.nattributes; i ++) + { + if (info->attributes[i].name) + { + free(info->attributes[i].name); + } + if (info->attributes[i].data) + { + free(info->attributes[i].data); + } + } + free(info->attributes); + } + + if (info->header.nattributes > 0) + { + info->attributes = malloc(sizeof(igtl_polydata_attribute) * info->header.nattributes); + if (info->attributes == NULL) + { + return 0; + } + for (i = 0; i < info->header.nattributes; i ++) + { + info->attributes[i].type = 0; + info->attributes[i].ncomponents = 1; + info->attributes[i].n = 0; + info->attributes[i].name = NULL; + info->attributes[i].data = NULL; + } + } + + return 1; + +} + + +int igtl_export igtl_polydata_free_info(igtl_polydata_info * info) +{ + unsigned int i; + + if (info == NULL) + { + return 0; + } + + /** Points **/ + if (info->points) + { + free(info->points); + info->points = NULL; + } + + /** Vertices **/ + if (info->vertices) + { + free(info->vertices); + info->vertices = NULL; + } + + /** Lines **/ + if (info->lines) + { + free(info->lines); + info->lines = NULL; + } + + /** Polygons **/ + if (info->polygons) + { + free(info->polygons); + info->polygons = NULL; + } + + /** Triangle strips **/ + if (info->triangle_strips) + { + free(info->triangle_strips); + info->triangle_strips = NULL; + } + + /** Attributes **/ + if (info->attributes) + { + for (i = 0; i < info->header.nattributes; i ++) + { + if (info->attributes[i].name) + { + free(info->attributes[i].name); + } + if (info->attributes[i].data) + { + free(info->attributes[i].data); + } + } + free(info->attributes); + } + + return 1; + +} + + +int igtl_polydata_convert_byteorder_topology(igtl_uint32 * dst, igtl_uint32 * src, igtl_uint32 size) +{ + igtl_uint32 * ptr32_src; + igtl_uint32 * ptr32_src_end; + igtl_uint32 * ptr32_dst; + + if (size == 0) + { + return 1; + } + + if (!src || !dst) + { + /* Return error, if either src or dst is NULL despite size>0 */ + return 0; + } + + if (!igtl_is_little_endian()) + { + memcpy((void*)dst, (void*)src, size); + } + else + { + ptr32_src = (igtl_uint32 *) src; + ptr32_src_end = ptr32_src + (size/sizeof(igtl_uint32)); + ptr32_dst = (igtl_uint32 *) dst; + while (ptr32_src < ptr32_src_end) + { + *ptr32_dst = BYTE_SWAP_INT32(*ptr32_src); + ptr32_dst ++; + ptr32_src ++; + } + } + + return 1; +} + + +int igtl_export igtl_polydata_unpack(int type, void * byte_array, igtl_polydata_info * info, igtl_uint64 size) +{ + /* size = number of points (not number of bytes). In case of vertices, this is specified + by size_vertices in igtl_polydata_header. */ + igtl_polydata_header * header; + char * ptr; + + igtl_uint32 * ptr32_src; + igtl_uint32 * ptr32_src_end; + igtl_uint32 * ptr32_dst; + igtl_uint32 s; + + igtl_polydata_attribute_header * att_header; + igtl_polydata_attribute * att; + + int total_name_length; + int name_length; + char name_buf[IGTL_POLY_MAX_ATTR_NAME_LEN+1]; + + unsigned int i; + int n; + + if (byte_array == NULL || info == NULL || size == 0) + { + return 0; + } + + /* POLYDATA header */ + header = (igtl_polydata_header *) byte_array; + if (igtl_is_little_endian()) + { + info->header.npoints = BYTE_SWAP_INT32(header->npoints); + info->header.nvertices = BYTE_SWAP_INT32(header->nvertices); + info->header.size_vertices = BYTE_SWAP_INT32(header->size_vertices); + info->header.nlines = BYTE_SWAP_INT32(header->nlines); + info->header.size_lines = BYTE_SWAP_INT32(header->size_lines); + info->header.npolygons = BYTE_SWAP_INT32(header->npolygons); + info->header.size_polygons = BYTE_SWAP_INT32(header->size_polygons); + info->header.ntriangle_strips = BYTE_SWAP_INT32(header->ntriangle_strips); + info->header.size_triangle_strips = BYTE_SWAP_INT32(header->size_triangle_strips); + info->header.nattributes = BYTE_SWAP_INT32(header->nattributes); + } + else + { + memcpy(&(info->header), header, sizeof(igtl_polydata_header)); + } + + /* Allocate memory to read data */ + /* TODO: compare the size of info before copying the header. */ + /* If the size doesn't change, avoid reallocation of memory. */ + if (igtl_polydata_alloc_info(info) == 0) + { + return 0; + } + + /* POINT section */ + ptr = (char*) byte_array + sizeof(igtl_polydata_header); + if (!igtl_is_little_endian()) + { + memcpy(info->points, ptr, sizeof(igtl_float32)*info->header.npoints*3); + } + else + { + ptr32_src = (igtl_uint32 *) ptr; + ptr32_src_end = ptr32_src + info->header.npoints*3; + ptr32_dst = (igtl_uint32 *) info->points; + while (ptr32_src < ptr32_src_end) + { + *ptr32_dst = BYTE_SWAP_INT32(*ptr32_src); + ptr32_dst ++; + ptr32_src ++; + } + } + + ptr += sizeof(igtl_float32)*info->header.npoints*3; + + /* Check size parameters */ + if (info->header.size_vertices%sizeof(igtl_uint32) != 0 || + info->header.size_lines%sizeof(igtl_uint32) != 0 || + info->header.size_polygons%sizeof(igtl_uint32) != 0 || + info->header.size_triangle_strips%sizeof(igtl_uint32)) + { + /* More than one of size parameters is multiples of 4 (size of 32-bit value) */ + return 0; + } + + /* VERTICES section */ + igtl_polydata_convert_byteorder_topology(info->vertices, (igtl_uint32*)ptr, info->header.size_vertices); + ptr += info->header.size_vertices; + + /* LINES section */ + igtl_polydata_convert_byteorder_topology(info->lines, (igtl_uint32*)ptr, info->header.size_lines); + ptr += info->header.size_lines; + + /* POLYGONS section */ + igtl_polydata_convert_byteorder_topology(info->polygons, (igtl_uint32*)ptr, info->header.size_polygons); + ptr += info->header.size_polygons; + + /* TRIANGLE_STRIPS section */ + igtl_polydata_convert_byteorder_topology(info->triangle_strips, (igtl_uint32*)ptr, info->header.size_triangle_strips); + ptr += info->header.size_triangle_strips; + + /* Attribute header */ + for (i = 0; i < info->header.nattributes; i ++) + { + att = &(info->attributes[i]); + att_header = (igtl_polydata_attribute_header *) ptr; + att->type = att_header->type; + att->ncomponents = att_header->ncomponents; + if (igtl_is_little_endian()) + { + att->n = BYTE_SWAP_INT32(att_header->n); + } + else + { + att->n = att_header->n; + } + ptr += sizeof(igtl_polydata_attribute_header); + } + + /* Attribute names */ + total_name_length = 0; + name_buf[IGTL_POLY_MAX_ATTR_NAME_LEN] = '\0'; + for (i = 0; i < info->header.nattributes; i ++) + { + name_length = strlen(ptr); + if (name_length <= IGTL_POLY_MAX_ATTR_NAME_LEN) + { + info->attributes[i].name = malloc(name_length+1); + strcpy(info->attributes[i].name, ptr); + } + else + { + /* invalid name length */ + return 0; + } + total_name_length += (name_length+1); + ptr += (name_length+1); + } + + if (total_name_length % 2 > 0) + { + /* add padding */ + ptr ++; + } + + /* Attributes */ + for (i = 0; i < info->header.nattributes; i ++) + { + if (info->attributes[i].type == IGTL_POLY_ATTR_TYPE_SCALAR) + { + n = info->attributes[i].ncomponents * info->attributes[i].n; + s = n * sizeof(igtl_float32); + } + else if (info->attributes[i].type == IGTL_POLY_ATTR_TYPE_NORMAL) + { + n = 3 * info->attributes[i].n; + s = n * sizeof(igtl_float32); + } + else if (info->attributes[i].type == IGTL_POLY_ATTR_TYPE_VECTOR) + { + n = 3 * info->attributes[i].n; + s = n * sizeof(igtl_float32); + } + else /* TENSOR */ + { + n = 9 * info->attributes[i].n; + s = n * sizeof(igtl_float32); + } + info->attributes[i].data = (igtl_float32*)malloc((size_t)s); + ptr32_dst = (igtl_uint32*)info->attributes[i].data; + ptr32_src = (igtl_uint32*)ptr; + ptr32_src_end = ptr32_src + n; + if (igtl_is_little_endian()) + { + while (ptr32_src < ptr32_src_end) + { + *ptr32_dst = BYTE_SWAP_INT32(*ptr32_src); + ptr32_dst ++; + ptr32_src ++; + } + } + else + { + memcpy(ptr32_dst, ptr32_src, s); + } + ptr += s; + } + + return 1; +} + + +int igtl_export igtl_polydata_pack(igtl_polydata_info * info, void * byte_array, int type) +{ + /* size = number of points (not number of bytes). In case of vertices, this is specified + by size_vertices in igtl_polydata_header. */ + igtl_polydata_header * header; + char * ptr; + + igtl_uint32 * ptr32_src; + igtl_uint32 * ptr32_src_end; + igtl_uint32 * ptr32_dst; + + igtl_polydata_attribute_header * att_header; + igtl_polydata_attribute * att; + + int total_name_length; + int name_length; + + unsigned int i; + int n; + int size; + + if (byte_array == NULL || info == NULL) + { + return 0; + } + + /* POLYDATA header */ + header = (igtl_polydata_header *) byte_array; + if (igtl_is_little_endian()) + { + header->npoints = BYTE_SWAP_INT32(info->header.npoints); + header->nvertices = BYTE_SWAP_INT32(info->header.nvertices); + header->size_vertices = BYTE_SWAP_INT32(info->header.size_vertices); + header->nlines = BYTE_SWAP_INT32(info->header.nlines); + header->size_lines = BYTE_SWAP_INT32(info->header.size_lines); + header->npolygons = BYTE_SWAP_INT32(info->header.npolygons); + header->size_polygons = BYTE_SWAP_INT32(info->header.size_polygons); + header->ntriangle_strips = BYTE_SWAP_INT32(info->header.ntriangle_strips); + header->size_triangle_strips = BYTE_SWAP_INT32(info->header.size_triangle_strips); + header->nattributes = BYTE_SWAP_INT32(info->header.nattributes); + } + else + { + memcpy(header, &(info->header), sizeof(igtl_polydata_header)); + } + + /* POINT section */ + ptr = (char*) byte_array + sizeof(igtl_polydata_header); + if (!igtl_is_little_endian()) + { + memcpy((void*)ptr, (void*)info->points, sizeof(igtl_float32)*info->header.npoints*3); + } + else + { + ptr32_src = (igtl_uint32 *) info->points; + ptr32_src_end = ptr32_src + info->header.npoints*3; + ptr32_dst = (igtl_uint32 *) ptr; + while (ptr32_src < ptr32_src_end) + { + *ptr32_dst = BYTE_SWAP_INT32(*ptr32_src); + ptr32_dst ++; + ptr32_src ++; + } + } + + ptr += sizeof(igtl_float32)*info->header.npoints*3; + + /* Check size parameters */ + if (info->header.size_vertices%sizeof(igtl_uint32) != 0 || + info->header.size_lines%sizeof(igtl_uint32) != 0 || + info->header.size_polygons%sizeof(igtl_uint32) != 0 || + info->header.size_triangle_strips%sizeof(igtl_uint32)) + { + /* More than one of size parameters is multiples of 4 (size of 32-bit value) */ + return 0; + } + + /* VERTICES section */ + igtl_polydata_convert_byteorder_topology((igtl_uint32*)ptr, info->vertices, + info->header.size_vertices); + ptr += info->header.size_vertices; + + /* LINES section */ + igtl_polydata_convert_byteorder_topology((igtl_uint32*)ptr, info->lines, + info->header.size_lines); + ptr += info->header.size_lines; + + /* POLYGONS section */ + igtl_polydata_convert_byteorder_topology((igtl_uint32*)ptr, info->polygons, + info->header.size_polygons); + ptr += info->header.size_polygons; + + /* TRIANGLE_STRIPS section */ + igtl_polydata_convert_byteorder_topology((igtl_uint32*)ptr, info->triangle_strips, + info->header.size_triangle_strips); + ptr += info->header.size_triangle_strips; + + /* Attribute header */ + for (i = 0; i < info->header.nattributes; i ++) + { + att = &(info->attributes[i]); + att_header = (igtl_polydata_attribute_header *) ptr; + att_header->type = att->type; + if (att->type == IGTL_POLY_ATTR_TYPE_SCALAR) + { + att_header->ncomponents = att->ncomponents; + } + else if (att->type == IGTL_POLY_ATTR_TYPE_VECTOR) + { + att_header->ncomponents = 3; + } + else if (att->type == IGTL_POLY_ATTR_TYPE_NORMAL) + { + att_header->ncomponents = 3; + } + else /* att->type == IGTL_POLY_ATTR_TYPE_TENSOR */ + { + att_header->ncomponents = 9; + } + + if (igtl_is_little_endian()) + { + att_header->n = BYTE_SWAP_INT32(att->n); + } + else + { + att_header->n = att->n; + } + ptr += sizeof(igtl_polydata_attribute_header); + } + + /* Attribute names */ + total_name_length = 0; + for (i = 0; i < info->header.nattributes; i ++) + { + name_length = strlen(info->attributes[i].name); + if (name_length > IGTL_POLY_MAX_ATTR_NAME_LEN) + { + return 0; + } + strcpy(ptr, info->attributes[i].name); + total_name_length += (name_length+1); + ptr += (name_length+1); + } + + if (total_name_length % 2 > 0) + { + /* add padding */ + *(char*)ptr = '\0'; + ptr ++; + } + + /* Attributes */ + for (i = 0; i < info->header.nattributes; i ++) + { + if (info->attributes[i].type == IGTL_POLY_ATTR_TYPE_SCALAR) + { + n = info->attributes[i].ncomponents * info->attributes[i].n; + size = n * sizeof(igtl_float32); + } + else if (info->attributes[i].type == IGTL_POLY_ATTR_TYPE_NORMAL) + { + n = 3 * info->attributes[i].n; + size = n * sizeof(igtl_float32); + } + else if (info->attributes[i].type == IGTL_POLY_ATTR_TYPE_VECTOR) + { + n = 3 * info->attributes[i].n; + size = n * sizeof(igtl_float32); + } + else if (info->attributes[i].type == IGTL_POLY_ATTR_TYPE_TCOORDS) + { + n = 3 * info->attributes[i].n; + size = n * sizeof(igtl_float32); + } + else /* TENSOR */ + { + n = 9 * info->attributes[i].n; + size = n * sizeof(igtl_float32); + } + if (igtl_is_little_endian()) + { + ptr32_dst = (igtl_uint32*)ptr; + ptr32_src = (igtl_uint32*)info->attributes[i].data; + ptr32_src_end = ptr32_src + n; + while (ptr32_src < ptr32_src_end) + { + *ptr32_dst = BYTE_SWAP_INT32(*ptr32_src); + ptr32_dst ++; + ptr32_src ++; + } + } + else + { + memcpy(ptr, info->attributes[i].data, size); + } + ptr += size; + } + + return 1; +} + + +igtl_uint64 igtl_export igtl_polydata_get_size(igtl_polydata_info * info, int type) +{ + igtl_uint64 data_size; + int name_len; + unsigned int i; + int n; + int size; + + /* Header */ + data_size = sizeof(igtl_polydata_header); + /* POINT section */ + data_size += sizeof(igtl_float32)*info->header.npoints*3; + /* VERTICES */ + data_size += info->header.size_vertices; + /* LINES */ + data_size += info->header.size_lines; + /* POLYGONS */ + data_size += info->header.size_polygons; + /* TRIANGLE_STRIPS */ + data_size += info->header.size_triangle_strips; + /* Attribute header */ + data_size += sizeof(igtl_polydata_attribute_header) * info->header.nattributes; + /* Attribute names */ + for (i = 0; i < info->header.nattributes; i ++) + { + name_len = strlen(info->attributes[i].name); + if (name_len > IGTL_POLY_MAX_ATTR_NAME_LEN) + { + /* Invaid name length */ + return 0; + } + data_size += name_len + 1; /* Including terminator */ + } + + /* Padding */ + if (data_size % 2 > 0) + { + data_size ++; + } + + /* Attributes */ + for (i = 0; i < info->header.nattributes; i ++) + { + if (info->attributes[i].type == IGTL_POLY_ATTR_TYPE_SCALAR) + { + n = info->attributes[i].ncomponents * info->attributes[i].n; + size = n * sizeof(igtl_float32); + } + else if (info->attributes[i].type == IGTL_POLY_ATTR_TYPE_NORMAL) + { + n = 3 * info->attributes[i].n; + size = n * sizeof(igtl_float32); + } + else if (info->attributes[i].type == IGTL_POLY_ATTR_TYPE_VECTOR) + { + n = 3 * info->attributes[i].n; + size = n * sizeof(igtl_float32); + } + else /* TENSOR */ + { + n = 9 * info->attributes[i].n; + size = n * sizeof(igtl_float32); + } + data_size += size; + } + + return data_size; +} + + +igtl_uint64 igtl_export igtl_polydata_get_crc(igtl_polydata_info * info, int type, void* polydata_message) +{ + igtl_uint64 crc; + igtl_uint64 polydata_length; + /*igtl_uint16 i;*/ + /*igtl_uint16 nc;*/ + + polydata_length = (igtl_uint32)igtl_polydata_get_size(info, type); + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) polydata_message, (int)polydata_length, crc); + + return crc; +} + diff --git a/openigtlink/repo/Source/igtlutil/igtl_polydata.h b/openigtlink/repo/Source/igtlutil/igtl_polydata.h new file mode 100644 index 0000000..0d5657b --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_polydata.h @@ -0,0 +1,143 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_POLYDATA_H +#define __IGTL_POLYDATA_H + +#include "igtl_win32header.h" +#include "igtl_header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_win32header.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define IGTL_POLY_MAX_ATTR_NAME_LEN 255 + +#define IGTL_POLY_ATTR_TYPE_SCALAR 0x00 +#define IGTL_POLY_ATTR_TYPE_VECTOR 0x01 +#define IGTL_POLY_ATTR_TYPE_NORMAL 0x02 +#define IGTL_POLY_ATTR_TYPE_TENSOR 0x03 +#define IGTL_POLY_ATTR_TYPE_RGBA 0x04 +#define IGTL_POLY_ATTR_TYPE_TCOORDS 0x05 + +#pragma pack(1) /* For 1-byte boundary in memory */ + +/** POLYDATA Header */ +typedef struct { + igtl_uint32 npoints; /* Number of points */ + + igtl_uint32 nvertices; /* Number of vertices */ + igtl_uint32 size_vertices; /* Size of vertex data (bytes) */ + + igtl_uint32 nlines; /* Number of lines */ + igtl_uint32 size_lines; /* Size of line data (bytes) */ + + igtl_uint32 npolygons; /* Number of polygons */ + igtl_uint32 size_polygons; /* Size of polygon data (bytes) */ + + igtl_uint32 ntriangle_strips; /* Number of triangle strips */ + igtl_uint32 size_triangle_strips; /* Size of triangle strips data (bytes) */ + + igtl_uint32 nattributes; /* Number of attributes */ +} igtl_polydata_header; + + +typedef struct { + igtl_uint8 type; /* attribute type */ + /* Values for TYPE_ATTRIBUTE (16-bit) + 0x00: POINT_DATA / Scalars + 0x01: POINT_DATA / Vectors + 0x02: POINT_DATA / Normals + 0x03: POINT_DATA / Tensors + 0x10: CELL_DATA / Scalars + 0x11: CELL_DATA / Vectors + 0x12: CELL_DATA / Normals + 0x13: CELL_DATA Tensors */ + igtl_uint8 ncomponents; /* number of components */ + /* must be 3 for Vectors and Normal, 9 for Tensor.*/ + igtl_uint32 n; +} igtl_polydata_attribute_header; + +#pragma pack() + +/** Attribute info */ +typedef struct { + igtl_uint8 type; + igtl_uint8 ncomponents; + igtl_uint32 n; + char * name; + igtl_float32 * data; +} igtl_polydata_attribute; + +/** POLYDATA info */ +typedef struct { + igtl_polydata_header header; /* Header */ + igtl_float32* points; /* Points */ + igtl_uint32 * vertices; /* Vertices -- array of (N, i1, i2, i3 ...iN) */ + igtl_uint32 * lines; /* Lines -- array of (N, i1, i2, i3 ...iN) */ + igtl_uint32 * polygons; /* Polygons -- array of (N, i1, i2, i3 ...iN) */ + igtl_uint32 * triangle_strips; /* Triangle strips -- array of (N, i1, i2, i3 ...iN) */ + igtl_polydata_attribute * attributes; /* Array of attributes */ +} igtl_polydata_info; + + +/** Initializes igtl_polydata_info */ +void igtl_export igtl_polydata_init_info(igtl_polydata_info * info); + +/** Allocates free arrays in polydata_info. + * Note that igtl_polydata_alloc_info() does not allocate memory for 'name' and 'data' + * in each igtl_polydata_attribute. Those elements have to be allocated in the developers + * responsibility. + * igtl_polydata_free_info() function assumes that igtl_polydata_info is allocated by + * igtl_polydata_alloc_info() and all memory blocks pointed from igtl_polydata_attribute + * have been allocated by malloc(). + * Return 1 if the array is successfully allocated/freed. */ +int igtl_export igtl_polydata_alloc_info(igtl_polydata_info * info); +int igtl_export igtl_polydata_free_info(igtl_polydata_info * info); + +/** Extracts information about child messages in a byte array of POLYDATA messages and store + * it in a igtl_polydata_info structure. 'type' argument specifies a message type prefix + * (none, GET_, STT_, STP_ or RTS_) by IGTL_TYPE_PREFIX_* macro. + * Returns 1 if success, otherwise 0. */ +int igtl_export igtl_polydata_unpack(int type, void * byte_array, igtl_polydata_info * info, igtl_uint64 size); + +/** Converts an igtl_polydata_info structure to a byte array. + * 'byte_array' should be allocated prior to calling igtl_polydata_pack() with memory size + * calculated by igtl_polydata_get_size(). 'type' argument specifies a message type prefix + * (none, GET_, STT_, STP_ or RTS_) by IGTL_TYPE_PREFIX_* macro. + * Returns 1 if success, otherwise 0. */ +int igtl_export igtl_polydata_pack(igtl_polydata_info * info, void * byte_array, int type); + +/** igtl_polydata_get_size() calculates the size of polydata header, consisting of + * POLYDATA hearder section (including number of child messages) and + * name table section based on a igtl_polydata_header. + * The size returned from this function does not include size of child message data. + * 'type' argument specifies a message type prefix + * (none, GET_, STT_, STP_ or RTS_) by IGTL_TYPE_PREFIX_* macro. */ +igtl_uint64 igtl_export igtl_polydata_get_size(igtl_polydata_info * info, int type); + +/** Calculates CRC of POLYDATA message. Note that 'info' is used only for + * getting size of the message. */ +igtl_uint64 igtl_export igtl_polydata_get_crc(igtl_polydata_info * info, int type, void* polydata_message); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_POLYDATA_H */ \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlutil/igtl_position.c b/openigtlink/repo/Source/igtlutil/igtl_position.c new file mode 100644 index 0000000..d74dfff --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_position.c @@ -0,0 +1,95 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include "igtl_position.h" +#include "igtl_util.h" + +#include + + +void igtl_export igtl_position_convert_byte_order(igtl_position* pos) +{ + + igtl_uint32 tmp[4]; + + if (igtl_is_little_endian()) + { + /* position */ + memcpy((void*)tmp, (void*)(pos->position), sizeof(igtl_float32)*3); + tmp[0] = BYTE_SWAP_INT32(tmp[0]); + tmp[1] = BYTE_SWAP_INT32(tmp[1]); + tmp[2] = BYTE_SWAP_INT32(tmp[2]); + memcpy((void*)(pos->position), (void*)tmp, sizeof(igtl_float32)*3); + + /* quaternion */ + memcpy((void*)tmp, (void*)(pos->quaternion), sizeof(igtl_float32)*4); + tmp[0] = BYTE_SWAP_INT32(tmp[0]); + tmp[1] = BYTE_SWAP_INT32(tmp[1]); + tmp[2] = BYTE_SWAP_INT32(tmp[2]); + tmp[3] = BYTE_SWAP_INT32(tmp[3]); + memcpy((void*)(pos->quaternion), (void*)tmp, sizeof(igtl_float32)*4); + } +} + +void igtl_export igtl_position_convert_byte_order_position_only(igtl_position* pos) +{ + + igtl_uint32 tmp[4]; + + if (igtl_is_little_endian()) + { + /* position */ + memcpy((void*)tmp, (void*)(pos->position), sizeof(igtl_float32)*3); + tmp[0] = BYTE_SWAP_INT32(tmp[0]); + tmp[1] = BYTE_SWAP_INT32(tmp[1]); + tmp[2] = BYTE_SWAP_INT32(tmp[2]); + memcpy((void*)(pos->position), (void*)tmp, sizeof(igtl_float32)*3); + } +} + +void igtl_export igtl_position_convert_byte_order_quaternion3(igtl_position* pos) +{ + + igtl_uint32 tmp[4]; + + if (igtl_is_little_endian()) + { + /* position */ + memcpy((void*)tmp, (void*)(pos->position), sizeof(igtl_float32)*3); + tmp[0] = BYTE_SWAP_INT32(tmp[0]); + tmp[1] = BYTE_SWAP_INT32(tmp[1]); + tmp[2] = BYTE_SWAP_INT32(tmp[2]); + memcpy((void*)(pos->position), (void*)tmp, sizeof(igtl_float32)*3); + + /* quaternion */ + memcpy((void*)tmp, (void*)(pos->quaternion), sizeof(igtl_float32)*3); + tmp[0] = BYTE_SWAP_INT32(tmp[0]); + tmp[1] = BYTE_SWAP_INT32(tmp[1]); + tmp[2] = BYTE_SWAP_INT32(tmp[2]); + memcpy((void*)(pos->quaternion), (void*)tmp, sizeof(igtl_float32)*3); + } + +} + + +igtl_uint64 igtl_export igtl_position_get_crc(igtl_position* pos) +{ + + igtl_uint64 crc = crc64(0, 0, 0); + + crc = crc64((unsigned char*)pos, IGTL_POSITION_MESSAGE_DEFAULT_SIZE, crc); + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_position.h b/openigtlink/repo/Source/igtlutil/igtl_position.h new file mode 100644 index 0000000..5e2f2ba --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_position.h @@ -0,0 +1,58 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_POSITION_H +#define __IGTL_POSITION_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" + +#define IGTL_POSITION_MESSAGE_DEFAULT_SIZE 28 + /** NOTE: the size varies if orientation is omitted **/ +#define IGTL_POSITION_MESSAGE_POSITON_ONLY_SIZE 12 /* size w/o quaternion */ +#define IGTL_POSITION_MESSAGE_WITH_QUATERNION3_SIZE 24 /* size 3-element quaternion */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** Status data header for OpenIGTLinik protocol */ +typedef struct { + igtl_float32 position[3]; /* (x, y, z) */ + igtl_float32 quaternion[4]; /* (ox, oy, oz, w) */ +} igtl_position; + +#pragma pack() + +/** Converts endianness of each member variable + * in igtl_status_header from host byte order to network byte order, + * or vice versa. */ +void igtl_export igtl_position_convert_byte_order(igtl_position* pos); +void igtl_export igtl_position_convert_byte_order_position_only(igtl_position* pos); +void igtl_export igtl_position_convert_byte_order_quaternion3(igtl_position* pos); + +/** Calculates CRC of position message */ +igtl_uint64 igtl_export igtl_position_get_crc(igtl_position* pos); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_POSITION_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_qtdata.c b/openigtlink/repo/Source/igtlutil/igtl_qtdata.c new file mode 100644 index 0000000..7d62c4d --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_qtdata.c @@ -0,0 +1,102 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_qtdata.h" +#include "igtl_util.h" + +void igtl_export igtl_qtdata_convert_byte_order(igtl_qtdata_element* qtdatalist, int nitem) +{ + igtl_qtdata_element* elem; + int i; + int j; + int k; + igtl_int32* tmp; + + for (i = 0; i < nitem; i ++) + { + elem = &(qtdatalist[i]); + if (igtl_is_little_endian()) + { + for (j = 0; j < 3; j ++) + { + tmp = (igtl_int32*)&(elem->position[j]); + *tmp = BYTE_SWAP_INT32(*tmp); + } + for (k = 0; k < 4; k ++) + { + tmp = (igtl_int32*)&(elem->quaternion[k]); + *tmp = BYTE_SWAP_INT32(*tmp); + } + } + } +} + + +void igtl_export igtl_stt_qtdata_convert_byte_order(igtl_stt_qtdata* stt_qtdata) +{ + igtl_int32* tmp; + + if (igtl_is_little_endian()) + { + tmp = (igtl_int32*)&(stt_qtdata->resolution); + *tmp = BYTE_SWAP_INT32(*tmp); + } +} + + +void igtl_export igtl_rts_qtdata_convert_byte_order(igtl_rts_qtdata* rts_qtdata) +{ + /* do nothing */ +} + + +igtl_uint64 igtl_export igtl_qtdata_get_crc(igtl_qtdata_element* qtdatalist, int nitem) +{ + igtl_qtdata_element* elem; + int i; + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + for (i = 0; i < nitem; i ++) + { + elem = &(qtdatalist[i]); + crc = crc64((unsigned char*) elem, IGTL_QTDATA_ELEMENT_SIZE, crc); + } + + return crc; +} + + +igtl_uint64 igtl_export igtl_stt_qtdata_get_crc(igtl_stt_qtdata* stt_qtdata) +{ + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) stt_qtdata, IGTL_STT_QTDATA_SIZE, crc); + return crc; +} + + +igtl_uint64 igtl_export igtl_rts_qtdata_get_crc(igtl_rts_qtdata* rts_qtdata) +{ + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) rts_qtdata, IGTL_RTS_QTDATA_SIZE, crc); + return crc; +} + diff --git a/openigtlink/repo/Source/igtlutil/igtl_qtdata.h b/openigtlink/repo/Source/igtlutil/igtl_qtdata.h new file mode 100644 index 0000000..e62d7d3 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_qtdata.h @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_QTDATA_H +#define __IGTL_QTDATA_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" + +#define IGTL_QTDATA_ELEMENT_SIZE 50 +#define IGTL_STT_QTDATA_SIZE 36 +#define IGTL_RTS_QTDATA_SIZE 1 + +#define IGTL_QTDATA_LEN_NAME 20 /* Maximum length of tracking instrument name */ +#define IGTL_STT_QTDATA_LEN_COORDNAME 32 /* Maximum length of coordinate system name */ + +#define IGTL_QTDATA_TYPE_TRACKER 1 /* Tracker */ +#define IGTL_QTDATA_TYPE_6D 2 /* 6D instrument (regular instrument) */ +#define IGTL_QTDATA_TYPE_3D 3 /* 3D instrument (only tip of the instrument defined) */ +#define IGTL_QTDATA_TYPE_5D 4 /* 5D instrument (tip and handle are defined, + but not the normal vector) */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** Status data header for OpenIGTLinik protocol */ +typedef struct { + char name[IGTL_QTDATA_LEN_NAME]; /* Name of instrument / tracker */ + igtl_uint8 type; /* Tracking data type (1-4) */ + igtl_uint8 reserved; /* Reserved byte */ + igtl_float32 position[3]; /* position (x, y, z) */ + igtl_float32 quaternion[4]; /* orientation as quaternion (qx, qy, qz, w) */ +} igtl_qtdata_element; + + +typedef struct { + igtl_int32 resolution; /* Minimum time between two frames. Use 0 for as fast as possible. */ + /* If e.g. 50 ms is specified, the maximum update rate will be 20 Hz. */ + char coord_name[IGTL_STT_QTDATA_LEN_COORDNAME]; /* Name of the coordinate system */ +} igtl_stt_qtdata; + +typedef struct { + igtl_int8 status; /* 0: Success 1: Error */ +} igtl_rts_qtdata; + +#pragma pack() + +/** igtl_qtdata_get_data_size(n) calculates the size of body based on the number + * of qtdatas. The size of body is used in the message header.*/ +#define igtl_qtdata_get_data_size(n) ((n) * IGTL_QTDATA_ELEMENT_SIZE) + +/** igtl_qtdata_get_data_n(size) calculates the number of qtdatas in the body, based on + * the body size. This function may be used when a client program parses a QTDATA message. */ +#define igtl_qtdata_get_data_n(size) ((size) / IGTL_QTDATA_ELEMENT_SIZE) + +/** Byte order conversion for an array of QTDATA, STT_QTDATA and RTS_QTDATA data structure + * Converts endianness of each element in an array of igtl_qtdata_element from host byte + * order to network byte order, or vice versa. */ +void igtl_export igtl_qtdata_convert_byte_order(igtl_qtdata_element* qtdatalist, int nelem); +void igtl_export igtl_stt_qtdata_convert_byte_order(igtl_stt_qtdata* stt_qtdata); +void igtl_export igtl_rts_qtdata_convert_byte_order(igtl_rts_qtdata* rts_qtdata); + +/** Calculates CRC of QTDATA, STT_QTDATA and RTS_QTDATA messages */ +igtl_uint64 igtl_export igtl_qtdata_get_crc(igtl_qtdata_element* qtdatalist, int nelem); +igtl_uint64 igtl_export igtl_stt_qtdata_get_crc(igtl_stt_qtdata* stt_qtdata); +igtl_uint64 igtl_export igtl_rts_qtdata_get_crc(igtl_rts_qtdata* rts_qtdata); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_QTDATA_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_qtrans.c b/openigtlink/repo/Source/igtlutil/igtl_qtrans.c new file mode 100644 index 0000000..98c2e90 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_qtrans.c @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include "igtl_qtrans.h" +#include "igtl_util.h" + +#include + + +void igtl_export igtl_qtrans_convert_byte_order(igtl_qtrans* pos) +{ + + igtl_uint32 tmp[4]; + + if (igtl_is_little_endian()) + { + /* qtrans */ + memcpy((void*)tmp, (void*)(pos->qtrans), sizeof(igtl_float32)*3); + tmp[0] = BYTE_SWAP_INT32(tmp[0]); + tmp[1] = BYTE_SWAP_INT32(tmp[1]); + tmp[2] = BYTE_SWAP_INT32(tmp[2]); + memcpy((void*)(pos->qtrans), (void*)tmp, sizeof(igtl_float32)*3); + + /* quaternion */ + memcpy((void*)tmp, (void*)(pos->quaternion), sizeof(igtl_float32)*4); + tmp[0] = BYTE_SWAP_INT32(tmp[0]); + tmp[1] = BYTE_SWAP_INT32(tmp[1]); + tmp[2] = BYTE_SWAP_INT32(tmp[2]); + tmp[3] = BYTE_SWAP_INT32(tmp[3]); + memcpy((void*)(pos->quaternion), (void*)tmp, sizeof(igtl_float32)*4); + } +} + + +igtl_uint64 igtl_export igtl_qtrans_get_crc(igtl_qtrans* pos) +{ + + igtl_uint64 crc = crc64(0, 0, 0); + + crc = crc64((unsigned char*)pos, IGTL_QTRANS_MESSAGE_DEFAULT_SIZE, crc); + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_qtrans.h b/openigtlink/repo/Source/igtlutil/igtl_qtrans.h new file mode 100644 index 0000000..95a1928 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_qtrans.h @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_QTRANS_H +#define __IGTL_QTRANS_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" + +#define IGTL_QTRANS_MESSAGE_DEFAULT_SIZE 28 + /** NOTE: the size varies if orientation is omitted **/ +#define IGTL_QTRANS_MESSAGE_POSITON_ONLY_SIZE 12 /* size w/o quaternion */ +#define IGTL_QTRANS_MESSAGE_WITH_QUATERNION3_SIZE 24 /* size 3-element quaternion */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** Status data header for OpenIGTLinik protocol */ +typedef struct { + igtl_float32 qtrans[3]; /* (x, y, z) */ + igtl_float32 quaternion[4]; /* (ox, oy, oz, w) */ +} igtl_qtrans; + +#pragma pack() + +/** Converts endianness of each member variable in igtl_status_header + * from host byte order to network byte order, or vice versa. */ +void igtl_export igtl_qtrans_convert_byte_order(igtl_qtrans* pos); + + /** Calculates CRC of qtrans message */ +igtl_uint64 igtl_export igtl_qtrans_get_crc(igtl_qtrans* pos); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_QTRANS_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_query.c b/openigtlink/repo/Source/igtlutil/igtl_query.c new file mode 100644 index 0000000..1761856 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_query.c @@ -0,0 +1,49 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_query.h" +#include "igtl_util.h" + + +void igtl_export igtl_query_convert_byte_order(igtl_query_header* header) +{ + + if (igtl_is_little_endian()) + { + header->queryID = BYTE_SWAP_INT32(header->queryID); + header->deviceUIDLength = BYTE_SWAP_INT16(header->deviceUIDLength); + } +} + + +igtl_uint64 igtl_export igtl_query_get_crc(igtl_query_header * header, void* query) +{ + igtl_uint64 crc; + igtl_uint32 query_length; + + /* convert byte order to get query length */ + igtl_query_convert_byte_order(header); + query_length = (igtl_uint32)(header->deviceUIDLength); + igtl_query_convert_byte_order(header); + + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) header, IGTL_QUERY_HEADER_SIZE, crc); + crc = crc64((unsigned char*) query, query_length, crc); + + return crc; +} + diff --git a/openigtlink/repo/Source/igtlutil/igtl_query.h b/openigtlink/repo/Source/igtlutil/igtl_query.h new file mode 100644 index 0000000..e2fa5d7 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_query.h @@ -0,0 +1,53 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_QUERY_H +#define __IGTL_QUERY_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_win32header.h" + +#define IGTL_QUERY_HEADER_SIZE 38 +#define IGTL_QUERY_DATE_TYPE_SIZE 32 +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memory */ + +typedef struct { + igtl_uint32 queryID; /* The unique ID of this QUERY */ + igtl_uint8 queryDataType[IGTL_QUERY_DATE_TYPE_SIZE]; /* The query data type of the message */ + + igtl_uint16 deviceUIDLength; /* Length of DEVICE Name */ +} igtl_query_header; + +#pragma pack() + +/** Converts endian-ness from host byte order to network byte order, + * or vice versa. NOTE: It is developer's responsibility to have the command body with BOM + * (byte order mark) or in big endian order. */ +void igtl_export igtl_query_convert_byte_order(igtl_query_header * header); + +/** Calculates CRC of image data body including header + * and array of pixel data. */ +igtl_uint64 igtl_export igtl_query_get_crc(igtl_query_header * header, void* query); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_QUERY_H */ \ No newline at end of file diff --git a/openigtlink/repo/Source/igtlutil/igtl_sensor.c b/openigtlink/repo/Source/igtlutil/igtl_sensor.c new file mode 100644 index 0000000..32eac1e --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_sensor.c @@ -0,0 +1,64 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_sensor.h" +#include "igtl_util.h" + +igtl_uint32 igtl_export igtl_sensor_get_data_size(igtl_sensor_header * header) +{ + + igtl_uint32 data_size; + + data_size = (igtl_uint32)(header->larray) * sizeof(igtl_float64); + + return data_size; +} + + +void igtl_export igtl_sensor_convert_byte_order(igtl_sensor_header* header, igtl_float64* data) +{ + int i; + int larray; + igtl_uint64* tmp; + + if (igtl_is_little_endian()) + { + larray = (int) header->larray; /* NOTE: larray is 8-bit (doesn't depend on endianness) */ + header->unit = BYTE_SWAP_INT64(header->unit); + + tmp = (igtl_uint64*) data; + for (i = 0; i < larray; i ++) + { + tmp[i] = BYTE_SWAP_INT64(tmp[i]); + } + } +} + + +igtl_uint64 igtl_export igtl_sensor_get_crc(igtl_sensor_header * header, igtl_float64* data) +{ + igtl_uint64 crc; + igtl_uint64 data_size; + + data_size = (igtl_uint32)(header->larray) * sizeof(igtl_float64); + + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) header, IGTL_SENSOR_HEADER_SIZE, crc); + crc = crc64((unsigned char*) data, (int)data_size, crc); + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_sensor.h b/openigtlink/repo/Source/igtlutil/igtl_sensor.h new file mode 100644 index 0000000..bd57372 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_sensor.h @@ -0,0 +1,56 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_SENSOR_H +#define __IGTL_SENSOR_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_unit.h" +#include "igtl_win32header.h" + +#define IGTL_SENSOR_HEADER_SIZE 10 + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +typedef struct { + igtl_uint8 larray; /* Length of array (0-255) */ + igtl_uint8 status; /* (reserved) sensor status */ + igtl_unit unit; /* Unit */ +} igtl_sensor_header; + +#pragma pack() + +/** This function calculates size of the pixel array, which will be + * transferred with the specified header. */ +igtl_uint32 igtl_export igtl_sensor_get_data_size(igtl_sensor_header * header); + +/** This function converts endianness from host byte order to network byte order, + * or vice versa. */ +void igtl_export igtl_sensor_convert_byte_order(igtl_sensor_header * header, igtl_float64* data); + +/** Calculates CRC of image data body including header + * and array of pixel data. */ +igtl_uint64 igtl_export igtl_sensor_get_crc(igtl_sensor_header * header, igtl_float64* data); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_SENSOR_H */ diff --git a/openigtlink/repo/Source/igtlutil/igtl_status.c b/openigtlink/repo/Source/igtlutil/igtl_status.c new file mode 100644 index 0000000..26642a6 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_status.c @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include "igtl_status.h" +#include "igtl_util.h" + +#include + +void igtl_export igtl_status_convert_byte_order(igtl_status_header* status) +{ + + if (igtl_is_little_endian()) + { + status->code = BYTE_SWAP_INT16(status->code); + status->subcode = BYTE_SWAP_INT64(status->subcode); + } +} + + +igtl_uint64 igtl_export igtl_status_get_crc(igtl_status_header* status, igtl_uint32 msglen, const char* msg) +{ + + igtl_uint64 crc = crc64(0, 0, 0); + + crc = crc64((unsigned char*)status, IGTL_STATUS_HEADER_SIZE, crc); + crc = crc64((unsigned char*)msg, msglen, crc); + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_status.h b/openigtlink/repo/Source/igtlutil/igtl_status.h new file mode 100644 index 0000000..2403b2e --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_status.h @@ -0,0 +1,80 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_STATUS_H +#define __IGTL_STATUS_H + +#include "igtl_util.h" +#include "igtl_types.h" + +#define IGTL_STATUS_HEADER_SIZE 30 + +#define IGTL_STATUS_ERROR_NAME_LENGTH 20 + +/* Status codes */ + +#define IGTL_STATUS_INVALID 0 +#define IGTL_STATUS_OK 1 +#define IGTL_STATUS_UNKNOWN_ERROR 2 +#define IGTL_STATUS_PANICK_MODE 3 /* emergency */ +#define IGTL_STATUS_NOT_FOUND 4 /* file, configuration, device etc */ +#define IGTL_STATUS_ACCESS_DENIED 5 +#define IGTL_STATUS_BUSY 6 +#define IGTL_STATUS_TIME_OUT 7 /* Time out / Connection lost */ +#define IGTL_STATUS_OVERFLOW 8 /* Overflow / Can't be reached */ +#define IGTL_STATUS_CHECKSUM_ERROR 9 /* Checksum error */ +#define IGTL_STATUS_CONFIG_ERROR 10 /* Configuration error */ +#define IGTL_STATUS_RESOURCE_ERROR 11 /* Not enough resource (memory, storage etc) */ +#define IGTL_STATUS_ILLEGAL_INSTRUCTION 12 /* Illegal/Unknown instruction */ +#define IGTL_STATUS_NOT_READY 13 /* Device not ready (starting up)*/ +#define IGTL_STATUS_MANUAL_MODE 14 /* Manual mode (device does not accept commands) */ +#define IGTL_STATUS_DISABLED 15 /* Device disabled */ +#define IGTL_STATUS_NOT_PRESENT 16 /* Device not present */ +#define IGTL_STATUS_UNKNOWN_VERSION 17 /* Device version not known */ +#define IGTL_STATUS_HARDWARE_FAILURE 18 /* Hardware failure */ +#define IGTL_STATUS_SHUT_DOWN 19 /* Exiting / shut down in progress */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** Status data header for OpenIGTLinik protocol */ +typedef struct { + igtl_uint16 code; /* status code defined above */ + igtl_int64 subcode; /* sub code for the error */ + char error_name[IGTL_STATUS_ERROR_NAME_LENGTH]; + /* error name -- can be anything, don't rely on this */ + /*char status_message[]; */ +} igtl_status_header; + +#pragma pack() + +/** Converts endianness of each member variable + * in igtl_status_header from host byte order to network byte order, + * or vice versa. */ +void igtl_export igtl_status_convert_byte_order(igtl_status_header* status); + +/** Calculates CRC of status data body including status message part */ +igtl_uint64 igtl_export igtl_status_get_crc(igtl_status_header* status, igtl_uint32 msglen, const char* msg); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_IMAGE_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_string.c b/openigtlink/repo/Source/igtlutil/igtl_string.c new file mode 100644 index 0000000..8a5b3d9 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_string.c @@ -0,0 +1,58 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_string.h" +#include "igtl_util.h" + +igtl_uint32 igtl_export igtl_string_get_string_length(igtl_string_header * header) +{ + + igtl_uint32 length; + length = (igtl_uint32)(header->length); + + return length; +} + + +void igtl_export igtl_string_convert_byte_order(igtl_string_header* header) +{ + + if (igtl_is_little_endian()) + { + header->encoding = BYTE_SWAP_INT16(header->encoding); + header->length = BYTE_SWAP_INT16(header->length); + } +} + + +igtl_uint64 igtl_export igtl_string_get_crc(igtl_string_header * header, void* string) +{ + igtl_uint64 crc; + igtl_uint64 string_length; + + /* convert byte order to get string length */ + igtl_string_convert_byte_order(header); + string_length = (igtl_uint32)(header->length); + igtl_string_convert_byte_order(header); + + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) header, IGTL_STRING_HEADER_SIZE, crc); + crc = crc64((unsigned char*) string, (int)string_length, crc); + + return crc; +} + diff --git a/openigtlink/repo/Source/igtlutil/igtl_string.h b/openigtlink/repo/Source/igtlutil/igtl_string.h new file mode 100644 index 0000000..2c1a3be --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_string.h @@ -0,0 +1,58 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_STRING_H +#define __IGTL_STRING_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" +#include "igtl_win32header.h" + +#define IGTL_STRING_HEADER_SIZE 4 + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +typedef struct { + igtl_uint16 encoding; /* Character encoding type as MIBenum value (defined by IANA). Default=3. */ + /* Please refer http://www.iana.org/assignments/character-sets for detail */ + igtl_uint16 length; /* Length of string */ +} igtl_string_header; + +#pragma pack() + +/** Calculates size of the pixel array, which will be + * transferred with the specified header. */ +igtl_uint32 igtl_export igtl_string_get_string_length(igtl_string_header * header); + +/** Converts endianness from host byte order to network byte order, + * or vice versa. NOTE: It is developer's responsibility to have the string body with BOM + * (byte order mark) or in big endian ordrer. */ +void igtl_export igtl_string_convert_byte_order(igtl_string_header * header); + +/** Calculates CRC of image data body including header + * and array of pixel data. */ +igtl_uint64 igtl_export igtl_string_get_crc(igtl_string_header * header, void* string); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_STRING_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_tdata.c b/openigtlink/repo/Source/igtlutil/igtl_tdata.c new file mode 100644 index 0000000..7542857 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_tdata.c @@ -0,0 +1,96 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_tdata.h" +#include "igtl_util.h" + +void igtl_export igtl_tdata_convert_byte_order(igtl_tdata_element* tdatalist, int nitem) +{ + igtl_tdata_element* elem; + int i; + int j; + igtl_int32* tmp; + + for (i = 0; i < nitem; i ++) + { + elem = &(tdatalist[i]); + if (igtl_is_little_endian()) + { + for (j = 0; j < 12; j ++) + { + tmp = (igtl_int32*)&(elem->transform[j]); + *tmp = BYTE_SWAP_INT32(*tmp); + } + } + } +} + + +void igtl_export igtl_stt_tdata_convert_byte_order(igtl_stt_tdata* stt_tdata) +{ + igtl_int32* tmp; + + if (igtl_is_little_endian()) + { + tmp = (igtl_int32*)&(stt_tdata->resolution); + *tmp = BYTE_SWAP_INT32(*tmp); + } +} + + +void igtl_export igtl_rts_tdata_convert_byte_order(igtl_rts_tdata* rts_tdata) +{ + /* do nothing */ +} + + +igtl_uint64 igtl_export igtl_tdata_get_crc(igtl_tdata_element* tdatalist, int nitem) +{ + igtl_tdata_element* elem; + int i; + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + for (i = 0; i < nitem; i ++) + { + elem = &(tdatalist[i]); + crc = crc64((unsigned char*) elem, IGTL_TDATA_ELEMENT_SIZE, crc); + } + + return crc; +} + + +igtl_uint64 igtl_export igtl_stt_tdata_get_crc(igtl_stt_tdata* stt_tdata) +{ + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) stt_tdata, IGTL_STT_TDATA_SIZE, crc); + return crc; +} + + +igtl_uint64 igtl_export igtl_rts_tdata_get_crc(igtl_rts_tdata* rts_tdata) +{ + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + crc = crc64((unsigned char*) rts_tdata, IGTL_RTS_TDATA_SIZE, crc); + return crc; +} + diff --git a/openigtlink/repo/Source/igtlutil/igtl_tdata.h b/openigtlink/repo/Source/igtlutil/igtl_tdata.h new file mode 100644 index 0000000..9f90900 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_tdata.h @@ -0,0 +1,89 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TDATA_H +#define __IGTL_TDATA_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" + +#define IGTL_TDATA_ELEMENT_SIZE 70 +#define IGTL_STT_TDATA_SIZE 36 +#define IGTL_RTS_TDATA_SIZE 1 + +#define IGTL_TDATA_LEN_NAME 20 /* Maximum length of tracking instrument name */ +#define IGTL_STT_TDATA_LEN_COORDNAME 32 /* Maximum length of coordinate system name */ + +#define IGTL_TDATA_TYPE_TRACKER 1 /* Tracker */ +#define IGTL_TDATA_TYPE_6D 2 /* 6D instrument (regular instrument) */ +#define IGTL_TDATA_TYPE_3D 3 /* 3D instrument (only tip of the instrument defined) */ +#define IGTL_TDATA_TYPE_5D 4 /* 5D instrument (tip and handle are defined, + but not the normal vector) */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** Status data header for OpenIGTLinik protocol */ +typedef struct { + char name[IGTL_TDATA_LEN_NAME]; /* Name of instrument / tracker */ + igtl_uint8 type; /* Tracking data type (1-4) */ + igtl_uint8 reserved; /* Reserved byte */ + igtl_float32 transform[12]; /* same as TRANSFORM */ +} igtl_tdata_element; + + +typedef struct { + igtl_int32 resolution; /* Minimum time between two frames. Use 0 for as fast as possible. */ + /* If e.g. 50 ms is specified, the maximum update rate will be 20 Hz. */ + char coord_name[IGTL_STT_TDATA_LEN_COORDNAME]; /* Name of the coordinate system */ +} igtl_stt_tdata; + +typedef struct { + igtl_int8 status; /* 0: Success 1: Error */ +} igtl_rts_tdata; + +#pragma pack() + +/** igtl_tdata_get_data_size(n) calculates the size of body based on the number + * of tdatas. The size of body is used in the message header.*/ +#define igtl_tdata_get_data_size(n) ((n) * IGTL_TDATA_ELEMENT_SIZE) + +/** igtl_tdata_get_data_n(size) calculates the number of tdatas in the body, based on + * the body size. This function may be used when a client program parses a TDATA message. */ +#define igtl_tdata_get_data_n(size) ((size) / IGTL_TDATA_ELEMENT_SIZE) + +/** Converts endianness of each element in an array of + * igtl_tdata_element from host byte order to network byte order, + * or vice versa.*/ +void igtl_export igtl_tdata_convert_byte_order(igtl_tdata_element* tdatalist, int nelem); +void igtl_export igtl_stt_tdata_convert_byte_order(igtl_stt_tdata* stt_tdata); +void igtl_export igtl_rts_tdata_convert_byte_order(igtl_rts_tdata* rts_tdata); + +/** Calculates CRC of TDATA, STT_TDATA and RTS_TDATA messages.*/ +igtl_uint64 igtl_export igtl_tdata_get_crc(igtl_tdata_element* tdatalist, int nelem); +igtl_uint64 igtl_export igtl_stt_tdata_get_crc(igtl_stt_tdata* stt_tdata); +igtl_uint64 igtl_export igtl_rts_tdata_get_crc(igtl_rts_tdata* rts_tdata); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_TDATA_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_trajectory.c b/openigtlink/repo/Source/igtlutil/igtl_trajectory.c new file mode 100644 index 0000000..b124c4d --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_trajectory.c @@ -0,0 +1,61 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_trajectory.h" +#include "igtl_util.h" + +void igtl_export igtl_trajectory_convert_byte_order(igtl_trajectory_element* trajectorylist, int nitem) +{ + igtl_trajectory_element* elem; + int i; + int j; + igtl_int32* tmp; + + for (i = 0; i < nitem; i ++) + { + elem = &(trajectorylist[i]); + if (igtl_is_little_endian()) + { + for (j = 0; j < 3; j ++) + { + tmp = (igtl_int32*)&(elem->entry_pos[j]); + *tmp = BYTE_SWAP_INT32(*tmp); + tmp = (igtl_int32*)&(elem->target_pos[j]); + *tmp = BYTE_SWAP_INT32(*tmp); + } + tmp = (igtl_int32*)&(elem->radius); + *tmp = BYTE_SWAP_INT32(*tmp); + } + } +} + + +igtl_uint64 igtl_export igtl_trajectory_get_crc(igtl_trajectory_element* trajectorylist, int nitem) +{ + igtl_trajectory_element* elem; + int i; + igtl_uint64 crc; + + crc = crc64(0, 0, 0); + for (i = 0; i < nitem; i ++) + { + elem = &(trajectorylist[i]); + crc = crc64((unsigned char*) elem, IGTL_TRAJECTORY_ELEMENT_SIZE, crc); + } + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_trajectory.h b/openigtlink/repo/Source/igtlutil/igtl_trajectory.h new file mode 100644 index 0000000..0134b84 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_trajectory.h @@ -0,0 +1,75 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TRAJECTORY_H +#define __IGTL_TRAJECTORY_H + +#include "igtl_win32header.h" +#include "igtl_util.h" +#include "igtl_types.h" + +#define IGTL_TRAJECTORY_ELEMENT_SIZE 150 +#define IGTL_TRAJECTORY_LEN_NAME 64 +#define IGTL_TRAJECTORY_LEN_GROUP_NAME 32 +#define IGTL_TRAJECTORY_LEN_OWNER 20 + +#define IGTL_TRAJECTORY_TYPE_ENTRY_ONLY 1 +#define IGTL_TRAJECTORY_TYPE_TARGET_ONLY 2 +#define IGTL_TRAJECTORY_TYPE_ENTRY_TARGET 3 + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) /* For 1-byte boundary in memroy */ + +/** Status data header for OpenIGTLinik protocol */ +typedef struct { + char name[IGTL_TRAJECTORY_LEN_NAME]; /* Name or description of the trajectory */ + char group_name[IGTL_TRAJECTORY_LEN_GROUP_NAME]; /* Can be "Trajectory", ... */ + igtl_int8 type; /* Trajectory type (see IGTL_TRAJECTORY_TYPE_* macros) */ + igtl_int8 reserved; + igtl_uint8 rgba[4]; /* Color in R/G/B/A */ + igtl_float32 entry_pos[3]; /* Coordinate of the entry point */ + igtl_float32 target_pos[3]; /* Coordinate of the target point */ + igtl_float32 radius; /* Radius of the trajectory. Can be 0. */ + char owner_name[IGTL_TRAJECTORY_LEN_OWNER]; /* Device name of the ower image */ +} igtl_trajectory_element; + +#pragma pack() + + +/** igtl_trajectory_get_data_size(n) calculates the size of body based on the number + * of trajectorys. The size of body is used in the message header. */ +#define igtl_trajectory_get_data_size(n) ((n) * IGTL_TRAJECTORY_ELEMENT_SIZE) + +/** igtl_trajectory_get_data_n(size) calculates the number of images in the body, based on + * the body size. This function may be used when a client program parses a TRAJECTORY message. */ +#define igtl_trajectory_get_data_n(size) ((size) / IGTL_TRAJECTORY_ELEMENT_SIZE) + +/** Converts endianness of each element in an array of + * igtl_igtl_trajectory_element from host byte order to network byte order, + * or vice versa. */ +void igtl_export igtl_trajectory_convert_byte_order(igtl_trajectory_element* trajectorylist, int nelem); + +/** Calculates CRC of trajectory message */ +igtl_uint64 igtl_export igtl_trajectory_get_crc(igtl_trajectory_element* trajectorylist, int nelem); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_POSITION_H */ + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_transform.c b/openigtlink/repo/Source/igtlutil/igtl_transform.c new file mode 100644 index 0000000..f819ac2 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_transform.c @@ -0,0 +1,47 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include "igtl_transform.h" +#include "igtl_util.h" +/*#include "crc32.h"*/ + +#include + +void igtl_export igtl_transform_convert_byte_order(igtl_float32* transform) +{ + int i; + igtl_uint32 tmp[12]; + + if (igtl_is_little_endian()) + { + memcpy(tmp, transform, sizeof(igtl_uint32)*12); + for (i = 0; i < 12; i ++) + { + tmp[i] = BYTE_SWAP_INT32(tmp[i]); + } + memcpy(transform, tmp, sizeof(igtl_uint32)*12); + } +} + + +igtl_uint64 igtl_export igtl_transform_get_crc(igtl_float32* transform) +{ + + igtl_uint64 crc = crc64(0, 0, 0); + + crc = crc64((unsigned char*)transform, sizeof(igtl_float32)*12, crc); + + return crc; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_transform.h b/openigtlink/repo/Source/igtlutil/igtl_transform.h new file mode 100644 index 0000000..182ff52 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_transform.h @@ -0,0 +1,43 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TRANSFORM_H +#define __IGTL_TRANSFORM_H + +#include "igtl_win32header.h" +#include "igtl_util.h" + +#define IGTL_TRANSFORM_SIZE 48 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +typedef igtl_float32[12] transform; +*/ + +/** Converts endianness of each member variable + * in igtl_image_header from host byte order to network byte order, + * or vice versa. */ +void igtl_export igtl_transform_convert_byte_order(igtl_float32* transform); + +/** Calculates CRC of transform data. */ +igtl_uint64 igtl_export igtl_transform_get_crc(igtl_float32* transform); + +#ifdef __cplusplus +} +#endif +#endif /*__IGTL_TRANSFORM_H*/ + diff --git a/openigtlink/repo/Source/igtlutil/igtl_types.h b/openigtlink/repo/Source/igtlutil/igtl_types.h new file mode 100644 index 0000000..f7213f1 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_types.h @@ -0,0 +1,352 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TYPES_H +#define __IGTL_TYPES_H + +#include "igtl_typeconfig.h" + +enum IANA_ENCODING_TYPE +{ + IANA_TYPE_US_ASCII = 3, + IANA_TYPE_ISO_8859_1 = 4, + IANA_TYPE_ISO_8859_2 = 5, + IANA_TYPE_ISO_8859_3 = 6, + IANA_TYPE_ISO_8859_4 = 7, + IANA_TYPE_ISO_8859_5 = 8, + IANA_TYPE_ISO_8859_6 = 9, + IANA_TYPE_ISO_8859_7 = 10, + IANA_TYPE_ISO_8859_8 = 11, + IANA_TYPE_ISO_8859_9 = 12, + IANA_TYPE_ISO_8859_10 = 13, + IANA_TYPE_ISO_6937_2_add = 14, + IANA_TYPE_JIS_X0201 = 15, + IANA_TYPE_JIS_Encoding = 16, + IANA_TYPE_Shift_JIS = 17, + IANA_TYPE_EUC_JP = 18, + IANA_TYPE_Extended_UNIX_Code_Fixed_Width_for_Japanese = 19, + IANA_TYPE_BS_4730 = 20, + IANA_TYPE_SEN_850200_C = 21, + IANA_TYPE_IT = 22, + IANA_TYPE_ES = 23, + IANA_TYPE_DIN_66003 = 24, + IANA_TYPE_NS_4551_1 = 25, + IANA_TYPE_NF_Z_62_010 = 26, + IANA_TYPE_ISO_10646_UTF_1 = 27, + IANA_TYPE_ISO_646_basic_1983 = 28, + IANA_TYPE_INVARIANT = 29, + IANA_TYPE_ISO_646_irv_1983 = 30, + IANA_TYPE_NATS_SEFI = 31, + IANA_TYPE_NATS_SEFI_ADD = 32, + IANA_TYPE_NATS_DANO = 33, + IANA_TYPE_NATS_DANO_ADD = 34, + IANA_TYPE_SEN_850200_B = 35, + IANA_TYPE_KS_C_5601_1987 = 36, + IANA_TYPE_ISO_2022_KR = 37, + IANA_TYPE_EUC_KR = 38, + IANA_TYPE_ISO_2022_JP = 39, + IANA_TYPE_ISO_2022_JP_2 = 40, + IANA_TYPE_JIS_C6220_1969_jp = 41, + IANA_TYPE_JIS_C6220_1969_ro = 42, + IANA_TYPE_PT = 43, + IANA_TYPE_greek7_old = 44, + IANA_TYPE_latin_greek = 45, + IANA_TYPE_NF_Z_62_010_1973 = 46, + IANA_TYPE_Latin_greek_1 = 47, + IANA_TYPE_ISO_5427 = 48, + IANA_TYPE_JIS_C6226_1978 = 49, + IANA_TYPE_BS_viewdata = 50, + IANA_TYPE_INIS = 51, + IANA_TYPE_INIS_8 = 52, + IANA_TYPE_INIS_cyrillic = 53, + IANA_TYPE_ISO_5427_1981 = 54, + IANA_TYPE_ISO_5428_1980 = 55, + IANA_TYPE_GB_1988_80 = 56, + IANA_TYPE_GB_2312_80 = 57, + IANA_TYPE_NS_4551_2 = 58, + IANA_TYPE_videotex_suppl = 59, + IANA_TYPE_PT2 = 60, + IANA_TYPE_ES2 = 61, + IANA_TYPE_MSZ_7795_3 = 62, + IANA_TYPE_JIS_C6226_1983 = 63, + IANA_TYPE_greek7 = 64, + IANA_TYPE_ASMO_449 = 65, + IANA_TYPE_iso_ir_90 = 66, + IANA_TYPE_JIS_C6229_1984_a = 67, + IANA_TYPE_JIS_C6229_1984_b = 68, + IANA_TYPE_JIS_C6229_1984_b_add = 69, + IANA_TYPE_JIS_C6229_1984_hand = 70, + IANA_TYPE_JIS_C6229_1984_hand_add = 71, + IANA_TYPE_JIS_C6229_1984_kana = 72, + IANA_TYPE_ISO_2033_1983 = 73, + IANA_TYPE_ANSI_X3_110_1983 = 74, + IANA_TYPE_T_61_7bit = 75, + IANA_TYPE_T_61_8bit = 76, + IANA_TYPE_ECMA_cyrillic = 77, + IANA_TYPE_CSA_Z243_4_1985_1 = 78, + IANA_TYPE_CSA_Z243_4_1985_2 = 79, + IANA_TYPE_CSA_Z243_4_1985_gr = 80, + IANA_TYPE_ISO_8859_6_E = 81, + IANA_TYPE_ISO_8859_6_I = 82, + IANA_TYPE_T_101_G2 = 83, + IANA_TYPE_ISO_8859_8_E = 84, + IANA_TYPE_ISO_8859_8_I = 85, + IANA_TYPE_CSN_369103 = 86, + IANA_TYPE_JUS_I_B1_002 = 87, + IANA_TYPE_IEC_P27_1 = 88, + IANA_TYPE_JUS_I_B1_003_serb = 89, + IANA_TYPE_JUS_I_B1_003_mac = 90, + IANA_TYPE_greek_ccitt = 91, + IANA_TYPE_NC_NC00_10_81 = 92, + IANA_TYPE_ISO_6937_2_25 = 93, + IANA_TYPE_GOST_19768_74 = 94, + IANA_TYPE_ISO_8859_supp = 95, + IANA_TYPE_ISO_10367_box = 96, + IANA_TYPE_latin_lap = 97, + IANA_TYPE_JIS_X0212_1990 = 98, + IANA_TYPE_DS_2089 = 99, + IANA_TYPE_us_dk = 100, + IANA_TYPE_dk_us = 101, + IANA_TYPE_KSC5636 = 102, + IANA_TYPE_UNICODE_1_1_UTF_7 = 103, + IANA_TYPE_ISO_2022_CN = 104, + IANA_TYPE_ISO_2022_CN_EXT = 105, + IANA_TYPE_UTF_8 = 106, + IANA_TYPE_ISO_8859_13 = 109, + IANA_TYPE_ISO_8859_14 = 110, + IANA_TYPE_ISO_8859_15 = 111, + IANA_TYPE_ISO_8859_16 = 112, + IANA_TYPE_GBK = 113, + IANA_TYPE_GB18030 = 114, + IANA_TYPE_OSD_EBCDIC_DF04_15 = 115, + IANA_TYPE_OSD_EBCDIC_DF03_IRV = 116, + IANA_TYPE_OSD_EBCDIC_DF04_1 = 117, + IANA_TYPE_ISO_11548_1 = 118, + IANA_TYPE_KZ_1048 = 119, + IANA_TYPE_ISO_10646_UCS_2 = 1000, + IANA_TYPE_ISO_10646_UCS_4 = 1001, + IANA_TYPE_ISO_10646_UCS_Basic = 1002, + IANA_TYPE_ISO_10646_Unicode_Latin1 = 1003, + IANA_TYPE_ISO_10646_J_1 = 1004, + IANA_TYPE_ISO_Unicode_IBM_1261 = 1005, + IANA_TYPE_ISO_Unicode_IBM_1268 = 1006, + IANA_TYPE_ISO_Unicode_IBM_1276 = 1007, + IANA_TYPE_ISO_Unicode_IBM_1264 = 1008, + IANA_TYPE_ISO_Unicode_IBM_1265 = 1009, + IANA_TYPE_UNICODE_1_1 = 1010, + IANA_TYPE_SCSU = 1011, + IANA_TYPE_UTF_7 = 1012, + IANA_TYPE_UTF_16BE = 1013, + IANA_TYPE_UTF_16LE = 1014, + IANA_TYPE_UTF_16 = 1015, + IANA_TYPE_CESU_8 = 1016, + IANA_TYPE_UTF_32 = 1017, + IANA_TYPE_UTF_32BE = 1018, + IANA_TYPE_UTF_32LE = 1019, + IANA_TYPE_BOCU_1 = 1020, + IANA_TYPE_ISO_8859_1_Windows_3_0_Latin_1 = 2000, + IANA_TYPE_ISO_8859_1_Windows_3_1_Latin_1 = 2001, + IANA_TYPE_ISO_8859_2_Windows_Latin_2 = 2002, + IANA_TYPE_ISO_8859_9_Windows_Latin_5 = 2003, + IANA_TYPE_hp_roman8 = 2004, + IANA_TYPE_Adobe_Standard_Encoding = 2005, + IANA_TYPE_Ventura_US = 2006, + IANA_TYPE_Ventura_International = 2007, + IANA_TYPE_DEC_MCS = 2008, + IANA_TYPE_IBM850 = 2009, + IANA_TYPE_PC8_Danish_Norwegian = 2012, + IANA_TYPE_IBM862 = 2013, + IANA_TYPE_PC8_Turkish = 2014, + IANA_TYPE_IBM_Symbols = 2015, + IANA_TYPE_IBM_Thai = 2016, + IANA_TYPE_HP_Legal = 2017, + IANA_TYPE_HP_Pi_font = 2018, + IANA_TYPE_HP_Math8 = 2019, + IANA_TYPE_Adobe_Symbol_Encoding = 2020, + IANA_TYPE_HP_DeskTop = 2021, + IANA_TYPE_Ventura_Math = 2022, + IANA_TYPE_Microsoft_Publishing = 2023, + IANA_TYPE_Windows_31J = 2024, + IANA_TYPE_GB2312 = 2025, + IANA_TYPE_Big5 = 2026, + IANA_TYPE_macintosh = 2027, + IANA_TYPE_IBM037 = 2028, + IANA_TYPE_IBM038 = 2029, + IANA_TYPE_IBM273 = 2030, + IANA_TYPE_IBM274 = 2031, + IANA_TYPE_IBM275 = 2032, + IANA_TYPE_IBM277 = 2033, + IANA_TYPE_IBM278 = 2034, + IANA_TYPE_IBM280 = 2035, + IANA_TYPE_IBM281 = 2036, + IANA_TYPE_IBM284 = 2037, + IANA_TYPE_IBM285 = 2038, + IANA_TYPE_IBM290 = 2039, + IANA_TYPE_IBM297 = 2040, + IANA_TYPE_IBM420 = 2041, + IANA_TYPE_IBM423 = 2042, + IANA_TYPE_IBM424 = 2043, + IANA_TYPE_IBM437 = 2011, + IANA_TYPE_IBM500 = 2044, + IANA_TYPE_IBM851 = 2045, + IANA_TYPE_IBM852 = 2010, + IANA_TYPE_IBM855 = 2046, + IANA_TYPE_IBM857 = 2047, + IANA_TYPE_IBM860 = 2048, + IANA_TYPE_IBM861 = 2049, + IANA_TYPE_IBM863 = 2050, + IANA_TYPE_IBM864 = 2051, + IANA_TYPE_IBM865 = 2052, + IANA_TYPE_IBM868 = 2053, + IANA_TYPE_IBM869 = 2054, + IANA_TYPE_IBM870 = 2055, + IANA_TYPE_IBM871 = 2056, + IANA_TYPE_IBM880 = 2057, + IANA_TYPE_IBM891 = 2058, + IANA_TYPE_IBM903 = 2059, + IANA_TYPE_IBM904 = 2060, + IANA_TYPE_IBM905 = 2061, + IANA_TYPE_IBM918 = 2062, + IANA_TYPE_IBM1026 = 2063, + IANA_TYPE_EBCDIC_AT_DE = 2064, + IANA_TYPE_EBCDIC_AT_DE_A = 2065, + IANA_TYPE_EBCDIC_CA_FR = 2066, + IANA_TYPE_EBCDIC_DK_NO = 2067, + IANA_TYPE_EBCDIC_DK_NO_A = 2068, + IANA_TYPE_EBCDIC_FI_SE = 2069, + IANA_TYPE_EBCDIC_FI_SE_A = 2070, + IANA_TYPE_EBCDIC_FR = 2071, + IANA_TYPE_EBCDIC_IT = 2072, + IANA_TYPE_EBCDIC_PT = 2073, + IANA_TYPE_EBCDIC_ES = 2074, + IANA_TYPE_EBCDIC_ES_A = 2075, + IANA_TYPE_EBCDIC_ES_S = 2076, + IANA_TYPE_EBCDIC_UK = 2077, + IANA_TYPE_EBCDIC_US = 2078, + IANA_TYPE_UNKNOWN_8BIT = 2079, + IANA_TYPE_MNEMONIC = 2080, + IANA_TYPE_MNEM = 2081, + IANA_TYPE_VISCII = 2082, + IANA_TYPE_VIQR = 2083, + IANA_TYPE_KOI8_R = 2084, + IANA_TYPE_HZ_GB_2312 = 2085, + IANA_TYPE_IBM866 = 2086, + IANA_TYPE_IBM775 = 2087, + IANA_TYPE_KOI8_U = 2088, + IANA_TYPE_IBM00858 = 2089, + IANA_TYPE_IBM00924 = 2090, + IANA_TYPE_IBM01140 = 2091, + IANA_TYPE_IBM01141 = 2092, + IANA_TYPE_IBM01142 = 2093, + IANA_TYPE_IBM01143 = 2094, + IANA_TYPE_IBM01144 = 2095, + IANA_TYPE_IBM01145 = 2096, + IANA_TYPE_IBM01146 = 2097, + IANA_TYPE_IBM01147 = 2098, + IANA_TYPE_IBM01148 = 2099, + IANA_TYPE_IBM01149 = 2100, + IANA_TYPE_Big5_HKSCS = 2101, + IANA_TYPE_IBM1047 = 2102, + IANA_TYPE_PTCP154 = 2103, + IANA_TYPE_Amiga_1251 = 2104, + IANA_TYPE_KOI7_switched = 2105, + IANA_TYPE_BRF = 2106, + IANA_TYPE_TSCII = 2107, + IANA_TYPE_CP51932 = 2108, + IANA_TYPE_windows_874 = 2109, + IANA_TYPE_windows_1250 = 2250, + IANA_TYPE_windows_1251 = 2251, + IANA_TYPE_windows_1252 = 2252, + IANA_TYPE_windows_1253 = 2253, + IANA_TYPE_windows_1254 = 2254, + IANA_TYPE_windows_1255 = 2255, + IANA_TYPE_windows_1256 = 2256, + IANA_TYPE_windows_1257 = 2257, + IANA_TYPE_windows_1258 = 2258, + IANA_TYPE_TIS_620 = 2259, + IANA_TYPE_CP50220 = 2260 +}; +/* 8-bit integer type */ +#if IGTL_SIZEOF_CHAR == 1 +typedef unsigned char igtl_uint8; +typedef signed char igtl_int8; +#else +# error "No native data type can represent an 8-bit integer." +#endif + +/* 16-bit integer type */ +#if IGTL_SIZEOF_SHORT == 2 +typedef unsigned short igtl_uint16; +typedef signed short igtl_int16; +#elif IGTL_SIZEOF_INT == 2 +typedef unsigned int igtl_uint16; +typedef signed int igtl_int16; +#else +# error "No native data type can represent a 16-bit integer." +#endif + +/* 32-bit integer type */ +#if IGTL_SIZEOF_INT == 4 +typedef unsigned int igtl_uint32; +typedef signed int igtl_int32; +#elif IGTL_SIZEOF_LONG == 4 +typedef unsigned long igtl_uint32; +typedef signed long igtl_int32; +#else +# error "No native data type can represent a 32-bit integer." +#endif + +/* 64-bit integer type */ +#if defined(IGTL_TYPE_USE_LONG_LONG) && IGTL_SIZEOF_LONG_LONG == 8 +typedef unsigned long long igtl_uint64; +typedef signed long long igtl_int64; +#elif IGTL_SIZEOF_INT == 8 +typedef unsigned int igtl_uint64; +typedef signed int igtl_int64; +#elif IGTL_SIZEOF_LONG == 8 +typedef unsigned long igtl_uint64; +typedef signed long igtl_int64; +#elif defined(IGTL_TYPE_USE___INT64) && IGTL_SIZEOF___INT64 == 8 +typedef unsigned __int64 igtl_uint64; +typedef signed __int64 igtl_int64; +#elif defined(IGTL_TYPE_USE_INT64_T) && IGTL_SIZEOF_INT64_T == 8 +typedef unsigned int64_t igtl_uint64; +typedef signed int64_t igtl_int64; +#else +# error "No native data type can represent a 64-bit integer." +#endif + +/* 32-bit floating point type */ +#if IGTL_SIZEOF_FLOAT == 4 +typedef float igtl_float32; +#else +# error "No native data type can represent a 32-bit floating point value." +#endif + +/* 64-bit floating point type */ +#if IGTL_SIZEOF_DOUBLE == 8 +typedef double igtl_float64; +#else +# error "No native data type can represent a 64-bit floating point value." +#endif + +/* 128-bit complex type (64-bit real + 64-bit imaginal)*/ +typedef double igtl_complex[2]; + + +#endif /* __IGTL_TYPES_H */ + + + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_unit.c b/openigtlink/repo/Source/igtlutil/igtl_unit.c new file mode 100644 index 0000000..1410b64 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_unit.c @@ -0,0 +1,89 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_unit.h" +#include "igtl_util.h" + + +void igtl_export igtl_unit_init(igtl_unit_data* data) +{ + int i; + + data->prefix = 0; + for (i = 0; i < 6; i ++) + { + data->unit[i] = 0; + data->exp[i] = 0; + } + +} + + +igtl_unit igtl_export igtl_unit_pack(igtl_unit_data* data) +{ + igtl_unit pack; + igtl_uint8 exp; + int i; + + pack = 0x0; + + /* Prefix */ + pack |= ((igtl_uint64) data->prefix) << 60; + + /* Units */ + for (i = 0; i < 6; i ++) + { + /* Check if exp is within the valid range */ + if (data->exp[i] < -7 || data->exp[i] > 7) + { + return 0; + } + /* Convert signed value from 8-bit to 4-bit */ + exp = data->exp[i] & 0x0F; + + /* put into the pack */ + pack |= ((igtl_uint64)data->unit[i]) << (10*(5-i) + 4); + pack |= ((igtl_uint64)exp) << (10*(5-i)); + } + + return pack; +} + + +int igtl_export igtl_unit_unpack(igtl_unit pack, igtl_unit_data* data) +{ + int i; + + /* Prefix */ + data->prefix = (igtl_uint8) (pack >> 60); + + /* Units */ + for (i = 0; i < 6; i ++) + { + data->unit[i] = (igtl_uint8) (pack >> (10*(5-i) + 4)) & 0x3F; + data->exp[i] = (igtl_uint8) (pack >> (10*(5-i))) & 0x0F; + /* Convert signed value in exponent field from 4-bit to 8-bit */ + if (data->exp[i] & 0x08) + { + data->exp[i] |= 0xF0; + } + } + return 1; +} + + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_unit.h b/openigtlink/repo/Source/igtlutil/igtl_unit.h new file mode 100644 index 0000000..c4b319e --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_unit.h @@ -0,0 +1,97 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_UNIT_H +#define __IGTL_UNIT_H + +#include "igtl_types.h" +#include "igtl_win32header.h" +#include "igtl_unit.h" + + +/* PREFIX */ +#define IGTL_UNIT_PREFIX_NONE 0x0 /* None */ +#define IGTL_UNIT_PREFIX_DEKA 0x1 /* deka (deca) (1e1) */ +#define IGTL_UNIT_PREFIX_HECTO 0x2 /* hecto (1e2) */ +#define IGTL_UNIT_PREFIX_KILO 0x3 /* kilo (1e3) */ +#define IGTL_UNIT_PREFIX_MEGA 0x4 /* mega (1e6) */ +#define IGTL_UNIT_PREFIX_GIGA 0x5 /* giga (1e9) */ +#define IGTL_UNIT_PREFIX_TERA 0x6 /* tera (1e12) */ +#define IGTL_UNIT_PREFIX_PETA 0x7 /* peta (1e15) */ +#define IGTL_UNIT_PREFIX_DECI 0x9 /* deci (1e-1) */ +#define IGTL_UNIT_PREFIX_CENTI 0xA /* centi (1e-2) */ +#define IGTL_UNIT_PREFIX_MILLI 0xB /* milli (1e-3) */ +#define IGTL_UNIT_PREFIX_MICRO 0xC /* micro (1e-6) */ +#define IGTL_UNIT_PREFIX_NANO 0xD /* nano (1e-9) */ +#define IGTL_UNIT_PREFIX_PICO 0xE /* pico (1e-12) */ +#define IGTL_UNIT_PREFIX_FEMTO 0xF /* femto (1e-15) */ + +/* SI Base Units */ +#define IGTL_UNIT_SI_BASE_NONE 0x00 +#define IGTL_UNIT_SI_BASE_METER 0x01 /* meter */ +#define IGTL_UNIT_SI_BASE_GRAM 0x02 /* gram */ +#define IGTL_UNIT_SI_BASE_SECOND 0x03 /* second */ +#define IGTL_UNIT_SI_BASE_AMPERE 0x04 /* ampere */ +#define IGTL_UNIT_SI_BASE_KELVIN 0x05 /* kelvin */ +#define IGTL_UNIT_SI_BASE_MOLE 0x06 /* mole */ +#define IGTL_UNIT_SI_BASE_CANDELA 0x07 /* candela */ + +/* SI Derived Units */ +#define IGTL_UNIT_SI_DERIVED_RADIAN 0x08 /* radian meter/meter */ +#define IGTL_UNIT_SI_DERIVED_STERADIAN 0x09 /* steradian meter^2/meter^2 */ +#define IGTL_UNIT_SI_DERIVED_HERTZ 0x0A /* hertz /second */ +#define IGTL_UNIT_SI_DERIVED_NEWTON 0x0B /* newton meter-kilogram/second^2 */ +#define IGTL_UNIT_SI_DERIVED_PASCAL 0x0C /* pascal kilogram/meter-second^2 */ +#define IGTL_UNIT_SI_DERIVED_JOULE 0x0D /* joule meter^2-kilogram/second^2 */ +#define IGTL_UNIT_SI_DERIVED_WATT 0x0E /* watt meter^2-kilogram/second^3 */ +#define IGTL_UNIT_SI_DERIVED_COULOMB 0x0F /* coulomb second-ampere */ +#define IGTL_UNIT_SI_DERIVED_VOLT 0x10 /* volt meter^2-kilogram/second^3-ampere */ +#define IGTL_UNIT_SI_DERIVED_FARAD 0x11 /* farad second^4-ampere^2/meter^2-kilogram */ +#define IGTL_UNIT_SI_DERIVED_OHM 0x12 /* ohm meter^2-kilogram/second^3-ampere^2 */ +#define IGTL_UNIT_SI_DERIVED_SIEMENS 0x13 /* siemens second^3-ampere^2/meter^2-kilogram */ +#define IGTL_UNIT_SI_DERIVED_WEBER 0x14 /* weber meter^2-kilogram/second^2-ampere */ +#define IGTL_UNIT_SI_DERIVED_TESLA 0x15 /* tesla kilogram/second^2-ampere */ +#define IGTL_UNIT_SI_DERIVED_HENRY 0x16 /* henry meter^2-kilogram/second^2-ampere^2 */ +#define IGTL_UNIT_SI_DERIVED_LUMEN 0x17 /* lumen candela-steradian */ +#define IGTL_UNIT_SI_DERIVED_LUX 0x18 /* lux candela-steradian/meter^2 */ +#define IGTL_UNIT_SI_DERIVED_BECQUEREL 0x19 /* becquerel /second */ +#define IGTL_UNIT_SI_DERIVED_GRAY 0x1A /* gray meter^2/second^2 */ +#define IGTL_UNIT_SI_DERIVED_SIEVERT 0x1B /* sievert meter^2/second^2 */ + +typedef igtl_uint64 igtl_unit; + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + igtl_uint8 prefix; /* Prefix */ + igtl_uint8 unit[6]; /* Either SI-Base or SI-Derived */ + igtl_int8 exp[6]; /* Must be within [-7, 7] */ +} igtl_unit_data; + +void igtl_export igtl_unit_init(igtl_unit_data* data); +igtl_unit igtl_export igtl_unit_pack(igtl_unit_data* data); +int igtl_export igtl_unit_unpack(igtl_unit pack, igtl_unit_data* data); + +#ifdef __cplusplus +} +#endif + +#endif /* __IGTL_UNIT_H */ + + + + diff --git a/openigtlink/repo/Source/igtlutil/igtl_util.c b/openigtlink/repo/Source/igtlutil/igtl_util.c new file mode 100644 index 0000000..dcca7a7 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_util.c @@ -0,0 +1,277 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtl_util.h" + +int igtl_export igtl_is_little_endian() +{ + short a = 1; + return ((char*)&a)[0]; +} + + +igtl_uint64 igtl_export crc64(unsigned char *data, igtl_uint64 len, igtl_uint64 crc) +{ + + static const igtl_uint64 table[256] = { + 0x0000000000000000ULL,0x42F0E1EBA9EA3693ULL, + 0x85E1C3D753D46D26ULL,0xC711223CFA3E5BB5ULL, + 0x493366450E42ECDFULL,0x0BC387AEA7A8DA4CULL, + 0xCCD2A5925D9681F9ULL,0x8E224479F47CB76AULL, + 0x9266CC8A1C85D9BEULL,0xD0962D61B56FEF2DULL, + 0x17870F5D4F51B498ULL,0x5577EEB6E6BB820BULL, + 0xDB55AACF12C73561ULL,0x99A54B24BB2D03F2ULL, + 0x5EB4691841135847ULL,0x1C4488F3E8F96ED4ULL, + 0x663D78FF90E185EFULL,0x24CD9914390BB37CULL, + 0xE3DCBB28C335E8C9ULL,0xA12C5AC36ADFDE5AULL, + 0x2F0E1EBA9EA36930ULL,0x6DFEFF5137495FA3ULL, + 0xAAEFDD6DCD770416ULL,0xE81F3C86649D3285ULL, + 0xF45BB4758C645C51ULL,0xB6AB559E258E6AC2ULL, + 0x71BA77A2DFB03177ULL,0x334A9649765A07E4ULL, + 0xBD68D2308226B08EULL,0xFF9833DB2BCC861DULL, + 0x388911E7D1F2DDA8ULL,0x7A79F00C7818EB3BULL, + 0xCC7AF1FF21C30BDEULL,0x8E8A101488293D4DULL, + 0x499B3228721766F8ULL,0x0B6BD3C3DBFD506BULL, + 0x854997BA2F81E701ULL,0xC7B97651866BD192ULL, + 0x00A8546D7C558A27ULL,0x4258B586D5BFBCB4ULL, + 0x5E1C3D753D46D260ULL,0x1CECDC9E94ACE4F3ULL, + 0xDBFDFEA26E92BF46ULL,0x990D1F49C77889D5ULL, + 0x172F5B3033043EBFULL,0x55DFBADB9AEE082CULL, + 0x92CE98E760D05399ULL,0xD03E790CC93A650AULL, + 0xAA478900B1228E31ULL,0xE8B768EB18C8B8A2ULL, + 0x2FA64AD7E2F6E317ULL,0x6D56AB3C4B1CD584ULL, + 0xE374EF45BF6062EEULL,0xA1840EAE168A547DULL, + 0x66952C92ECB40FC8ULL,0x2465CD79455E395BULL, + 0x3821458AADA7578FULL,0x7AD1A461044D611CULL, + 0xBDC0865DFE733AA9ULL,0xFF3067B657990C3AULL, + 0x711223CFA3E5BB50ULL,0x33E2C2240A0F8DC3ULL, + 0xF4F3E018F031D676ULL,0xB60301F359DBE0E5ULL, + 0xDA050215EA6C212FULL,0x98F5E3FE438617BCULL, + 0x5FE4C1C2B9B84C09ULL,0x1D14202910527A9AULL, + 0x93366450E42ECDF0ULL,0xD1C685BB4DC4FB63ULL, + 0x16D7A787B7FAA0D6ULL,0x5427466C1E109645ULL, + 0x4863CE9FF6E9F891ULL,0x0A932F745F03CE02ULL, + 0xCD820D48A53D95B7ULL,0x8F72ECA30CD7A324ULL, + 0x0150A8DAF8AB144EULL,0x43A04931514122DDULL, + 0x84B16B0DAB7F7968ULL,0xC6418AE602954FFBULL, + 0xBC387AEA7A8DA4C0ULL,0xFEC89B01D3679253ULL, + 0x39D9B93D2959C9E6ULL,0x7B2958D680B3FF75ULL, + 0xF50B1CAF74CF481FULL,0xB7FBFD44DD257E8CULL, + 0x70EADF78271B2539ULL,0x321A3E938EF113AAULL, + 0x2E5EB66066087D7EULL,0x6CAE578BCFE24BEDULL, + 0xABBF75B735DC1058ULL,0xE94F945C9C3626CBULL, + 0x676DD025684A91A1ULL,0x259D31CEC1A0A732ULL, + 0xE28C13F23B9EFC87ULL,0xA07CF2199274CA14ULL, + 0x167FF3EACBAF2AF1ULL,0x548F120162451C62ULL, + 0x939E303D987B47D7ULL,0xD16ED1D631917144ULL, + 0x5F4C95AFC5EDC62EULL,0x1DBC74446C07F0BDULL, + 0xDAAD56789639AB08ULL,0x985DB7933FD39D9BULL, + 0x84193F60D72AF34FULL,0xC6E9DE8B7EC0C5DCULL, + 0x01F8FCB784FE9E69ULL,0x43081D5C2D14A8FAULL, + 0xCD2A5925D9681F90ULL,0x8FDAB8CE70822903ULL, + 0x48CB9AF28ABC72B6ULL,0x0A3B7B1923564425ULL, + 0x70428B155B4EAF1EULL,0x32B26AFEF2A4998DULL, + 0xF5A348C2089AC238ULL,0xB753A929A170F4ABULL, + 0x3971ED50550C43C1ULL,0x7B810CBBFCE67552ULL, + 0xBC902E8706D82EE7ULL,0xFE60CF6CAF321874ULL, + 0xE224479F47CB76A0ULL,0xA0D4A674EE214033ULL, + 0x67C58448141F1B86ULL,0x253565A3BDF52D15ULL, + 0xAB1721DA49899A7FULL,0xE9E7C031E063ACECULL, + 0x2EF6E20D1A5DF759ULL,0x6C0603E6B3B7C1CAULL, + 0xF6FAE5C07D3274CDULL,0xB40A042BD4D8425EULL, + 0x731B26172EE619EBULL,0x31EBC7FC870C2F78ULL, + 0xBFC9838573709812ULL,0xFD39626EDA9AAE81ULL, + 0x3A28405220A4F534ULL,0x78D8A1B9894EC3A7ULL, + 0x649C294A61B7AD73ULL,0x266CC8A1C85D9BE0ULL, + 0xE17DEA9D3263C055ULL,0xA38D0B769B89F6C6ULL, + 0x2DAF4F0F6FF541ACULL,0x6F5FAEE4C61F773FULL, + 0xA84E8CD83C212C8AULL,0xEABE6D3395CB1A19ULL, + 0x90C79D3FEDD3F122ULL,0xD2377CD44439C7B1ULL, + 0x15265EE8BE079C04ULL,0x57D6BF0317EDAA97ULL, + 0xD9F4FB7AE3911DFDULL,0x9B041A914A7B2B6EULL, + 0x5C1538ADB04570DBULL,0x1EE5D94619AF4648ULL, + 0x02A151B5F156289CULL,0x4051B05E58BC1E0FULL, + 0x87409262A28245BAULL,0xC5B073890B687329ULL, + 0x4B9237F0FF14C443ULL,0x0962D61B56FEF2D0ULL, + 0xCE73F427ACC0A965ULL,0x8C8315CC052A9FF6ULL, + 0x3A80143F5CF17F13ULL,0x7870F5D4F51B4980ULL, + 0xBF61D7E80F251235ULL,0xFD913603A6CF24A6ULL, + 0x73B3727A52B393CCULL,0x31439391FB59A55FULL, + 0xF652B1AD0167FEEAULL,0xB4A25046A88DC879ULL, + 0xA8E6D8B54074A6ADULL,0xEA16395EE99E903EULL, + 0x2D071B6213A0CB8BULL,0x6FF7FA89BA4AFD18ULL, + 0xE1D5BEF04E364A72ULL,0xA3255F1BE7DC7CE1ULL, + 0x64347D271DE22754ULL,0x26C49CCCB40811C7ULL, + 0x5CBD6CC0CC10FAFCULL,0x1E4D8D2B65FACC6FULL, + 0xD95CAF179FC497DAULL,0x9BAC4EFC362EA149ULL, + 0x158E0A85C2521623ULL,0x577EEB6E6BB820B0ULL, + 0x906FC95291867B05ULL,0xD29F28B9386C4D96ULL, + 0xCEDBA04AD0952342ULL,0x8C2B41A1797F15D1ULL, + 0x4B3A639D83414E64ULL,0x09CA82762AAB78F7ULL, + 0x87E8C60FDED7CF9DULL,0xC51827E4773DF90EULL, + 0x020905D88D03A2BBULL,0x40F9E43324E99428ULL, + 0x2CFFE7D5975E55E2ULL,0x6E0F063E3EB46371ULL, + 0xA91E2402C48A38C4ULL,0xEBEEC5E96D600E57ULL, + 0x65CC8190991CB93DULL,0x273C607B30F68FAEULL, + 0xE02D4247CAC8D41BULL,0xA2DDA3AC6322E288ULL, + 0xBE992B5F8BDB8C5CULL,0xFC69CAB42231BACFULL, + 0x3B78E888D80FE17AULL,0x7988096371E5D7E9ULL, + 0xF7AA4D1A85996083ULL,0xB55AACF12C735610ULL, + 0x724B8ECDD64D0DA5ULL,0x30BB6F267FA73B36ULL, + 0x4AC29F2A07BFD00DULL,0x08327EC1AE55E69EULL, + 0xCF235CFD546BBD2BULL,0x8DD3BD16FD818BB8ULL, + 0x03F1F96F09FD3CD2ULL,0x41011884A0170A41ULL, + 0x86103AB85A2951F4ULL,0xC4E0DB53F3C36767ULL, + 0xD8A453A01B3A09B3ULL,0x9A54B24BB2D03F20ULL, + 0x5D45907748EE6495ULL,0x1FB5719CE1045206ULL, + 0x919735E51578E56CULL,0xD367D40EBC92D3FFULL, + 0x1476F63246AC884AULL,0x568617D9EF46BED9ULL, + 0xE085162AB69D5E3CULL,0xA275F7C11F7768AFULL, + 0x6564D5FDE549331AULL,0x279434164CA30589ULL, + 0xA9B6706FB8DFB2E3ULL,0xEB46918411358470ULL, + 0x2C57B3B8EB0BDFC5ULL,0x6EA7525342E1E956ULL, + 0x72E3DAA0AA188782ULL,0x30133B4B03F2B111ULL, + 0xF7021977F9CCEAA4ULL,0xB5F2F89C5026DC37ULL, + 0x3BD0BCE5A45A6B5DULL,0x79205D0E0DB05DCEULL, + 0xBE317F32F78E067BULL,0xFCC19ED95E6430E8ULL, + 0x86B86ED5267CDBD3ULL,0xC4488F3E8F96ED40ULL, + 0x0359AD0275A8B6F5ULL,0x41A94CE9DC428066ULL, + 0xCF8B0890283E370CULL,0x8D7BE97B81D4019FULL, + 0x4A6ACB477BEA5A2AULL,0x089A2AACD2006CB9ULL, + 0x14DEA25F3AF9026DULL,0x562E43B4931334FEULL, + 0x913F6188692D6F4BULL,0xD3CF8063C0C759D8ULL, + 0x5DEDC41A34BBEEB2ULL,0x1F1D25F19D51D821ULL, + 0xD80C07CD676F8394ULL,0x9AFCE626CE85B507ULL, + }; + + while (len > 0) + { + crc = table[*data ^ (unsigned char)(crc >> 56)] ^ (crc << 8); + data++; + len--; + } + return crc; +} + + +igtl_uint32 igtl_export igtl_nanosec_to_frac(igtl_uint32 nanosec) +{ + + igtl_uint32 base = 1000000000; /*10^9*/ + + igtl_uint32 mask = 0x80000000; + igtl_uint32 r = 0x00000000; + + do + { + base++; + base >>= 1; + if (nanosec >= base) + { + r |= mask; + nanosec -= base; + } + mask >>= 1; + } + while (mask); + + return r; +} + + +igtl_uint32 igtl_export igtl_frac_to_nanosec(igtl_uint32 frac) +{ + igtl_uint32 base = 1000000000; /*10^9*/ + + igtl_uint32 mask = 0x80000000; + igtl_uint32 r = 0x00000000; + + do + { + base++; + base >>= 1; + r += (frac & mask)? base : 0; + mask >>= 1; + } while (mask); + + return r; +} + + +void igtl_export igtl_message_dump_hex(FILE* stream, const void* message, int bytes) +{ + /* Print first 256 bytes as HEX values in STDERR for debug */ + + unsigned char* p; + int row; + int cols_in_last_row; + int i; + int j; + + p = (unsigned char*)message; + row = bytes / 16; + cols_in_last_row = bytes % 16; + + for (i = 0; i < row; i ++) + { + for (j = 0; j < 16; j ++) + { + fprintf(stream, "%02x ", *p); + p++; + } + fprintf(stream, "\n"); + } + + for (j = 0; j < cols_in_last_row; j ++) + { + fprintf(stream, "%02x ", p[j]); + } + fprintf(stream, "\n"); + +} + + +/* Calculate number of bytes / element */ +igtl_uint32 igtl_export igtl_get_scalar_size(int type) +{ + igtl_uint32 bytes; + + switch (type) + { + case IGTL_SCALAR_INT8: + case IGTL_SCALAR_UINT8: + bytes = 1; + break; + case IGTL_SCALAR_INT16: + case IGTL_SCALAR_UINT16: + bytes = 2; + break; + case IGTL_SCALAR_INT32: + case IGTL_SCALAR_UINT32: + case IGTL_SCALAR_FLOAT32: + bytes = 4; + break; + case IGTL_SCALAR_FLOAT64: + bytes = 8; + break; + case IGTL_SCALAR_COMPLEX: + bytes = 16; + break; + default: + bytes = 0; + break; + } + + return bytes; +} diff --git a/openigtlink/repo/Source/igtlutil/igtl_util.h b/openigtlink/repo/Source/igtlutil/igtl_util.h new file mode 100644 index 0000000..104496d --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_util.h @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_UTIL_H +#define __IGTL_UTIL_H + +#include +#include "igtl_win32header.h" +#include "igtl_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/* Scalar type for point data */ +#define IGTL_SCALAR_INT8 2 +#define IGTL_SCALAR_UINT8 3 +#define IGTL_SCALAR_INT16 4 +#define IGTL_SCALAR_UINT16 5 +#define IGTL_SCALAR_INT32 6 +#define IGTL_SCALAR_UINT32 7 +#define IGTL_SCALAR_FLOAT32 10 +#define IGTL_SCALAR_FLOAT64 11 +#define IGTL_SCALAR_COMPLEX 13 + + +/** Byte order conversion macros */ +#define BYTE_SWAP_INT16(S) (((S) & 0xFF) << 8 \ + | (((S) >> 8) & 0xFF)) +#define BYTE_SWAP_INT32(L) ((BYTE_SWAP_INT16 ((L) & 0xFFFF) << 16) \ + | BYTE_SWAP_INT16 (((L) >> 16) & 0xFFFF)) +#define BYTE_SWAP_INT64(LL) ((BYTE_SWAP_INT32 ((LL) & 0xFFFFFFFF) << 32) \ + | BYTE_SWAP_INT32 (((LL) >> 32) & 0xFFFFFFFF)) + +/** Tests endian of the host */ +int igtl_export igtl_is_little_endian(); +igtl_uint64 igtl_export crc64(unsigned char *data, igtl_uint64 len, igtl_uint64 crc); + +/** Converts nanosecond to fraction / fraction to nanosec. */ +igtl_uint32 igtl_export igtl_nanosec_to_frac(igtl_uint32 nanosec); +igtl_uint32 igtl_export igtl_frac_to_nanosec(igtl_uint32 frac); +void igtl_export igtl_message_dump_hex(FILE* stream, const void* message, int max_size); + +/** Gets size of scalar. Type should be IGTL_SCALAR_* */ +igtl_uint32 igtl_export igtl_get_scalar_size(int type); + +#ifdef __cplusplus +} +#endif + +#endif /*__IGTL_UTIL_H*/ + diff --git a/openigtlink/repo/Source/igtlutil/igtl_win32header.h b/openigtlink/repo/Source/igtlutil/igtl_win32header.h new file mode 100644 index 0000000..51bfa80 --- /dev/null +++ b/openigtlink/repo/Source/igtlutil/igtl_win32header.h @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_WIN32HEADER_H +#define __IGTL_WIN32HEADER_H + +#include "igtl_typeconfig.h" + +#if (defined(_WIN32) || defined(WIN32)) && !defined(IGTLSTATIC) +# ifdef IGTLCommon_EXPORTS +# define igtl_export __declspec(dllexport) +# else +# define igtl_export __declspec(dllimport) +# endif /* igtl_common_exports */ +#else +/* unix needs nothing */ +#define igtl_export +#endif + +#if defined(_WIN32) +# include +#endif + +#if defined(_MSC_VER) + /* Enable MSVC compiler warning messages that are useful but off by default.*/ +# pragma warning ( disable : 4996 ) /* 'strncpy': This function or variable may be unsafe. */ +#endif + + +#endif /*__IGTL_WIN32HEADER_H*/ diff --git a/openigtlink/repo/SuperBuild/CMakeListsVP9Download.txt.in b/openigtlink/repo/SuperBuild/CMakeListsVP9Download.txt.in new file mode 100644 index 0000000..e69de29 diff --git a/openigtlink/repo/SuperBuild/External_AV1.cmake b/openigtlink/repo/SuperBuild/External_AV1.cmake new file mode 100644 index 0000000..0ee57ba --- /dev/null +++ b/openigtlink/repo/SuperBuild/External_AV1.cmake @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 2.8.2) +include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) +include(${OpenIGTLink_SOURCE_DIR}/SuperBuild/FindAV1.cmake) +IF(AV1_FOUND) + # AV1 has been built already + MESSAGE(STATUS "Using AV1 available at: ${AV1_INCLUDE_DIR}") +ELSE() + # AV1 has not been built yet, so download and build it as an external project + SET(GIT_REPOSITORY "https://aomedia.googlesource.com/aom") + SET(GIT_TAG "master") + + MESSAGE(STATUS "Downloading AV1 ${GIT_TAG} from: ${GIT_REPOSITORY}") + + IF(WIN32) # for Windows + SET(AV1_LIBRARY optimized ${AV1_LIBRARY_DIR}\\Release\\aom.lib debug ${AV1_LIBRARY_DIR}\\Debug\\aom.lib CACHE STRING "AV1 library" FORCE) + ELSE() + IF(OpenIGTLink_BUILD_SHARED_LIBS) + IF (CMAKE_CONFIGURATION_TYPES) + SET(AV1_LIBRARY optimized ${AV1_LIBRARY_DIR}/Release/libaom.so debug ${AV1_LIBRARY_DIR}/Debug/libaom.so CACHE STRING "AV1 library" FORCE) + ELSE() + SET(AV1_LIBRARY ${AV1_LIBRARY_DIR}/libaom.so CACHE STRING "AV1 library" FORCE) + ENDIF() + ELSE() + IF (CMAKE_CONFIGURATION_TYPES) + SET(AV1_LIBRARY optimized ${AV1_LIBRARY_DIR}/Release/libaom.a debug ${AV1_LIBRARY_DIR}/Debug/libaom.a CACHE STRING "AV1 library" FORCE) + ELSE() + SET(AV1_LIBRARY ${AV1_LIBRARY_DIR}/libaom.a CACHE STRING "AV1 library" FORCE) + ENDIF() + ENDIF() + ENDIF() + SET (AV1_INCLUDE_DIR "${CMAKE_BINARY_DIR}/Deps/AV1/aom" CACHE PATH "AV1 source directory" FORCE) + SET (AV1_LIBRARY_DIR "${CMAKE_BINARY_DIR}/Deps/AV1-bin" CACHE PATH "AV1 library directory" FORCE) + ExternalProject_Add(AV1 + PREFIX "${CMAKE_BINARY_DIR}/Deps/AV1-prefix" + SOURCE_DIR "${CMAKE_BINARY_DIR}/Deps/AV1" + BINARY_DIR "${AV1_LIBRARY_DIR}" + #--Download step-------------- + GIT_REPOSITORY "${GIT_REPOSITORY}" + GIT_TAG ${GIT_TAG} + #--Configure step------------- + CMAKE_ARGS + ${PLATFORM_SPECIFIC_ARGS} + -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/Deps/AV1-install + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY:STRING=${AV1_LIBRARY_DIR} + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:STRING=${AV1_LIBRARY_DIR} + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${AV1_LIBRARY_DIR} + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DBUILD_SHARED_LIBS:BOOL=${OpenIGTLink_BUILD_SHARED_LIBS} + -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} + -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} + -DAOM_TARGET_CPU:STRING=generic + -DENABLE_EXAMPLES:BOOL=OFF + -DCONFIG_UNIT_TESTS=0 + #--Build step----------------- + BUILD_ALWAYS 1 + INSTALL_COMMAND "" + ) +ENDIF() \ No newline at end of file diff --git a/openigtlink/repo/SuperBuild/External_VP9.cmake b/openigtlink/repo/SuperBuild/External_VP9.cmake new file mode 100644 index 0000000..72c5566 --- /dev/null +++ b/openigtlink/repo/SuperBuild/External_VP9.cmake @@ -0,0 +1,74 @@ +cmake_minimum_required(VERSION 2.8.2) + +include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) +include(${OpenIGTLink_SOURCE_DIR}/SuperBuild/FindVP9.cmake) + +SET(VP9_DEPENDENCIES) + +IF(VP9_FOUND) + IF(${OpenIGTLink_PROTOCOL_VERSION} LESS 3) + MESSAGE(FATAL_ERROR "Video streaming requires a build of OpenIGTLink with v3 support enabled. Please set the OpenIGTLink_PROTOCOL_VERSION_3 to true.") + ENDIF() +ELSE() + # OpenIGTLink has not been built yet, so download and build it as an external project + MESSAGE(STATUS "Downloading VP9 from https://github.com/webmproject/libvpx.git") + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + INCLUDE(${OpenIGTLink_SOURCE_DIR}/SuperBuild/External_yasm.cmake) + IF(NOT YASM_FOUND) + LIST(APPEND VP9_DEPENDENCIES YASM) + message("VP9 dependencies modified." VP9_DEPENDENCIES) + ENDIF() + SET (VP9_INCLUDE_DIR "${CMAKE_BINARY_DIR}/Deps/VP9/vpx" CACHE PATH "VP9 source directory" FORCE) + SET (VP9_LIBRARY_DIR "${CMAKE_BINARY_DIR}/Deps/VP9" CACHE PATH "VP9 library directory" FORCE) + ExternalProject_Add(VP9 + PREFIX "${CMAKE_BINARY_DIR}/Deps/VP9-prefix" + GIT_REPOSITORY https://github.com/webmproject/libvpx/ + GIT_TAG v1.6.1 + SOURCE_DIR "${CMAKE_BINARY_DIR}/Deps/VP9" + CONFIGURE_COMMAND "${CMAKE_BINARY_DIR}/Deps/VP9/configure" --disable-examples --as=yasm --enable-pic --disable-tools --disable-docs --disable-vp8 --disable-libyuv --disable-unit_tests --disable-postproc WORKING_DIRECTORY "${VP9_LIBRARY_DIR}" + BUILD_ALWAYS 1 + BUILD_COMMAND PATH=${YASM_BINARY_DIR}:$ENV{PATH}; make + BUILD_IN_SOURCE 1 + INSTALL_COMMAND "" + TEST_COMMAND "" + DEPENDS ${VP9_DEPENDENCIES} + ) + else() + if( ("${CMAKE_GENERATOR}" MATCHES "Visual Studio 14 2015") OR ("${CMAKE_GENERATOR}" MATCHES "Visual Studio 15 2017" ) OR + ("${CMAKE_GENERATOR}" MATCHES "Visual Studio 12 2013") OR ("${CMAKE_GENERATOR}" MATCHES "Visual Studio 16 2019" ) + ) + SET (VP9_INCLUDE_DIR "${CMAKE_BINARY_DIR}/Deps/VP9-Binary/include/vpx" CACHE PATH "VP9 source directory" FORCE) + SET (BinaryURL "") + if (${CMAKE_VS_PLATFORM_NAME} MATCHES "(Win64|x64|IA64)") + SET (VP9_LIBRARY_DIR "${CMAKE_BINARY_DIR}/Deps/VP9-Binary/lib/x64" CACHE PATH "VP9 library directory" FORCE) + else() + SET (VP9_LIBRARY_DIR "${CMAKE_BINARY_DIR}/Deps/VP9-Binary/lib/x86" CACHE PATH "VP9 library directory" FORCE) + endif() + if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio 12 2013") + SET (BinaryURL "https://github.com/ShiftMediaProject/libvpx/releases/download/v1.8.1-1/libvpx_v1.8.1-1_msvc12.zip") + elseif("${CMAKE_GENERATOR}" MATCHES "Visual Studio 14 2015" ) + SET (BinaryURL "https://github.com/ShiftMediaProject/libvpx/releases/download/v1.8.1-1/libvpx_v1.8.1-1_msvc14.zip") + elseif("${CMAKE_GENERATOR}" MATCHES "Visual Studio 15 2017" ) + SET (BinaryURL "https://github.com/ShiftMediaProject/libvpx/releases/download/v1.8.1-1/libvpx_v1.8.1-1_msvc15.zip") + elseif("${CMAKE_GENERATOR}" MATCHES "Visual Studio 16 2019" ) + SET (BinaryURL "https://github.com/ShiftMediaProject/libvpx/releases/download/v1.8.1-1/libvpx_v1.8.1-1_msvc16.zip") + + endif() + ExternalProject_Add(VP9 + URL ${BinaryURL} + SOURCE_DIR "${CMAKE_BINARY_DIR}/Deps/VP9-Binary" + CONFIGURE_COMMAND "" + BUILD_ALWAYS 0 + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) + else() + SET(OpenIGTLink_USE_VP9 OFF CACHE BOOL "" FORCE) + IF (OpenIGTLink_USE_H264 OR OpenIGTLink_USE_VP9 OR OpenIGTLink_USE_X265 OR OpenIGTLink_USE_OpenHEVC OR OpenIGTLink_USE_AV1) + SET(OpenIGTLink_ENABLE_VIDEOSTREAMING OFF) + ENDIF() + message(WARNING "Only support for Visual Studio 14 2015") + endif() + endif() +ENDIF() diff --git a/openigtlink/repo/SuperBuild/External_openHEVC.cmake b/openigtlink/repo/SuperBuild/External_openHEVC.cmake new file mode 100644 index 0000000..ae90505 --- /dev/null +++ b/openigtlink/repo/SuperBuild/External_openHEVC.cmake @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 2.8.2) +include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) +include(${OpenIGTLink_SOURCE_DIR}/SuperBuild/FindOpenHEVC.cmake) +INCLUDE(${OpenIGTLink_SOURCE_DIR}/SuperBuild/External_yasm.cmake) +SET(OpenHEVC_DEPENDENCIES) +IF(NOT YASM_FOUND) + LIST(APPEND OpenHEVC_DEPENDENCIES YASM) +ENDIF() +IF(OpenHEVC_FOUND) + # OpenHEVC has been built already + MESSAGE(STATUS "Using OpenHEVC available at: ${OpenHEVC_INCLUDE_DIR}") +ELSE() + # OpenHEVC has not been built yet, so download and build it as an external project + SET(GIT_REPOSITORY "https://github.com/openigtlink/openHEVC.git") + SET(GIT_TAG "master") + + IF(MSVC) + LIST(APPEND PLATFORM_SPECIFIC_ARGS -DCMAKE_CXX_MP_FLAG:BOOL=ON) + ENDIF() + + MESSAGE(STATUS "Downloading OpenHEVC ${GIT_TAG} from: ${GIT_REPOSITORY}") + + SET (OpenHEVC_INCLUDE_DIR "${CMAKE_BINARY_DIR}/Deps/OpenHEVC/gpac/modules/openhevc_dec" CACHE PATH "OpenHEVC source directory" FORCE) + SET (OpenHEVC_LIBRARY_DIR "${CMAKE_BINARY_DIR}/Deps/OpenHEVC-bin") + IF(WIN32) # for Windows + SET(OpenHEVC_LIBRARY optimized ${OpenHEVC_LIBRARY_DIR}\\Release\\LibOpenHevcWrapper.lib debug ${OpenHEVC_LIBRARY_DIR}\\Debug\\LibOpenHevcWrapper.lib CACHE STRING "OpenHEVC library" FORCE) + ELSE() + IF (CMAKE_CONFIGURATION_TYPES) + SET(OpenHEVC_LIBRARY optimized ${OpenHEVC_LIBRARY_DIR}/Release/libLibOpenHevcWrapper.a debug ${OpenHEVC_LIBRARY_DIR}/Debug/libLibOpenHevcWrapper.a CACHE STRING "OpenHEVC library" FORCE) + ELSE() + SET(OpenHEVC_LIBRARY ${OpenHEVC_LIBRARY_DIR}/libLibOpenHevcWrapper.a) + ENDIF() + ENDIF() + ExternalProject_Add( OpenHEVC + PREFIX "${CMAKE_BINARY_DIR}/Deps/OpenHEVC-prefix" + SOURCE_DIR "${CMAKE_BINARY_DIR}/Deps/OpenHEVC" + BINARY_DIR "${OpenHEVC_LIBRARY_DIR}" + #--Download step-------------- + GIT_REPOSITORY "${GIT_REPOSITORY}" + GIT_TAG ${GIT_TAG} + #--Configure step------------- + CMAKE_ARGS + ${PLATFORM_SPECIFIC_ARGS} + -DCMAKE_INSTALL_PREFIX:PATH="${CMAKE_BINARY_DIR}/Deps/OpenHEVC-install" + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY:STRING=${OpenHEVC_LIBRARY_DIR} + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:STRING=${OpenHEVC_LIBRARY_DIR} + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${OpenHEVC_LIBRARY_DIR} + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DBUILD_SHARED_LIBS:BOOL=${OpenIGTLink_BUILD_SHARED_LIBS} + -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} + -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} + #--Build step----------------- + BUILD_ALWAYS 1 + INSTALL_COMMAND "" + DEPENDS ${OpenHEVC_DEPENDENCIES} + ) +ENDIF() \ No newline at end of file diff --git a/openigtlink/repo/SuperBuild/External_openh264.cmake b/openigtlink/repo/SuperBuild/External_openh264.cmake new file mode 100644 index 0000000..787577f --- /dev/null +++ b/openigtlink/repo/SuperBuild/External_openh264.cmake @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 2.8.2) +include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) +include(${OpenIGTLink_SOURCE_DIR}/SuperBuild/FindOpenH264.cmake) +IF(OpenH264_FOUND) + # H264 has been built already + IF(${OpenIGTLink_PROTOCOL_VERSION} LESS 3) + MESSAGE(FATAL_ERROR "Video streaming requires a build of OpenIGTLink with v3 support enabled. Please set the OpenIGTLink_PROTOCOL_VERSION_3 to true.") + ENDIF() +ELSE() + # OpenIGTLink has not been built yet, so download and build it as an external project + MESSAGE(STATUS "Downloading openh264 from https://github.com/cisco/openh264.git.") + SET (OpenH264_INCLUDE_DIR "${CMAKE_BINARY_DIR}/Deps/openh264/codec/api/wels" CACHE PATH "H264 source directory" FORCE) + SET (OpenH264_LIBRARY_DIR "${CMAKE_BINARY_DIR}/Deps/openh264" CACHE PATH "H264 source directory" FORCE) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + ExternalProject_Add(OpenH264 + PREFIX "${CMAKE_BINARY_DIR}/Deps/openh264-prefix" + SOURCE_DIR "${CMAKE_BINARY_DIR}/Deps/openh264" + GIT_REPOSITORY https://github.com/cisco/openh264.git + GIT_TAG master + CONFIGURE_COMMAND "" + BUILD_ALWAYS 1 + BUILD_COMMAND make + BUILD_IN_SOURCE 1 + INSTALL_COMMAND "" + TEST_COMMAND "" + ) + else() + # ToDo: if it is a window os platform, make the build successful + ExternalProject_Add(OpenH264 + PREFIX "${CMAKE_BINARY_DIR}/Deps/openh264-prefix" + SOURCE_DIR "${CMAKE_BINARY_DIR}/Deps/openh264" + GIT_REPOSITORY https://github.com/cisco/openh264.git + GIT_TAG master + CONFIGURE_COMMAND "" + BUILD_ALWAYS 1 + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) + endif() +ENDIF() diff --git a/openigtlink/repo/SuperBuild/External_x265.cmake b/openigtlink/repo/SuperBuild/External_x265.cmake new file mode 100644 index 0000000..b24ee7d --- /dev/null +++ b/openigtlink/repo/SuperBuild/External_x265.cmake @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.7.2) +include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) +include(${OpenIGTLink_SOURCE_DIR}/SuperBuild/FindX265.cmake) + +IF(X265_FOUND) + MESSAGE(STATUS "Using X265 available at: ${X265_INCLUDE_DIR}") +ELSE() + INCLUDE(${OpenIGTLink_SOURCE_DIR}/SuperBuild/External_yasm.cmake) + SET(X265_DEPENDENCIES) + IF(NOT YASM_FOUND) + LIST(APPEND X265_DEPENDENCIES YASM) + ENDIF() + # x265 has not been built yet, so download and build it as an external project + SET(GIT_REPOSITORY "https://github.com/videolan/x265.git") + SET(GIT_TAG "2.5") + + IF(MSVC) + LIST(APPEND PLATFORM_SPECIFIC_ARGS -DCMAKE_CXX_MP_FLAG:BOOL=ON) + ENDIF() + + SET(Generator ${CMAKE_GENERATOR}) + IF("${CMAKE_GENERATOR}" STREQUAL "Xcode") + MESSAGE(FATAL_ERROR "Xcode build tend to fail for x265, use unix makefiles instead. And link the source and library directory manually in the cmake advance settings. see the link for details: https://bitbucket.org/multicoreware/x265/issues/303/build-x265-version20-on-xcode") + #SET(Generator "Unix Makefiles") # xcode generator tend to fail, use unix makefiles instead, https://bitbucket.org/multicoreware/x265/issues/303/build-x265-version20-on-xcode + ELSE() + MESSAGE(STATUS "Downloading x265 ${GIT_TAG} from: ${GIT_REPOSITORY}") + SET (X265_INCLUDE_DIR "${CMAKE_BINARY_DIR}/Deps/x265/source" CACHE PATH "x265 source directory" FORCE) + SET (X265_LIBRARY_DIR "${CMAKE_BINARY_DIR}/Deps/x265-bin" CACHE PATH "x265 library directory" FORCE) + ExternalProject_Add(X265 + PREFIX "${CMAKE_BINARY_DIR}/Deps/x265-prefix" + SOURCE_DIR "${CMAKE_BINARY_DIR}/Deps/x265" + SOURCE_SUBDIR source # SOURCE_SUBDIR is only available for cmake version later than 3.7.2 + BINARY_DIR "${X265_LIBRARY_DIR}" + #--Download step-------------- + GIT_REPOSITORY "${GIT_REPOSITORY}" + GIT_TAG ${GIT_TAG} + #--Configure step------------- + CMAKE_ARGS # cd ${X265_LIBRARY_DIR} && ${CMAKE_COMMAND} + ${PLATFORM_SPECIFIC_ARGS} + -DCMAKE_GENERATOR:STRING=${Generator} + -DCMAKE_INSTALL_PREFIX:PATH="${CMAKE_BINARY_DIR}/Deps/x265-install" + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY:STRING=${X265_LIBRARY_DIR} + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:STRING=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${X265_LIBRARY_DIR} + -DBUILD_SHARED_LIBS:BOOL=${OpenIGTLink_BUILD_SHARED_LIBS} + -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} + -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} + -DEXPORT_C_API:BOOL=ON + -DENABLE_CLI:BOOL=OFF #${X265_INCLUDE_DIR}/source + #--Build step----------------- + BUILD_ALWAYS 1 + INSTALL_COMMAND "" + DEPENDS ${X265_DEPENDENCIES} + ) + ENDIF() +ENDIF() \ No newline at end of file diff --git a/openigtlink/repo/SuperBuild/External_yasm.cmake b/openigtlink/repo/SuperBuild/External_yasm.cmake new file mode 100644 index 0000000..d1f8dee --- /dev/null +++ b/openigtlink/repo/SuperBuild/External_yasm.cmake @@ -0,0 +1,53 @@ +cmake_minimum_required(VERSION 2.8.2) +include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) +include(${OpenIGTLink_SOURCE_DIR}/SuperBuild/FindYASM.cmake) +include(${CMAKE_ROOT}/Modules/FindPythonInterp.cmake) + +IF(YASM_FOUND) + # YASM has been built already + MESSAGE(STATUS "Using YASM available at: ${YASM_BINARY_DIR}") +ELSE() + SET(YASM_PYTHON_EXECUTABLE "" CACHE STRING "Python Interpreter") + if("${YASM_PYTHON_EXECUTABLE}" STREQUAL "") + find_package(PythonInterp "2.7" REQUIRED) + SET(YASM_PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}) + endif() + # yas has not been built yet, so download and build it as an external project + SET(GIT_REPOSITORY "https://github.com/yasm/yasm.git") + SET(GIT_TAG "master") + IF(MSVC) + LIST(APPEND PLATFORM_SPECIFIC_ARGS -DCMAKE_CXX_MP_FLAG:BOOL=ON) + ENDIF() + + MESSAGE(STATUS "Downloading yasm ${GIT_TAG} from: ${GIT_REPOSITORY}") + + SET (YASM_SOURCE_DIR "${CMAKE_BINARY_DIR}/Deps/yasm" CACHE PATH "YASM source directory" FORCE) + SET (YASM_BINARY_DIR "${CMAKE_BINARY_DIR}/Deps/yasm-bin" CACHE PATH "YASM library directory" FORCE) + IF(TARGET YASM) + return() + ENDIF() + ExternalProject_Add( YASM + PREFIX "${CMAKE_BINARY_DIR}/Deps/yasm-prefix" + SOURCE_DIR "${YASM_SOURCE_DIR}" + BINARY_DIR "${YASM_BINARY_DIR}" + #--Download step-------------- + GIT_REPOSITORY "${GIT_REPOSITORY}" + GIT_TAG ${GIT_TAG} + #--Configure step------------- + CMAKE_ARGS + ${PLATFORM_SPECIFIC_ARGS} + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY:STRING=${YASM_BINARY_DIR} + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:STRING=${YASM_BINARY_DIR} + -DYASM_INSTALL_BIN_DIR:STRING="bin" + -DPYTHON_EXECUTABLE:STRING=${YASM_PYTHON_EXECUTABLE} + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${YASM_BINARY_DIR} + -DBUILD_SHARED_LIBS:BOOL=${OpenIGTLink_BUILD_SHARED_LIBS} + -DBUILD_TESTING:BOOL=OFF + -DBUILD_EXAMPLES:BOOL=OFF + -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} + -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} + #--Build step----------------- + BUILD_ALWAYS 1 + INSTALL_COMMAND "" + ) +ENDIF() \ No newline at end of file diff --git a/openigtlink/repo/SuperBuild/FindAV1.cmake b/openigtlink/repo/SuperBuild/FindAV1.cmake new file mode 100644 index 0000000..d21ea91 --- /dev/null +++ b/openigtlink/repo/SuperBuild/FindAV1.cmake @@ -0,0 +1,49 @@ +# - The AV1 library +# Once done this will define +# +# Open - A list of search hints +# +# AV1_FOUND - found AV1 +# AV1_INCLUDE_DIR - the AV1 include directory +# AV1_LIBRARY - AV1 library + +SET( AV1_PATH_HINTS + ${AV1_ROOT} + ${AV1_INCLUDE_DIR} + ${AV1_LIBRARY_DIR} + ) + +unset(AV1_INCLUDE_DIR CACHE) +find_path(AV1_INCLUDE_DIR NAMES aom.h aom_encoder.h aom_decoder.h + PATH_SUFFIXES aom + HINTS ${AV1_PATH_HINTS} + ) +unset(AV1_LIBRARY CACHE) +IF(WIN32) + IF(OpenIGTLink_BUILD_SHARED_LIBS) + message(FATAL_ERROR "Windows DLL builds not supported yet") + ENDIF() + find_library(AV1_LIBRARY + NAMES aom.lib + PATH_SUFFIXES ${CMAKE_BUILD_TYPE} + HINTS ${AV1_PATH_HINTS} + ) +ELSE() + IF(OpenIGTLink_BUILD_SHARED_LIBS) + find_library(AV1_LIBRARY + NAMES libaom.so + PATH_SUFFIXES ${CMAKE_BUILD_TYPE} + HINTS ${AV1_PATH_HINTS} + ) + ELSE() + find_library(AV1_LIBRARY + NAMES libaom.a + PATH_SUFFIXES ${CMAKE_BUILD_TYPE} + HINTS ${AV1_PATH_HINTS} + ) + ENDIF() +ENDIF() +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(AV1 REQUIRED_VARS AV1_LIBRARY AV1_INCLUDE_DIR) + +mark_as_advanced(AV1_INCLUDE_DIR AV1_LIBRARY) diff --git a/openigtlink/repo/SuperBuild/FindOpenH264.cmake b/openigtlink/repo/SuperBuild/FindOpenH264.cmake new file mode 100644 index 0000000..30a8599 --- /dev/null +++ b/openigtlink/repo/SuperBuild/FindOpenH264.cmake @@ -0,0 +1,41 @@ +# - The OpenH264 library +# Once done this will define +# +# OpenH264_ROOT - A list of search hints +# +# OpenH264_FOUND - found OpenH264 +# OpenH264_INCLUDE_DIR - the OpenH264 include directory +# OpenH264_LIBRARY_DIR - the OpenH264 library directory +# A more complete find module cmake file could be found at: +# https://github.com/BelledonneCommunications/linphone-cmake-builder/blob/master/builders/openh264.cmake + +# Dependencies +#libfind_package(OpenH264 NASM) + +if (UNIX AND NOT ANDROID) + find_package(PkgConfig QUIET) + pkg_check_modules(PC_OpenH264 QUIET openh264) +endif (UNIX AND NOT ANDROID) + +SET( OpenH264_PATH_HINTS + ${OpenH264_ROOT} + ${OpenH264_INCLUDE_DIR} + ${OpenH264_LIBRARY_DIR} + ) + +unset(OpenH264_INCLUDE_DIR CACHE) +find_path(OpenH264_INCLUDE_DIR NAMES codec_api.h codec_app_def.h codec_def.h + PATH_SUFFIXES include/wels codec/api/svc + HINTS ${OpenH264_PATH_HINTS} + ) +unset(OpenH264_LIBRARY_DIR CACHE) +find_path(OpenH264_LIBRARY_DIR NAMES openh264${CMAKE_STATIC_LIBRARY_SUFFIX} libopenh264.a + PATH_SUFFIXES lib + HINTS ${OpenH264_PATH_HINTS} + ) + + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenH264 DEFAULT_MSG OpenH264_INCLUDE_DIR OpenH264_LIBRARY_DIR) + +mark_as_advanced(OpenH264_INCLUDE_DIR OpenH264_LIBRARY_DIR) diff --git a/openigtlink/repo/SuperBuild/FindOpenHEVC.cmake b/openigtlink/repo/SuperBuild/FindOpenHEVC.cmake new file mode 100644 index 0000000..8fd8822 --- /dev/null +++ b/openigtlink/repo/SuperBuild/FindOpenHEVC.cmake @@ -0,0 +1,37 @@ +# - The OPENHEVC library +# Once done this will define +# +# Open - A list of search hints +# +# OpenHEVC_FOUND - found OpenHEVC +# OpenHEVC_INCLUDE_DIR - the OpenHEVC include directory +# OpenHEVC_LIBRARY - OpenHEVC library + +SET( OpenHEVC_PATH_HINTS + ${OpenHEVC_ROOT} + ${OpenHEVC_INCLUDE_DIR} + ) + +unset(OpenHEVC_INCLUDE_DIR CACHE) +find_path(OpenHEVC_INCLUDE_DIR NAMES openHevcWrapper.h + PATH_SUFFIXES gpac/modules/openhevc_dec + HINTS ${OpenHEVC_PATH_HINTS} + ) +unset(OpenHEVC_LIBRARY CACHE) +IF(WIN32) + find_library(OpenHEVC_LIBRARY + NAMES LibOpenHevcWrapper${CMAKE_STATIC_LIBRARY_SUFFIX} + PATH_SUFFIXES ${CMAKE_BUILD_TYPE} + HINTS ${OpenHEVC_PATH_HINTS} + ) +ELSE() + find_library(OpenHEVC_LIBRARY + NAMES libLibOpenHevcWrapper.a + PATH_SUFFIXES ${CMAKE_BUILD_TYPE} + HINTS ${OpenHEVC_PATH_HINTS} + ) +ENDIF() +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenHEVC REQUIRED_VARS OpenHEVC_LIBRARY OpenHEVC_INCLUDE_DIR) + +mark_as_advanced(OpenHEVC_INCLUDE_DIR OpenHEVC_LIBRARY) diff --git a/openigtlink/repo/SuperBuild/FindVP9.cmake b/openigtlink/repo/SuperBuild/FindVP9.cmake new file mode 100644 index 0000000..1e5da45 --- /dev/null +++ b/openigtlink/repo/SuperBuild/FindVP9.cmake @@ -0,0 +1,62 @@ +# - The VP9 library +# Once done this will define +# +# VP9_ROOT - A list of search hints +# +# VP9_FOUND - found VP9 +# VP9_INCLUDE_DIR - the VP9 include directory +# VP9_LIBRARY_DIR - VP9 library directory +if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + SET( VP9_PATH_HINTS + ${VP9_ROOT} + ${VP9_INCLUDE_DIR} + ${VP9_LIBRARY_DIR} + ) + unset(VP9_INCLUDE_DIR CACHE) + find_path(VP9_INCLUDE_DIR NAMES vp8cx.h vpx_image.h + PATH_SUFFIXES vpx + HINTS ${VP9_PATH_HINTS} + ) + + unset(VP9_LIBRARY_DIR CACHE) + find_path(VP9_LIBRARY_DIR + NAMES libvpx.a + PATH_SUFFIXES ${Platform}/${CMAKE_BUILD_TYPE} + HINTS ${VP9_PATH_HINTS} + ) +else() + SET(VP9_PATH_HINTS + ${VP9_ROOT} + ${VP9_INCLUDE_DIR} + ) + find_path(VP9_INCLUDE_DIRECT_DIR NAMES vp8cx.h vpx_image.h + PATH_SUFFIXES vpx + HINTS ${VP9_PATH_HINTS} + ) + SET(VP9_PATH_HINTS + ${VP9_ROOT} + ) + + list(APPEND VP9_PATH_HINTS ${VP9_LIBRARY_DIR}/lib) + + find_path(VP9_LIBRARY_DIRECT_DIR libvpx.lib + HINTS ${VP9_PATH_HINTS} + ) + if(VP9_LIBRARY_DIRECT_DIR AND VP9_INCLUDE_DIRECT_DIR) + #VP9 library and header files are all found + SET(VP9_INCLUDE_DIR "${VP9_INCLUDE_DIRECT_DIR}" CACHE PATH "" FORCE) + unset(VP9_LIBRARY_DIRECT_DIR CACHE) + unset(VP9_INCLUDE_DIRECT_DIR CACHE) + else() + unset(VP9_INCLUDE_DIRECT_DIR CACHE) + unset(VP9_LIBRARY_DIRECT_DIR CACHE) # don't expose the VP9_LIBRARY_DIRECT_DIR to user, force the user to set the variable VP9_LIBRARY_DIR + MESSAGE(WARNING "VP9 library file not found, specify the path where the vp9 project was build, if vp9 was built in source, then set the library path the same as include path") + SET(VP9_LIBRARY_DIR "" CACHE PATH "" FORCE) + SET(VP9_INCLUDE_DIR "" CACHE PATH "" FORCE) + endif() +endif() + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(VP9 REQUIRED_VARS VP9_LIBRARY_DIR VP9_INCLUDE_DIR) +mark_as_advanced(VP9_INCLUDE_DIR VP9_LIBRARY_DIR) + \ No newline at end of file diff --git a/openigtlink/repo/SuperBuild/FindX265.cmake b/openigtlink/repo/SuperBuild/FindX265.cmake new file mode 100644 index 0000000..2c9588b --- /dev/null +++ b/openigtlink/repo/SuperBuild/FindX265.cmake @@ -0,0 +1,39 @@ +# - The X265 library +# Once done this will define +# +# X265_ROOT - A list of search hints +# +# X265_FOUND - found X265 +# X265_INCLUDE_DIR - the X265 include directory +# X265_LIBRARY_DIR - X265 library directory + +#if (UNIX AND NOT ANDROID) +# find_package(PkgConfig QUIET) +# pkg_check_modules(PC_X265 QUIET X265) +#endif() + +SET( X265_PATH_HINTS + ${X265_ROOT} + ${X265_INCLUDE_DIR} + ) +unset(X265_INCLUDE_DIR CACHE) +find_path(X265_INCLUDE_DIR NAMES x265.h + HINTS ${X265_PATH_HINTS} + PATH_SUFFIXES source + ) +set(X265_LIBRARY_DIR "" CACHE PATH "") +SET( X265_PATH_HINTS + ${X265_ROOT} + ${X265_LIBRARY_DIR} + ) +find_path(X265_LIBRARY_DIRECT_DIR x265-static${CMAKE_STATIC_LIBRARY_SUFFIX} | libx265.a + HINTS ${X265_PATH_HINTS} + ) +if(NOT X265_LIBRARY_DIRECT_DIR) + unset(X265_LIBRARY_DIRECT_DIR CACHE) # don't expose the X265_LIBRARY_DIRECT_DIR to user, force the user to set the variable X265_LIBRARY_DIR +endif() + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(X265 REQUIRED_VARS X265_LIBRARY_DIR X265_INCLUDE_DIR) + +#mark_as_advanced(X265_INCLUDE_DIR X265_LIBRARY_DIR) diff --git a/openigtlink/repo/SuperBuild/FindYASM.cmake b/openigtlink/repo/SuperBuild/FindYASM.cmake new file mode 100644 index 0000000..70ad52f --- /dev/null +++ b/openigtlink/repo/SuperBuild/FindYASM.cmake @@ -0,0 +1,29 @@ +# - The YASM library +# Once done this will define +# +# YASM_ROOT - A list of search hints +# +# YASM_FOUND - found YASM +# YASM_BINARY_DIR - YASM library directory + +#if (UNIX AND NOT ANDROID) +# find_package(PkgConfig QUIET) +# pkg_check_modules(PC_YASM QUIET YASM) +#endif() + +SET( YASM_PATH_HINTS + ${YASM_ROOT} + ${CMAKE_BINARY_DIR}/Deps/yasm + ${CMAKE_BINARY_DIR}/Deps/yasm-bin + ) + +unset(YASM_BINARY_DIR CACHE) +find_path(YASM_BINARY_DIR + NAMES yasm + HINTS ${YASM_PATH_HINTS} + PATH_SUFFIXES Debug Release + ) +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(YASM REQUIRED_VARS YASM_BINARY_DIR) + +mark_as_advanced(YASM_BINARY_DIR) diff --git a/openigtlink/repo/SuperBuild/Superbuild.cmake b/openigtlink/repo/SuperBuild/Superbuild.cmake new file mode 100644 index 0000000..6ae9a17 --- /dev/null +++ b/openigtlink/repo/SuperBuild/Superbuild.cmake @@ -0,0 +1,89 @@ +#--------------------------------------------------- +SET(OpenIGTLink_DEPENDENCIES) + +#--------------------------------------------------- +# VideoStreaming dependencies +IF(OpenIGTLink_USE_H264) + INCLUDE(${CMAKE_CURRENT_LIST_DIR}/External_openh264.cmake) + IF(NOT OpenH264_FOUND) + LIST(APPEND OpenIGTLink_DEPENDENCIES OpenH264) + ENDIF() +ENDIF() + +IF(OpenIGTLink_USE_VP9) + INCLUDE(${CMAKE_CURRENT_LIST_DIR}/External_VP9.cmake) + IF(NOT VP9_FOUND) + LIST(APPEND OpenIGTLink_DEPENDENCIES VP9) + ENDIF() +ENDIF() + +IF(OpenIGTLink_USE_X265) + INCLUDE(${CMAKE_CURRENT_LIST_DIR}/External_X265.cmake) + IF(NOT X265_FOUND) + LIST(APPEND OpenIGTLink_DEPENDENCIES X265) + ENDIF() +ENDIF() + +IF(OpenIGTLink_USE_OpenHEVC) + INCLUDE(${CMAKE_CURRENT_LIST_DIR}/External_openHEVC.cmake) + IF(NOT OpenHEVC_FOUND) + LIST(APPEND OpenIGTLink_DEPENDENCIES OpenHEVC) + ENDIF() +ENDIF() + +IF(OpenIGTLink_USE_AV1) + INCLUDE(${CMAKE_CURRENT_LIST_DIR}/External_AV1.cmake) + IF(NOT AV1_FOUND) + LIST(APPEND OpenIGTLink_DEPENDENCIES AV1) + ENDIF() +ENDIF() + +IF(OpenIGTLink_USE_WEBSOCKET) + INCLUDE(${CMAKE_CURRENT_LIST_DIR}/External_WebSocket.cmake) + LIST(APPEND OpenIGTLink_DEPENDENCIES websocket) +ENDIF() + +ExternalProject_Add( OpenIGTLink-lib + PREFIX "${CMAKE_BINARY_DIR}/OpenIGTLink-prefix" + SOURCE_DIR "${CMAKE_BINARY_DIR}/OpenIGTLink" + BINARY_DIR "${CMAKE_BINARY_DIR}/OpenIGTLink-bin" + #--Download step-------------- + GIT_REPOSITORY "https://github.com/openigtlink/OpenIGTLink.git" + GIT_TAG master + #--Configure step------------- + CMAKE_ARGS + ${PLATFORM_SPECIFIC_ARGS} + -DOpenIGTLink_SUPERBUILD:BOOL=OFF + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY:STRING=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:STRING=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + -DBUILD_SHARED_LIBS:BOOL=${OpenIGTLink_BUILD_SHARED_LIBS} + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DOpenIGTLink_BUILD_TESTING:BOOL=${OpenIGTLink_BUILD_TESTING} + -DOpenIGTLink_USE_GTEST:BOOL=${OpenIGTLink_USE_GTEST} + -DOpenIGTLink_USE_H264:BOOL=${OpenIGTLink_USE_H264} + -DOpenIGTLink_USE_VP9:BOOL=${OpenIGTLink_USE_VP9} + -DOpenIGTLink_USE_X265:BOOL=${OpenIGTLink_USE_X265} + -DOpenIGTLink_USE_OpenHEVC:BOOL=${OpenIGTLink_USE_OpenHEVC} + -DOpenIGTLink_USE_AV1:BOOL=${OpenIGTLink_USE_AV1} + -DOpenIGTLink_USE_WEBSOCKET:BOOL=${OpenIGTLink_USE_WEBSOCKET} + -DOpenIGTLink_BUILD_EXAMPLES:BOOL=${OpenIGTLink_BUILD_EXAMPLES} + -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} + -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} + -DOpenH264_INCLUDE_DIR:STRING=${OpenH264_INCLUDE_DIR} + -DOpenH264_LIBRARY_DIR:STRING=${OpenH264_LIBRARY_DIR} + -DX265_INCLUDE_DIR:STRING=${X265_INCLUDE_DIR} + -DX265_LIBRARY_DIR:STRING=${X265_LIBRARY_DIR} + -DOpenHEVC_INCLUDE_DIR:STRING=${OpenHEVC_INCLUDE_DIR} + -DOpenHEVC_LIBRARY:STRING=${OpenHEVC_LIBRARY} + -DVP9_INCLUDE_DIR:STRING=${VP9_INCLUDE_DIR} + -DVP9_LIBRARY_DIR:STRING=${VP9_LIBRARY_DIR} + -DAV1_INCLUDE_DIR:STRING=${AV1_INCLUDE_DIR} + -DAV1_LIBRARY_DIR:STRING=${AV1_LIBRARY_DIR} + -DYASM_BINARY_DIR:STRING=${YASM_BINARY_DIR} + #--Build step----------------- + BUILD_ALWAYS 1 + #--Install step----------------- + INSTALL_COMMAND "" + DEPENDS ${OpenIGTLink_DEPENDENCIES} + ) diff --git a/openigtlink/repo/Testing/CMakeLists.txt b/openigtlink/repo/Testing/CMakeLists.txt new file mode 100644 index 0000000..461b64c --- /dev/null +++ b/openigtlink/repo/Testing/CMakeLists.txt @@ -0,0 +1,207 @@ +PROJECT( OpenIGTLinkTesting ) + +cmake_minimum_required(VERSION 2.8.11) +find_package(OpenIGTLink REQUIRED) +include(${OpenIGTLink_USE_FILE}) +include_directories(${OpenIGTLink_INCLUDE_DIRS}) +link_directories(${OpenIGTLink_LIBRARY_DIRS}) +include_directories(${PROJECT_BINARY_DIR}) +configure_file(${PROJECT_SOURCE_DIR}/igtlTestConfig.h.in ${PROJECT_BINARY_DIR}/igtlTestConfig.h) +ENABLE_TESTING() +ADD_SUBDIRECTORY( igtlutil ) +IF(OpenIGTLink_USE_GTEST AND (NOT OpenIGTLink_BUILD_SHARED_LIBS)) + #----------- + #download of GoogleTest + if( MSVC ) # VS2012 doesn't support correctly the tuples yet + add_definitions("-D_VARIADIC_MAX=10") + endif() + # Download and unpack googletest at configure time + configure_file(GoogletestDownload.txt.in + googletest-download/CMakeLists.txt) + execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" . + WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/googletest-download" ) + + execute_process(COMMAND "${CMAKE_COMMAND}" --build . + WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/googletest-download" ) + + # Prevent GoogleTest from overriding our compiler/linker options + # when building with Visual Studio + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + + # Add googletest directly to our build. This adds + # the following targets: gtest, gtest_main, gmock + # and gmock_main + add_subdirectory("${PROJECT_BINARY_DIR}/gmock" + "${PROJECT_BINARY_DIR}/gmock-build" ) + + # The gtest/gmock targets carry header search path + # dependencies automatically when using CMake 2.8.11 or + # later. Otherwise we have to add them here ourselves. + include_directories("${gtest_SOURCE_DIR}/include") + include_directories("${gmock_SOURCE_DIR}/include") +ENDIF() + +ADD_EXECUTABLE(igtlMultiThreaderTest1 igtlMultiThreaderTest1.cxx) +ADD_EXECUTABLE(igtlMultiThreaderTest2 igtlMultiThreaderTest2.cxx) +ADD_EXECUTABLE(igtlMultiThreaderTest3 igtlMultiThreaderTest3.cxx) +ADD_EXECUTABLE(igtlMessageFactoryTest igtlMessageFactoryTest.cxx) +ADD_EXECUTABLE(igtlTimeStampTest1 igtlTimeStampTest1.cxx) +ADD_EXECUTABLE(igtlMessageBaseTest igtlMessageBaseTest.cxx) +ADD_EXECUTABLE(igtlConditionVariableTest igtlConditionVariableTest.cxx) + +ADD_EXECUTABLE(igtlImageMessageTest igtlImageMessageTest.cxx) +ADD_EXECUTABLE(igtlImageMessage2Test igtlImageMessage2Test.cxx) +ADD_EXECUTABLE(igtlTransformMessageTest igtlTransformMessageTest.cxx) +ADD_EXECUTABLE(igtlPositionMessageTest igtlPositionMessageTest.cxx) +ADD_EXECUTABLE(igtlStatusMessageTest igtlStatusMessageTest.cxx) +ADD_EXECUTABLE(igtlCapabilityMessageTest igtlCapabilityMessageTest.cxx) + +#ADD_EXECUTABLE(igtlSocketTest igtlSocketTest.cxx) +#ADD_EXECUTABLE(igtlServerSocketTest igtlServerSocketTest.cxx) +#ADD_EXECUTABLE(igtlClientSocketTest igtlClientSocketTest.cxx) + +# Message Tests Added in Version 2 +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "1") + ADD_EXECUTABLE(igtlBindMessageTest igtlBindMessageTest.cxx) + ADD_EXECUTABLE(igtlColorTableMessageTest igtlColorTableMessageTest.cxx) + ADD_EXECUTABLE(igtlLabelMetaMessageTest igtlLabelMetaMessageTest.cxx) + ADD_EXECUTABLE(igtlNDArrayMessageTest igtlNDArrayMessageTest.cxx) + ADD_EXECUTABLE(igtlImageMetaMessageTest igtlImageMetaMessageTest.cxx) + ADD_EXECUTABLE(igtlPointMessageTest igtlPointMessageTest.cxx) + ADD_EXECUTABLE(igtlPolyDataMessageTest igtlPolyDataMessageTest.cxx) + ADD_EXECUTABLE(igtlSensorMessageTest igtlSensorMessageTest.cxx) + ADD_EXECUTABLE(igtlStringMessageTest igtlStringMessageTest.cxx) + ADD_EXECUTABLE(igtlTrackingDataMessageTest igtlTrackingDataMessageTest.cxx) + ADD_EXECUTABLE(igtlTrajectoryMessageTest igtlTrajectoryMessageTest.cxx) +ENDIF() + +# Message Tests Added in Version 3 +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "2") + ADD_EXECUTABLE(igtlCommandMessageTest igtlCommandMessageTest.cxx) + ADD_EXECUTABLE(igtlMessageRTPWrapperTest igtlMessageRTPWrapperTest.cxx) +ENDIF() + +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "2" AND (OpenIGTLink_USE_H264 OR OpenIGTLink_USE_VP9 OR (OpenIGTLink_USE_X265 AND OpenIGTLink_USE_OpenHEVC) OR OpenIGTLink_USE_AV1)) + ADD_EXECUTABLE(igtlVideoMessageTest igtlVideoMessageTest.cxx) + ADD_EXECUTABLE(igtlVideoMetaMessageTest igtlVideoMetaMessageTest.cxx) +ENDIF() + + +IF(OpenIGTLink_USE_GTEST AND (NOT OpenIGTLink_BUILD_SHARED_LIBS)) + SET(GTEST_LINK OpenIGTLink gtest_main gtest gmock_main gmock) +ELSE() + SET(GTEST_LINK OpenIGTLink) +ENDIF() + +TARGET_LINK_LIBRARIES(igtlMultiThreaderTest1 OpenIGTLink) +TARGET_LINK_LIBRARIES(igtlMultiThreaderTest2 OpenIGTLink) +TARGET_LINK_LIBRARIES(igtlMultiThreaderTest3 OpenIGTLink) +TARGET_LINK_LIBRARIES(igtlMessageFactoryTest OpenIGTLink) +TARGET_LINK_LIBRARIES(igtlTimeStampTest1 OpenIGTLink) +TARGET_LINK_LIBRARIES(igtlMessageBaseTest ${GTEST_LINK}) +TARGET_LINK_LIBRARIES(igtlConditionVariableTest ${GTEST_LINK}) + +TARGET_LINK_LIBRARIES(igtlImageMessageTest ${GTEST_LINK}) +TARGET_LINK_LIBRARIES(igtlImageMessage2Test ${GTEST_LINK}) +TARGET_LINK_LIBRARIES(igtlCapabilityMessageTest ${GTEST_LINK}) +TARGET_LINK_LIBRARIES(igtlStatusMessageTest ${GTEST_LINK}) +TARGET_LINK_LIBRARIES(igtlTransformMessageTest ${GTEST_LINK}) +TARGET_LINK_LIBRARIES(igtlPositionMessageTest ${GTEST_LINK}) + +# Message Tests Added in Version 2 +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "1") + TARGET_LINK_LIBRARIES(igtlBindMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlColorTableMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlLabelMetaMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlNDArrayMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlImageMetaMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlPointMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlPolyDataMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlSensorMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlStringMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlTrackingDataMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlTrajectoryMessageTest ${GTEST_LINK}) +ENDIF() + +# Message Tests Added in Version 3 +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "2") + TARGET_LINK_LIBRARIES(igtlCommandMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlMessageRTPWrapperTest ${GTEST_LINK}) +ENDIF() + +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "2" AND (OpenIGTLink_USE_H264 OR OpenIGTLink_USE_VP9 OR (OpenIGTLink_USE_X265 AND OpenIGTLink_USE_OpenHEVC) OR OpenIGTLink_USE_AV1)) + TARGET_LINK_LIBRARIES(igtlVideoMessageTest ${GTEST_LINK}) + TARGET_LINK_LIBRARIES(igtlVideoMetaMessageTest ${GTEST_LINK}) +ENDIF() + + +#TARGET_LINK_LIBRARIES(igtlSocketTest ${GTEST_LINK}) +#TARGET_LINK_LIBRARIES(igtlClientSocketTest ${GTEST_LINK}) +#TARGET_LINK_LIBRARIES(igtlServerSocketTest ${GTEST_LINK}) + +set(TestStringFormat1 "--gtest_filter=*.*FormatVersion1") + +ADD_TEST(igtlMultiThreaderTest1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlMultiThreaderTest1) +ADD_TEST(igtlMultiThreaderTest2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlMultiThreaderTest2) +ADD_TEST(igtlMultiThreaderTest3 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlMultiThreaderTest3) +ADD_TEST(igtlMessageFactoryTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlMessageFactoryTest) +ADD_TEST(igtlTimeStampTest1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlTimeStampTest1) +ADD_TEST(igtlMessageBaseTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlMessageBaseTest) +ADD_TEST(igtlConditionVariableTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlConditionVariableTest ${TestStringFormat1}) + +ADD_TEST(igtlImageMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlImageMessageTest) +ADD_TEST(igtlImageMessage2Test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlImageMessage2Test) +ADD_TEST(igtlCapabilityMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlCapabilityMessageTest) +ADD_TEST(igtlStatusMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlStatusMessageTest) +ADD_TEST(igtlTransformMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlTransformMessageTest ${TestStringFormat1}) +ADD_TEST(igtlPositionMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlPositionMessageTest ${TestStringFormat1}) + + +# Message Tests Added in Version 2 +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "1") + ADD_TEST(igtlBindMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlBindMessageTest ${TestStringFormat1}) + ADD_TEST(igtlColorTableMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlColorTableMessageTest ${TestStringFormat1}) + ADD_TEST(igtlLabelMetaMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlLabelMetaMessageTest ${TestStringFormat1}) + ADD_TEST(igtlNDArrayMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlNDArrayMessageTest ${TestStringFormat1}) + ADD_TEST(igtlImageMetaMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlLabelMetaMessageTest ${TestStringFormat1}) + ADD_TEST(igtlPointMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlPointMessageTest ${TestStringFormat1}) + ADD_TEST(igtlPolyDataMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlPolyDataMessageTest ${TestStringFormat1}) + ADD_TEST(igtlSensorMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlSensorMessageTest ${TestStringFormat1}) + ADD_TEST(igtlStringMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlStringMessageTest ${TestStringFormat1}) + ADD_TEST(igtlTrackingDataMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlTrackingDataMessageTest ${TestStringFormat1}) + ADD_TEST(igtlTrajectoryMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlTrajectoryMessageTest ${TestStringFormat1}) +ENDIF() + +set(TestStringFormat2 "--gtest_filter=*.*FormatVersion2") +# Message Tests Added in Version 3 +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "2") + ADD_TEST(igtlMessageBaseTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlMessageBaseTest ${TestStringFormat2}) + ADD_TEST(igtlImageMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlImageMessageTest ${TestStringFormat2}) + ADD_TEST(igtlImageMessage2TestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlImageMessage2Test ${TestStringFormat2}) + ADD_TEST(igtlBindMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlBindMessageTest ${TestStringFormat2}) + ADD_TEST(igtlCapabilityMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlCapabilityMessageTest ${TestStringFormat2}) + ADD_TEST(igtlColorTableMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlColorTableMessageTest ${TestStringFormat2}) + ADD_TEST(igtlConditionVariableTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlConditionVariableTest ${TestStringFormat2}) + ADD_TEST(igtlLabelMetaMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlLabelMetaMessageTest ${TestStringFormat2}) + ADD_TEST(igtlNDArrayMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlNDArrayMessageTest ${TestStringFormat2}) + ADD_TEST(igtlImageMetaMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlLabelMetaMessageTest ${TestStringFormat2}) + ADD_TEST(igtlPointMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlPointMessageTest ${TestStringFormat2}) + ADD_TEST(igtlPolyDataMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlPolyDataMessageTest ${TestStringFormat2}) + ADD_TEST(igtlSensorMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlSensorMessageTest ${TestStringFormat2}) + ADD_TEST(igtlStatusMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlStatusMessageTest ${TestStringFormat2}) + ADD_TEST(igtlStringMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlStringMessageTest ${TestStringFormat2}) + ADD_TEST(igtlTrackingDataMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlTrackingDataMessageTest ${TestStringFormat2}) + ADD_TEST(igtlTrajectoryMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlTrajectoryMessageTest ${TestStringFormat2}) + ADD_TEST(igtlTransformMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlTransformMessageTest ${TestStringFormat2}) + ADD_TEST(igtlPositionMessageTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlPositionMessageTest) + ## Command message is available in Protocol version 3, however, we will test both header version 1 and 2 + ADD_TEST(igtlCommandMessageTestFormatVersion1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlCommandMessageTest ${TestStringFormat1}) + ADD_TEST(igtlCommandMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlCommandMessageTest ${TestStringFormat2}) + ADD_TEST(igtlMessageRTPWrapperTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlMessageRTPWrapperTest ${TestStringFormat2}) +ENDIF() + +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "2" AND (OpenIGTLink_USE_H264 OR OpenIGTLink_USE_VP9 OR (OpenIGTLink_USE_X265 AND OpenIGTLink_USE_OpenHEVC) OR OpenIGTLink_USE_AV1)) + ADD_TEST(igtlVideoMessageTestFormatVersion1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlVideoMessageTest ${TestStringFormat1}) + ADD_TEST(igtlVideoMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlVideoMessageTest ${TestStringFormat2}) + ADD_TEST(igtlVideoMetaMessageTestFormatVersion2 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtlVideoMetaMessageTest ${TestStringFormat2}) +ENDIF() diff --git a/openigtlink/repo/Testing/GoogletestDownload.txt.in b/openigtlink/repo/Testing/GoogletestDownload.txt.in new file mode 100644 index 0000000..481152f --- /dev/null +++ b/openigtlink/repo/Testing/GoogletestDownload.txt.in @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 2.8.2) + +project(googletest-download NONE) +include(ExternalProject) +ExternalProject_Add(googletest + URL https://github.com/google/googletest/archive/release-1.7.0.zip + #GIT_REPOSITORY https://github.com/google/googletest.git + #GIT_TAG master + SOURCE_DIR "${PROJECT_BINARY_DIR}/gtest" + BINARY_DIR "${PROJECT_BINARY_DIR}/gtest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) + +ExternalProject_Add(googlemock + URL https://github.com/google/googlemock/archive/release-1.7.0.zip + SOURCE_DIR "${PROJECT_BINARY_DIR}/gmock" + BINARY_DIR "${PROJECT_BINARY_DIR}/gmock-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) diff --git a/openigtlink/repo/Testing/igtlBindMessageTest.cxx b/openigtlink/repo/Testing/igtlBindMessageTest.cxx new file mode 100644 index 0000000..40fd775 --- /dev/null +++ b/openigtlink/repo/Testing/igtlBindMessageTest.cxx @@ -0,0 +1,241 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlBindMessage.h" +#include "igtlutil/igtl_test_data_bind.h" +#include "igtlutil/igtl_test_data_image.h" +#include "igtlTransformMessage.h" +#include "igtlImageMessage.h" +#include "igtlSensorMessage.h" +#include "igtlMessageDebugFunction.h" +#include "igtlUnit.h" +#include "igtl_unit.h" +#include "igtl_header.h" +#include "igtl_image.h" +#include "igtl_transform.h" +#include "igtl_bind.h" +#include "igtlTestConfig.h" +#include "string.h" + +#define MESSAGE_BIND_HEADER_SIZE 98 +#define MESSAGE_BIND_BODY_SIZE 2678 +#define TEST_IMAGE_MESSAGE_SIZE 2500 +#define MESSAGE_SENSOR_BODY_SIZE 58 + +igtl::ImageMessage::Pointer imageSendMsg2 = igtl::ImageMessage::New(); +igtl::ImageMessage::Pointer imageReceiveMsg2 = igtl::ImageMessage::New(); +igtl::SensorMessage::Pointer sensorDataSendMsg = igtl::SensorMessage::New(); +igtl::SensorMessage::Pointer sensorDataReceiveMsg = igtl::SensorMessage::New(); +igtl::TransformMessage::Pointer transformSendMsg = igtl::TransformMessage::New(); +igtl::TransformMessage::Pointer transformReceiveMsg = igtl::TransformMessage::New(); +igtl::BindMessage::Pointer bindSendMsg = igtl::BindMessage::New(); +igtl::BindMessage::Pointer bindReceiveMsg = igtl::BindMessage::New(); +igtl::Unit::Pointer unit = igtl::Unit::New(); +igtl::GetBindMessage::Pointer getBindSendMessage = igtl::GetBindMessage::New(); +igtl::GetBindMessage::Pointer getBindReceiveMessage = igtl::GetBindMessage::New(); +igtl::StartBindMessage::Pointer startBindSendMessage = igtl::StartBindMessage::New(); +igtl::StartBindMessage::Pointer startBindReceiveMessage = igtl::StartBindMessage::New(); + + +float inT[4] = {-0.954892f, 0.196632f, -0.222525f, 0.0}; +float inS[4] = {-0.196632f, 0.142857f, 0.970014f, 0.0}; +float inN[4] = {0.222525f, 0.970014f, -0.0977491f, 0.0}; +float inOrigin[4] = {46.0531f,19.4709f,46.0531f, 1.0}; +igtl::Matrix4x4 inMatrix = {{inT[0],inS[0],inN[0],inOrigin[0]}, + {inT[1],inS[1],inN[1],inOrigin[1]}, + {inT[2],inS[2],inN[2],inOrigin[2]}, + {inT[3],inS[3],inN[3],inOrigin[3]}}; +int size[3] = {50, 50, 1}; // image dimension +float spacing[3] = {1.0f, 1.0f, 1.0f}; // spacing (mm/pixel) +int svsize[3] = {50, 50, 1}; // sub-volume size +int svoffset[3] = {0, 0, 0}; // sub-volume offset +int scalarType = igtl::ImageMessage::TYPE_UINT8;// scalar type +igtlFloat64 sensorValues[6] = {123456.78,12345.678,1234.5678,123.45678,12.345678,1.2345678}; + + +void BuildUpElements() +{ + imageSendMsg2 = igtl::ImageMessage::New(); + imageSendMsg2->SetHeaderVersion(IGTL_HEADER_VERSION_1); + imageSendMsg2->SetTimeStamp(0, 1234567892); + imageSendMsg2->SetDeviceName("ChildImage"); + //Initialization of a image message + imageSendMsg2->SetDimensions(size); + imageSendMsg2->SetSpacing(spacing); + imageSendMsg2->SetScalarType(scalarType); + imageSendMsg2->SetSubVolume(svsize, svoffset); + imageSendMsg2->SetNumComponents(1); + imageSendMsg2->SetScalarType(IGTL_IMAGE_STYPE_TYPE_UINT8); + imageSendMsg2->SetEndian(IGTL_IMAGE_ENDIAN_LITTLE); + imageSendMsg2->SetCoordinateSystem(IGTL_IMAGE_COORD_RAS); + imageSendMsg2->SetMatrix(inMatrix); + //imageSendMsg2->AllocateBuffer(IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE); + imageSendMsg2->AllocateScalars(); + memcpy(imageSendMsg2->GetPackBodyPointer(), (const void*)(test_image_message+IGTL_HEADER_SIZE), + (size_t)(IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE));//here m_Body is set. + //imageSendMsg2->SetScalarPointer((void*)test_image); + imageSendMsg2->Pack(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)imageSendMsg2->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + imageReceiveMsg2->SetMessageHeader(headerMsg); + imageReceiveMsg2->AllocatePack(); + + sensorDataSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + sensorDataSendMsg->AllocatePack(); + sensorDataSendMsg->SetLength(6); + sensorDataSendMsg->SetDeviceName("ChildSensor"); + sensorDataSendMsg->SetTimeStamp(0, 1234567892); + unit->Init(); + unit->SetPrefix(IGTL_UNIT_PREFIX_NONE); + unit->Append(IGTL_UNIT_SI_BASE_METER, (igtl_int8) 1); + unit->Append(IGTL_UNIT_SI_BASE_SECOND, (igtl_int8) -2); + unit->Pack(); + sensorDataSendMsg->SetUnit(unit); + for (int i =0; i < 6; i++) + { + sensorDataSendMsg->SetValue(i, sensorValues[i]); + } + sensorDataSendMsg->Pack(); + + sensorDataReceiveMsg->AllocatePack(); + sensorDataReceiveMsg->SetLength(6); + + transformSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + transformSendMsg->AllocatePack(); + transformSendMsg->SetTimeStamp(0, 1234567892); + transformSendMsg->SetDeviceName("ChildTrans"); + transformSendMsg->SetMatrix(inMatrix); + transformSendMsg->Pack(); + + transformReceiveMsg->AllocatePack(); + bindSendMsg->Init(); + bindSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + bindSendMsg->SetTimeStamp(0, 1234567892); + bindSendMsg->SetDeviceName("DeviceName"); + bindSendMsg->AppendChildMessage(transformSendMsg); + bindSendMsg->AppendChildMessage(imageSendMsg2); + bindSendMsg->AppendChildMessage(sensorDataSendMsg); + bindSendMsg->Pack(); +} + +TEST(BindMessageTest, Pack) +{ + BuildUpElements(); + std::cout << "1" << std::endl; + char * messageBody = (char*)bindSendMsg->GetPackBodyPointer() + MESSAGE_BIND_HEADER_SIZE; + std::cout << "2" << std::endl; + int r = memcmp((const void*)bindSendMsg->GetPackPointer(), (const void*)test_bind_message_header, + (size_t)(IGTL_HEADER_SIZE)); + std::cout << "3" << std::endl; + EXPECT_EQ(r, 0); + + std::cout << "4" << std::endl; + r = memcmp((const void*)bindSendMsg->GetPackBodyPointer(), (const void*)test_bind_message_bind_header, MESSAGE_BIND_HEADER_SIZE); + std::cout << "5" << std::endl; + EXPECT_EQ(r, 0); + std::cout << "6" << std::endl; + messageBody = (char*)bindSendMsg->GetPackBodyPointer() + MESSAGE_BIND_HEADER_SIZE; + std::cout << "7" << std::endl; + r = memcmp((const void*)(messageBody), (const void*)test_bind_message_bind_body, MESSAGE_BIND_BODY_SIZE); + std::cout << "8" << std::endl; + EXPECT_EQ(r, 0); +} + +TEST(BindMessageTest, Unpack) +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), bindSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + bindReceiveMsg->SetMessageHeader(headerMsg); + bindReceiveMsg->AllocatePack(); + memcpy(bindReceiveMsg->GetPackBodyPointer(), bindSendMsg->GetPackBodyPointer(),MESSAGE_BIND_HEADER_SIZE + MESSAGE_BIND_BODY_SIZE); + bindReceiveMsg->Unpack(1); + + bindReceiveMsg->GetChildMessage(0, transformReceiveMsg); + bindReceiveMsg->GetChildMessage(1, imageReceiveMsg2); + bindReceiveMsg->GetChildMessage(2, sensorDataReceiveMsg); + igtl_header *messageHeader = (igtl_header *)bindReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "BIND"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, MESSAGE_BIND_HEADER_SIZE + MESSAGE_BIND_BODY_SIZE); + int r = memcmp(bindReceiveMsg->GetPackBodyPointer(), test_bind_message_bind_header, MESSAGE_BIND_HEADER_SIZE); + EXPECT_EQ(r, 0); + + igtl_header *imageHeader = (igtl_header *)imageReceiveMsg2->GetPackPointer(); + EXPECT_STREQ(imageHeader->device_name, "ChildImage"); + EXPECT_STREQ(imageHeader->name, "IMAGE"); + EXPECT_EQ(imageHeader->header_version, 1); + EXPECT_EQ(imageHeader->timestamp, 1234567892); + EXPECT_EQ(imageHeader->body_size, IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE); + + + int returnSize[3] = {0,0,0}; + imageReceiveMsg2->GetDimensions(returnSize); + EXPECT_THAT(returnSize,testing::ElementsAreArray(size)); + float returnSpacing[3] = {0.0f,0.0f,0.0f}; + imageReceiveMsg2->GetSpacing(returnSpacing); + EXPECT_TRUE(ArrayFloatComparison(returnSpacing, spacing, 3, ABS_ERROR)); + int returnSvsize[3] = {0,0,0}, returnSvoffset[3] = {0,0,0}; + imageReceiveMsg2->GetSubVolume(returnSvsize, returnSvoffset); + EXPECT_THAT(returnSvsize,testing::ElementsAreArray(svsize)); + EXPECT_THAT(returnSvoffset,testing::ElementsAreArray(svoffset)); + EXPECT_EQ(imageReceiveMsg2->GetScalarType(), IGTL_IMAGE_STYPE_TYPE_UINT8); + EXPECT_EQ(imageReceiveMsg2->GetEndian(), IGTL_IMAGE_ENDIAN_LITTLE); + EXPECT_EQ(imageReceiveMsg2->GetCoordinateSystem(), IGTL_IMAGE_COORD_RAS); + + r = memcmp((const char*)imageReceiveMsg2->GetPackBodyPointer()+IGTL_IMAGE_HEADER_SIZE, test_image, TEST_IMAGE_MESSAGE_SIZE); + EXPECT_EQ(r, 0); + + igtl_header *transformHeader = (igtl_header *)transformReceiveMsg->GetPackPointer(); + EXPECT_STREQ(transformHeader->device_name, "ChildTrans"); + EXPECT_STREQ(transformHeader->name, "TRANSFORM"); + EXPECT_EQ(transformHeader->header_version, 1); + EXPECT_EQ(transformHeader->timestamp, 1234567892); + EXPECT_EQ(transformHeader->body_size, IGTL_TRANSFORM_SIZE); + + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + transformReceiveMsg->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); + + igtl_header *sensorHeader = (igtl_header *)sensorDataReceiveMsg->GetPackPointer(); + EXPECT_STREQ(sensorHeader->device_name, "ChildSensor"); + EXPECT_STREQ(sensorHeader->name, "SENSOR"); + EXPECT_EQ(sensorHeader->header_version, 1); + EXPECT_EQ(sensorHeader->timestamp, 1234567892); + EXPECT_EQ(sensorHeader->body_size, MESSAGE_SENSOR_BODY_SIZE); + + igtl::igtlUnit unitTruth = 0x443E0000000000; + EXPECT_EQ(sensorDataReceiveMsg->GetUnit(), unitTruth); + EXPECT_EQ(sensorDataReceiveMsg->GetLength(),6); + EXPECT_FLOAT_EQ(sensorDataReceiveMsg->GetValue(0),123456.78); + EXPECT_FLOAT_EQ(sensorDataReceiveMsg->GetValue(1),12345.678); + EXPECT_FLOAT_EQ(sensorDataReceiveMsg->GetValue(2),1234.5678); + EXPECT_FLOAT_EQ(sensorDataReceiveMsg->GetValue(3),123.45678); + EXPECT_FLOAT_EQ(sensorDataReceiveMsg->GetValue(4),12.345678); + EXPECT_FLOAT_EQ(sensorDataReceiveMsg->GetValue(5),1.2345678); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlCapabilityMessageTest.cxx b/openigtlink/repo/Testing/igtlCapabilityMessageTest.cxx new file mode 100644 index 0000000..954fe7f --- /dev/null +++ b/openigtlink/repo/Testing/igtlCapabilityMessageTest.cxx @@ -0,0 +1,75 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlCapabilityMessage.h" +#include "igtlutil/igtl_test_data_capability.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +#define CAPABILITY_MESSAGE_BODY_SIZE 48 + +igtl::CapabilityMessage::Pointer capabilitySendMsg = igtl::CapabilityMessage::New(); +igtl::CapabilityMessage::Pointer capabilityReceiveMsg = igtl::CapabilityMessage::New(); + +TEST(ColorTableMessageTest, Pack) +{ + capabilitySendMsg->SetTimeStamp(0, 1234567892); + capabilitySendMsg->SetDeviceName("DeviceName"); + capabilitySendMsg->SetNumberOfTypes(4); + capabilitySendMsg->SetType(0, "IMAGE"); + capabilitySendMsg->SetType(1, "GET_IMAGE"); + capabilitySendMsg->SetType(2, "TRANSFORM"); + capabilitySendMsg->SetType(3, "GET_TRANS"); + capabilitySendMsg->Pack(); + + TestDebugCharArrayCmp(capabilitySendMsg->GetPackPointer(), test_capability_message, IGTL_HEADER_SIZE); + int r = memcmp((const void*)capabilitySendMsg->GetPackPointer(), (const void*)test_capability_message, IGTL_HEADER_SIZE); + EXPECT_EQ(r, 0); + r = memcmp((const void*)capabilitySendMsg->GetPackBodyPointer(), (const void*)(test_capability_message+IGTL_HEADER_SIZE), CAPABILITY_MESSAGE_BODY_SIZE); + EXPECT_EQ(r, 0); +} + + +TEST(ColorTableMessageTest, Unpack) +{ + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + memcpy(headerMsg->GetPackPointer(), capabilitySendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + capabilityReceiveMsg->SetMessageHeader(headerMsg); + capabilityReceiveMsg->AllocatePack(); + memcpy(capabilityReceiveMsg->GetPackBodyPointer(), capabilitySendMsg->GetPackBodyPointer(), capabilitySendMsg->GetPackBodySize()); + capabilityReceiveMsg->Unpack(); + + EXPECT_EQ(capabilityReceiveMsg->GetNumberOfTypes(),4); + EXPECT_STREQ(capabilityReceiveMsg->GetType(0),"IMAGE"); + EXPECT_STREQ(capabilityReceiveMsg->GetType(1),"GET_IMAGE"); + EXPECT_STREQ(capabilityReceiveMsg->GetType(2),"TRANSFORM"); + EXPECT_STREQ(capabilityReceiveMsg->GetType(3),"GET_TRANS"); + std::vector typeStrings = capabilityReceiveMsg->GetTypes(); + EXPECT_EQ(typeStrings.size(),4); + EXPECT_STREQ(typeStrings[0].c_str(),"IMAGE"); + EXPECT_STREQ(typeStrings[1].c_str(),"GET_IMAGE"); + EXPECT_STREQ(typeStrings[2].c_str(),"TRANSFORM"); + EXPECT_STREQ(typeStrings[3].c_str(),"GET_TRANS"); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlClientSocketTest.cxx b/openigtlink/repo/Testing/igtlClientSocketTest.cxx new file mode 100644 index 0000000..2e3666d --- /dev/null +++ b/openigtlink/repo/Testing/igtlClientSocketTest.cxx @@ -0,0 +1,90 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlServerSocket.h" +#include "igtlSocket.h" +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtlMessageHeader.h" +#include "igtl_util.h" +#include "igtlOSUtil.h" +#include "igtlClientSocket.h" +#include "igtlMultiThreader.h" +#include "igtlQuaternionTrackingDataMessage.h" + +#include "igtlTestConfig.h" +#include "string.h" + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Invoke; +using ::testing::IsNull; + +using igtl::ServerSocket; +using igtl::ClientSocket; +using igtl::Socket; + + +class ClientSocketMock { +public: + ClientSocketMock(ClientSocket::Pointer pointer) { + real_ = pointer; + // By default, all calls are delegated to the real object. + ON_CALL(*this, ConnectToServer(_,_,_)) + .WillByDefault(Invoke(real_.GetPointer(), &ClientSocket::ConnectToServer)); + } + ClientSocketMock(){real_.~SmartPointer();}; + + MOCK_METHOD3(ConnectToServer, int(const char* hostName, int port, bool logErrorIfServerConnectionFailed)); + ClientSocket::Pointer getPointer(){return real_;}; + +private: + ClientSocket::Pointer real_; + +}; + +void* ThreadFunction(void* ptr); + +int port = 18944; + +TEST(ClientSocketTest, ConnectToServerTest) +{ + + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + igtl::ClientSocket::Pointer clientSocket; + clientSocket = igtl::ClientSocket::New(); + ClientSocketMock clientSocketMock(clientSocket); + EXPECT_CALL(clientSocketMock, ConnectToServer(_,_,_)).Times(2); + EXPECT_EQ(clientSocketMock.ConnectToServer("localhost", port,0), -1); + threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, NULL); + igtl::Sleep(1000); + EXPECT_EQ(clientSocketMock.ConnectToServer("localhost", port,1), 0); + clientSocketMock.getPointer()->CloseSocket(); +} + +void* ThreadFunction(void* ptr) +{ + int waitingTime = 10000; + ServerSocket::Pointer serverSocket = ServerSocket::New(); + serverSocket->CreateServer(port); + serverSocket->WaitForConnection(waitingTime); + serverSocket->CloseSocket(); + return NULL; +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlColorTableMessageTest.cxx b/openigtlink/repo/Testing/igtlColorTableMessageTest.cxx new file mode 100644 index 0000000..31335ca --- /dev/null +++ b/openigtlink/repo/Testing/igtlColorTableMessageTest.cxx @@ -0,0 +1,72 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlColorTableMessage.h" +#include "igtlutil/igtl_test_data_colortable2.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_colortable.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +#define COLOR_TABLE_SIZE 256 + +igtl::ColorTableMessage::Pointer colorTableSendMsg = igtl::ColorTableMessage::New(); +igtl::ColorTableMessage::Pointer colorTableReceiveMsg = igtl::ColorTableMessage::New(); + +TEST(ColorTableMessageTest, Pack) +{ + colorTableSendMsg->SetTimeStamp(0, 1234567892); + colorTableSendMsg->SetDeviceName("DeviceName"); + colorTableSendMsg->SetIndexType(IGTL_COLORTABLE_INDEX_UINT8); + colorTableSendMsg->SetMapType(IGTL_COLORTABLE_MAP_UINT8); + colorTableSendMsg->AllocateTable(); + memcpy(colorTableSendMsg->GetTablePointer(), test_colortable_message+IGTL_HEADER_SIZE+IGTL_COLORTABLE_HEADER_SIZE, (size_t)(COLOR_TABLE_SIZE)); + colorTableSendMsg->Pack(); + + TestDebugCharArrayCmp(colorTableSendMsg->GetPackPointer(), test_colortable_message, IGTL_HEADER_SIZE); + int r = memcmp((const void*)colorTableSendMsg->GetPackPointer(), (const void*)test_colortable_message, IGTL_HEADER_SIZE); + EXPECT_EQ(r, 0); + r = memcmp((const void*)colorTableSendMsg->GetPackBodyPointer(), (const void*)(test_colortable_message+IGTL_HEADER_SIZE), IGTL_COLORTABLE_HEADER_SIZE+COLOR_TABLE_SIZE); + EXPECT_EQ(r, 0); +} + + +TEST(ColorTableMessageTest, Unpack) +{ + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + memcpy(headerMsg->GetPackPointer(), colorTableSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + colorTableReceiveMsg->SetMessageHeader(headerMsg); + colorTableReceiveMsg->AllocatePack(); + memcpy(colorTableReceiveMsg->GetPackBodyPointer(), colorTableSendMsg->GetPackBodyPointer(), colorTableSendMsg->GetPackBodySize()); + colorTableReceiveMsg->Unpack(); + + EXPECT_EQ(colorTableReceiveMsg->GetMapType(),IGTL_COLORTABLE_MAP_UINT8); + EXPECT_EQ(colorTableReceiveMsg->GetIndexType(),IGTL_COLORTABLE_INDEX_UINT8); + for (int i = 0; i < 256; i ++) + { + EXPECT_EQ(((unsigned char*)colorTableReceiveMsg->GetTablePointer())[i], i); + } + +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlCommandMessageTest.cxx b/openigtlink/repo/Testing/igtlCommandMessageTest.cxx new file mode 100644 index 0000000..5669cec --- /dev/null +++ b/openigtlink/repo/Testing/igtlCommandMessageTest.cxx @@ -0,0 +1,202 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlCommandMessage.h" +#include "igtlutil/igtl_test_data_command.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_command.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +igtl::CommandMessage::Pointer sendCommandMsg = igtl::CommandMessage::New(); +igtl::CommandMessage::Pointer receiveCommandMsg = igtl::CommandMessage::New(); + +void BuildMessageFormat1() +{ + sendCommandMsg = igtl::CommandMessage::New(); + sendCommandMsg->SetHeaderVersion(1); + sendCommandMsg->SetCommandId(5); + sendCommandMsg->SetContentEncoding(3); + sendCommandMsg->SetCommandName("This is a test command"); + sendCommandMsg->SetCommandContent("Start the tracking machine"); + sendCommandMsg->Pack(); +} + +TEST(CommandMessageTest, PackFormatVersion1) +{ + BuildMessageFormat1(); + int r = memcmp((const void*)sendCommandMsg->GetBufferPointer(), (const void*)test_command_message,(size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)sendCommandMsg->GetBufferBodyPointer(), (const void*)(test_command_message+(size_t)(IGTL_HEADER_SIZE)), sizeof(test_command_message)-IGTL_HEADER_SIZE); + EXPECT_EQ(r, 0); +} + + +TEST(CommandMessageTest, UnPackFormatVersion1) +{ + BuildMessageFormat1(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->InitBuffer(); + memcpy(headerMsg->GetBufferPointer(), (const void*)sendCommandMsg->GetBufferPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + receiveCommandMsg->SetMessageHeader(headerMsg); + receiveCommandMsg->AllocatePack(); + memcpy(receiveCommandMsg->GetBufferBodyPointer(), sendCommandMsg->GetBufferBodyPointer(), headerMsg->GetBodySizeToRead()); + receiveCommandMsg->Unpack(); + igtl_header *messageHeader = (igtl_header *)receiveCommandMsg->GetBufferPointer(); + EXPECT_STREQ(messageHeader->device_name, ""); + EXPECT_STREQ(messageHeader->name, "COMMAND"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 0); + EXPECT_EQ(messageHeader->body_size, sizeof(test_command_message)-IGTL_HEADER_SIZE); + igtl_uint64 crc; + memcpy(&crc, &test_command_message[IGTL_HEADER_SIZE-sizeof(igtl_uint64)], sizeof(igtl_uint64)); + if(igtl_is_little_endian()) + { + crc = BYTE_SWAP_INT64(crc); + } + EXPECT_EQ(messageHeader->crc, crc); + EXPECT_STREQ(receiveCommandMsg->GetCommandContent().c_str(), "Start the tracking machine"); + EXPECT_EQ(receiveCommandMsg->GetContentEncoding(), 3); + + // Test start + // reuse the command message. + sendCommandMsg->SetContentEncoding(4); + sendCommandMsg->Pack(); + headerMsg->InitBuffer(); + memcpy(headerMsg->GetBufferPointer(), (const void*)sendCommandMsg->GetBufferPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + receiveCommandMsg->SetMessageHeader(headerMsg); + receiveCommandMsg->AllocatePack(); + memcpy(receiveCommandMsg->GetBufferBodyPointer(), sendCommandMsg->GetBufferBodyPointer(), headerMsg->GetBodySizeToRead()); + receiveCommandMsg->Unpack(); + //header should still be the same, though crc should be different + messageHeader = (igtl_header *)receiveCommandMsg->GetBufferPointer(); + EXPECT_STREQ(messageHeader->device_name, ""); + EXPECT_STREQ(messageHeader->name, "COMMAND"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 0); + EXPECT_EQ(messageHeader->body_size, sizeof(test_command_message)-IGTL_HEADER_SIZE); + if(igtl_is_little_endian()) + { + crc = BYTE_SWAP_INT64(crc); + } + EXPECT_NE(messageHeader->crc, crc); // should not be equal as the content changed + EXPECT_EQ(receiveCommandMsg->GetContentEncoding(), 4); + +} + + + +#if OpenIGTLink_PROTOCOL_VERSION >= 3 +#include "igtlutil/igtl_test_data_commandFormat2.h" +#include "igtlMessageFormat2TestMacro.h" +void BuildMessageFormat2() +{ + sendCommandMsg = igtl::CommandMessage::New(); + sendCommandMsg->SetHeaderVersion(2); + sendCommandMsg->SetCommandId(5); + sendCommandMsg->SetContentEncoding(3); + sendCommandMsg->SetCommandName("This is a test command"); + sendCommandMsg->SetCommandContent("Start the tracking machine"); + sendCommandMsg->SetDeviceName("OpticalTracker"); + igtlMetaDataAddElementMacro(sendCommandMsg); + sendCommandMsg->Pack(); +} + +TEST(CommandMessageTest, PackFormatVersion2) +{ + BuildMessageFormat2(); + int r = memcmp((const void*)sendCommandMsg->GetBufferPointer(), (const void*)test_command_messageFormat2, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)sendCommandMsg->GetBufferBodyPointer(), (const void*)(test_command_messageFormat2+(size_t)(IGTL_HEADER_SIZE)), sizeof(test_command_messageFormat2)-IGTL_HEADER_SIZE); + EXPECT_EQ(r, 0); +} + + +TEST(CommandMessageTest, UnpackFormatVersion2) +{ + BuildMessageFormat2(); + igtlMetaDataAddElementMacro(sendCommandMsg); + sendCommandMsg->Pack(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + headerMsg->InitBuffer(); + memcpy(headerMsg->GetBufferPointer(), (const void*)sendCommandMsg->GetBufferPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + + receiveCommandMsg->SetMessageHeader(headerMsg); + receiveCommandMsg->AllocatePack(); + memcpy(receiveCommandMsg->GetBufferBodyPointer(), sendCommandMsg->GetBufferBodyPointer(), headerMsg->GetBodySizeToRead()); + receiveCommandMsg->Unpack(); + + igtl_header *messageHeader = (igtl_header *)receiveCommandMsg->GetBufferPointer(); + EXPECT_STREQ(messageHeader->device_name, "OpticalTracker"); + EXPECT_STREQ(messageHeader->name, "COMMAND"); + EXPECT_EQ(messageHeader->header_version, 2); + EXPECT_EQ(messageHeader->timestamp, 0); + + int size = sizeof(test_command_messageFormat2) - IGTL_HEADER_SIZE; + EXPECT_EQ(messageHeader->body_size, sizeof(test_command_messageFormat2)-IGTL_HEADER_SIZE); + + igtl_uint64 crc; + memcpy(&crc, &test_command_messageFormat2[IGTL_HEADER_SIZE-sizeof(igtl_uint64)], sizeof(igtl_uint64)); + if(igtl_is_little_endian()) + { + crc = BYTE_SWAP_INT64(crc); + } + EXPECT_EQ(messageHeader->crc, crc); + EXPECT_STREQ(receiveCommandMsg->GetCommandContent().c_str(), "Start the tracking machine"); + igtlMetaDataComparisonMacro(receiveCommandMsg); + + // Test start + // reuse the command message. + sendCommandMsg->SetContentEncoding(4); + sendCommandMsg->Pack(); + headerMsg->InitBuffer(); + memcpy(headerMsg->GetBufferPointer(), (const void*)sendCommandMsg->GetBufferPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + receiveCommandMsg->SetMessageHeader(headerMsg); + receiveCommandMsg->AllocatePack(); + memcpy(receiveCommandMsg->GetBufferBodyPointer(), sendCommandMsg->GetBufferBodyPointer(), headerMsg->GetBodySizeToRead()); + receiveCommandMsg->Unpack(); + //header should still be the same, though crc should be different + messageHeader = (igtl_header *)receiveCommandMsg->GetBufferPointer(); + EXPECT_STREQ(messageHeader->device_name, "OpticalTracker"); + EXPECT_STREQ(messageHeader->name, "COMMAND"); + EXPECT_EQ(messageHeader->header_version, 2); + EXPECT_EQ(messageHeader->timestamp, 0); + EXPECT_EQ(messageHeader->body_size, sizeof(test_command_messageFormat2)-IGTL_HEADER_SIZE); + if(igtl_is_little_endian()) + { + crc = BYTE_SWAP_INT64(crc); + } + EXPECT_NE(messageHeader->crc, crc); // should not be equal as the content changed + EXPECT_EQ(receiveCommandMsg->GetContentEncoding(), 4); + EXPECT_STREQ(receiveCommandMsg->GetCommandContent().c_str(), "Start the tracking machine"); + igtlMetaDataComparisonMacro(receiveCommandMsg); +} + +#endif + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + + + + diff --git a/openigtlink/repo/Testing/igtlConditionVariableTest.cxx b/openigtlink/repo/Testing/igtlConditionVariableTest.cxx new file mode 100644 index 0000000..c266055 --- /dev/null +++ b/openigtlink/repo/Testing/igtlConditionVariableTest.cxx @@ -0,0 +1,213 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlConditionVariable.h" +#include "igtlMultiThreader.h" +#include "igtlOSUtil.h" +#include "igtlTestConfig.h" +#include "string.h" + +void* TestThreadCounter(void* ptr); +void* TestThreadWaitingTimeOut(void* ptr); +void* TestThreadWaiting1(void* ptr); +void* TestThreadWaiting2(void* ptr); + +typedef struct { + igtl::SimpleMutexLock* glock; + igtl::ConditionVariable::Pointer conditionVar; + bool isBroadCast; + int iFinalCount; + bool condition; + std::vector threads; +} ThreadData; + +TEST(ConditionVariableTest, SingleChildThreadTest) +{ + // From this test we can see that, the wait function really works, + // the main thread waits until the spawned thread is finished, otherwize the icount1 will be 0. + igtl::ConditionVariable::Pointer conditionVar = igtl::ConditionVariable::New(); + igtl::SimpleMutexLock *localMutex = new igtl::SimpleMutexLock(); + + ThreadData td; + td.threads = std::vector(1); + td.conditionVar = conditionVar; + td.glock = localMutex; + td.isBroadCast = false; + td.iFinalCount = 0; + td.condition = false; + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadWaiting1, &td); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadCounter, &td); + + while (td.threads[0] == false) + { + igtl::Sleep(20); + } + + std::cerr<<"The child thread is released"; + EXPECT_EQ(td.iFinalCount, 10); +} + +TEST(ConditionVariableTest, MultiChildThreadTest) +{ + igtl::ConditionVariable::Pointer conditionVar = igtl::ConditionVariable::New(); + igtl::SimpleMutexLock *localMutex = new igtl::SimpleMutexLock(); + ThreadData td; + td.conditionVar = conditionVar; + td.glock = localMutex; + td.isBroadCast = false; + td.threads = std::vector(2,false); + td.iFinalCount = 0; + td.condition = false; + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadWaiting1, &td); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadCounter, &td); + igtl::Sleep(1000); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadWaiting2, &td); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadCounter, &td); + while (td.threads[0] == false || td.threads[1] == false) + igtl::Sleep(20); + EXPECT_EQ(td.iFinalCount, 20); + std::cerr<<"The child threads are released"; +} + +TEST(ConditionVariableTest, Broadcast) +{ + igtl::ConditionVariable::Pointer conditionVar = igtl::ConditionVariable::New(); + igtl::SimpleMutexLock *localMutex = new igtl::SimpleMutexLock(); + ThreadData td; + td.conditionVar = conditionVar; + td.glock = localMutex; + td.isBroadCast = true; + td.threads = std::vector(2); + td.iFinalCount = 0; + td.condition = false; + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadWaiting1, &td); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadCounter, &td); + igtl::Sleep(1000); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadWaiting2, &td); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadCounter, &td); + while (td.threads[0] == false || td.threads[1] == false) + igtl::Sleep(20); + EXPECT_LT(td.iFinalCount, 20); + std::cerr<<"The child threads are released"; +} + + +TEST(ConditionVariableTest, WaitTimeOut) +{ + igtl::ConditionVariable::Pointer conditionVar = igtl::ConditionVariable::New(); + igtl::SimpleMutexLock *localMutex = new igtl::SimpleMutexLock(); + ThreadData td; + td.conditionVar = conditionVar; + td.glock = localMutex; + td.isBroadCast = true; + td.threads = std::vector(1); + td.threads[0] = false; + td.iFinalCount = 0; + td.condition = false; + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadWaitingTimeOut, &td); + igtl::Sleep(3000); + EXPECT_EQ(td.threads[0], true); + std::cerr<<"The child threads are released"; +} + + +void* TestThreadWaitingTimeOut(void* ptr) +{ + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + ThreadData* td = static_cast(info->UserData); + td->glock->Lock(); + + while(!td->condition) + { + td->conditionVar->Wait(td->glock, 1000); + } + + td->threads[0]= true; + td->glock->Unlock(); + return NULL; +} + +void* TestThreadWaiting1(void* ptr) +{ + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + ThreadData* td = static_cast(info->UserData); + td->glock->Lock(); + + while(!td->condition) + { + td->conditionVar->Wait(td->glock); + } + + td->threads[0]= true; + td->glock->Unlock(); + return NULL; +} + + +void* TestThreadWaiting2(void* ptr) +{ + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + ThreadData* td = static_cast(info->UserData); + td->glock->Lock(); + + while(!td->condition) + { + td->conditionVar->Wait(td->glock); + } + + td->threads[1]= true; + td->glock->Unlock(); + return NULL; +} + +void* TestThreadCounter(void* ptr) +{ + //------------------------------------------------------------ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + ThreadData* td = static_cast(info->UserData); + //igtl::SimpleMutexLock *glock = td->glocks[0]; + int i = 0; + while(++i <=10) + { + std::cerr<iFinalCount++; + }; + td->condition = true; + if (td->isBroadCast) + { + td->conditionVar->Broadcast(); + } + else + { + td->conditionVar->Signal(); + } + return NULL; +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlImageMessage2Test.cxx b/openigtlink/repo/Testing/igtlImageMessage2Test.cxx new file mode 100644 index 0000000..80e1332 --- /dev/null +++ b/openigtlink/repo/Testing/igtlImageMessage2Test.cxx @@ -0,0 +1,141 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlImageMessage2.h" +#include "igtlutil/igtl_test_data_image.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_image.h" +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_util.h" +#include "igtlTestConfig.h" +#include "string.h" + +igtl::ImageMessage2::Pointer imageSendMsg2 = igtl::ImageMessage2::New(); +igtl::ImageMessage2::Pointer imageReceiveMsg2 = igtl::ImageMessage2::New(); + +float inT[4] = {-0.954892f, 0.196632f, -0.222525f, 0.0}; +float inS[4] = {-0.196632f, 0.142857f, 0.970014f, 0.0}; +float inN[4] = {0.222525f, 0.970014f, -0.0977491f, 0.0}; +float inOrigin[4] = {46.0531f,19.4709f,46.0531f, 1.0}; +igtl::Matrix4x4 inMatrix = {{inT[0],inS[0],inN[0],inOrigin[0]}, + {inT[1],inS[1],inN[1],inOrigin[1]}, + {inT[2],inS[2],inN[2],inOrigin[2]}, + {inT[3],inS[3],inN[3],inOrigin[3]}}; +int size[3] = {50, 50, 1}; // image dimension +float spacing[3] = {1.0f, 1.0f, 1.0f}; // spacing (mm/pixel) +int svsize[3] = {50, 50, 1}; // sub-volume size +int svoffset[3] = {0, 0, 0}; // sub-volume offset +int scalarType = igtl::ImageMessage2::TYPE_UINT8;// scalar type + +void BuildUp() +{ + imageSendMsg2 = igtl::ImageMessage2::New(); + imageSendMsg2->SetTimeStamp(0, 1234567892); + imageSendMsg2->SetDeviceName("DeviceName"); + //Initialization of a image message + imageSendMsg2->SetDimensions(size); + imageSendMsg2->SetSpacing(spacing); + imageSendMsg2->SetScalarType(scalarType); + imageSendMsg2->SetSubVolume(svsize, svoffset); + imageSendMsg2->SetNumComponents(1); + imageSendMsg2->SetScalarType(IGTL_IMAGE_STYPE_TYPE_UINT8); + imageSendMsg2->SetEndian(IGTL_IMAGE_ENDIAN_LITTLE); + imageSendMsg2->SetCoordinateSystem(IGTL_IMAGE_COORD_RAS); + imageSendMsg2->SetMatrix(inMatrix); + imageSendMsg2->AllocateBuffer(IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE); + imageSendMsg2->AllocateScalars(); + memcpy(imageSendMsg2->GetPackFragmentPointer(1), (void*)(test_image_message+IGTL_HEADER_SIZE), IGTL_IMAGE_HEADER_SIZE);//here m_ImageHeader is set. + imageSendMsg2->SetScalarPointer((void*)test_image); //m_Image and m_Body are set + imageSendMsg2->Pack(); +} + +TEST(ImageMessage2Test, Pack) +{ + BuildUp(); + int r = memcmp((const void*)imageSendMsg2->GetPackPointer(), (const void*)test_image_message, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)imageSendMsg2->GetPackFragmentPointer(1), (const void*)(test_image_message+IGTL_HEADER_SIZE), (size_t)(IGTL_IMAGE_HEADER_SIZE)); + EXPECT_EQ(r, 0); +} + +TEST(ImageMessage2Test, Unpack) +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)imageSendMsg2->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + imageReceiveMsg2->SetMessageHeader(headerMsg); + imageReceiveMsg2->SetDimensions(50, 50, 1); + imageReceiveMsg2->SetSubVolume(50, 50, 1, 0, 0, 0); + imageReceiveMsg2->AllocateScalars(); + memcpy(imageReceiveMsg2->GetPackFragmentPointer(0), imageSendMsg2->GetPackFragmentPointer(0), IGTL_HEADER_SIZE); + + memcpy(imageReceiveMsg2->GetPackBodyPointer(), imageSendMsg2->GetPackBodyPointer(), IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE); + imageReceiveMsg2->Unpack(); + igtl_header *messageHeader = (igtl_header *)headerMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "IMAGE"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_IMAGE_HEADER_SIZE + TEST_IMAGE_MESSAGE_SIZE); + + int returnSize[3] = {0,0,0}; + imageReceiveMsg2->GetDimensions(returnSize); + EXPECT_THAT(returnSize,testing::ElementsAreArray(size)); + float returnSpacing[3] = {0.0f,0.0f,0.0f}; + imageReceiveMsg2->GetSpacing(returnSpacing); + for(int i=0;i < 3; i++) + { + EXPECT_NEAR(returnSpacing[i], spacing[i], ABS_ERROR); + } + int returnSvsize[3] = {0,0,0}, returnSvoffset[3] = {0,0,0}; + imageReceiveMsg2->GetSubVolume(returnSvsize, returnSvoffset); + EXPECT_THAT(returnSvsize,testing::ElementsAreArray(svsize)); + EXPECT_THAT(returnSvoffset,testing::ElementsAreArray(svoffset)); + EXPECT_EQ(imageReceiveMsg2->GetScalarType(), IGTL_IMAGE_STYPE_TYPE_UINT8); + EXPECT_EQ(imageReceiveMsg2->GetEndian(), IGTL_IMAGE_ENDIAN_LITTLE); + EXPECT_EQ(imageReceiveMsg2->GetCoordinateSystem(), IGTL_IMAGE_COORD_RAS); + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + imageReceiveMsg2->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); + int r = memcmp(imageReceiveMsg2->GetPackFragmentPointer(2), (unsigned char*)test_image, TEST_IMAGE_MESSAGE_SIZE); + EXPECT_EQ(r, 0); +} + +TEST(ImageMessage2Test, FragmentImageTest) +{ + EXPECT_TRUE(true); + /* + int TEST_FRAGMENTIMAGE_MESSAGE_SIZE = TEST_IMAGE_MESSAGE_SIZE/2; + unsigned char test_fragmentImage[TEST_FRAGMENTIMAGE_MESSAGE_SIZE]; + memcpy(test_fragmentImage, test_image_message+IGTL_HEADER_SIZE+IGTL_IMAGE_HEADER_SIZE+TEST_FRAGMENTIMAGE_MESSAGE_SIZE, TEST_FRAGMENTIMAGE_MESSAGE_SIZE); // copy the last half of the image + unsigned char * charwholeImagePointer = (unsigned char *)imageSendMsg2->GetScalarPointer(); + EXPECT_EQ(strcmp((const char *)charwholeImagePointer, (const char *)test_image), 0); + imageSendMsg2->SetScalarPointer((void*)test_fragmentImage); + unsigned char * fragmentImagePointer = (unsigned char *)imageSendMsg2->GetScalarPointer(); + EXPECT_NE(strcmp((const char *)charwholeImagePointer, (const char *)fragmentImagePointer),0); + EXPECT_EQ(strcmp((const char *)fragmentImagePointer, (const char *)(test_image_message+IGTL_HEADER_SIZE+IGTL_IMAGE_HEADER_SIZE+TEST_FRAGMENTIMAGE_MESSAGE_SIZE)),0); + */ +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlImageMessageTest.cxx b/openigtlink/repo/Testing/igtlImageMessageTest.cxx new file mode 100644 index 0000000..c0878af --- /dev/null +++ b/openigtlink/repo/Testing/igtlImageMessageTest.cxx @@ -0,0 +1,252 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlImageMessage.h" +#include "igtlutil/igtl_test_data_image.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_image.h" +#include "igtl_util.h" +#include "igtlTestConfig.h" +#include "string.h" + +igtl::ImageMessage::Pointer imageSendMsg = igtl::ImageMessage::New(); +igtl::ImageMessage::Pointer imageReceiveMsg = igtl::ImageMessage::New(); +float inT[4] = {-0.954892f, 0.196632f, -0.222525f, 0.0}; +float inS[4] = {-0.196632f, 0.142857f, 0.970014f, 0.0}; +float inN[4] = {0.222525f, 0.970014f, -0.0977491f, 0.0}; +float inOrigin[4] = {46.0531f,19.4709f,46.0531f, 1.0}; +igtl::Matrix4x4 inMatrix = {{inT[0],inS[0],inN[0],inOrigin[0]}, + {inT[1],inS[1],inN[1],inOrigin[1]}, + {inT[2],inS[2],inN[2],inOrigin[2]}, + {inT[3],inS[3],inN[3],inOrigin[3]}}; +int size[3] = {50, 50, 1}; // image dimension +float spacing[3] = {1.0f, 1.0f, 1.0f}; // spacing (mm/pixel) +int svsize[3] = {50, 50, 1}; // sub-volume size +int svoffset[3] = {0, 0, 0}; // sub-volume offset +int scalarType = igtl::ImageMessage::TYPE_UINT8;// scalar type + + +void BuildUp() +{ + imageSendMsg = igtl::ImageMessage::New(); + imageSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + imageSendMsg->SetTimeStamp(0, 1234567892); + imageSendMsg->SetDeviceName("DeviceName"); + //Initialization of a image message + imageSendMsg->SetDimensions(size); + imageSendMsg->SetSpacing(spacing); + imageSendMsg->SetScalarType(scalarType); + imageSendMsg->SetSubVolume(svsize, svoffset); + imageSendMsg->SetNumComponents(1); + imageSendMsg->SetScalarType(IGTL_IMAGE_STYPE_TYPE_UINT8); + imageSendMsg->SetEndian(IGTL_IMAGE_ENDIAN_LITTLE); + imageSendMsg->SetCoordinateSystem(IGTL_IMAGE_COORD_RAS); + imageSendMsg->SetMatrix(inMatrix); + imageSendMsg->AllocateScalars(); + memcpy((void*)imageSendMsg->GetScalarPointer(), test_image_message+IGTL_HEADER_SIZE+IGTL_IMAGE_HEADER_SIZE, TEST_IMAGE_MESSAGE_SIZE);//here m_Image is set. + imageSendMsg->Pack(); +} + +TEST(ImageMessageTest, Pack) +{ + BuildUp(); + int r = memcmp((const void*)imageSendMsg->GetPackPointer(), (const void*)test_image_message, + (size_t)(IGTL_HEADER_SIZE+IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE)); + EXPECT_EQ(r, 0); +} + +TEST(ImageMessageTest, Unpack) +{ + BuildUp(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)imageSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + imageReceiveMsg->SetMessageHeader(headerMsg); + imageReceiveMsg->AllocatePack(); + memcpy(imageReceiveMsg->GetPackBodyPointer(), imageSendMsg->GetPackBodyPointer(), IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE); + imageReceiveMsg->Unpack(); + + igtl_header *messageHeader = (igtl_header *)imageReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "IMAGE"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE); + + int returnSize[3] = {0,0,0}; + imageReceiveMsg->GetDimensions(returnSize); + EXPECT_THAT(returnSize,testing::ElementsAreArray(size)); + float returnSpacing[3] = {0.0f,0.0f,0.0f}; + imageReceiveMsg->GetSpacing(returnSpacing); + EXPECT_TRUE(ArrayFloatComparison(returnSpacing, spacing, 3, ABS_ERROR)); + int returnSvsize[3] = {0,0,0}, returnSvoffset[3] = {0,0,0}; + imageReceiveMsg->GetSubVolume(returnSvsize, returnSvoffset); + EXPECT_THAT(returnSvsize,testing::ElementsAreArray(svsize)); + EXPECT_THAT(returnSvoffset,testing::ElementsAreArray(svoffset)); + EXPECT_EQ(imageReceiveMsg->GetScalarType(), IGTL_IMAGE_STYPE_TYPE_UINT8); + EXPECT_EQ(imageReceiveMsg->GetEndian(), IGTL_IMAGE_ENDIAN_LITTLE); + EXPECT_EQ(imageReceiveMsg->GetCoordinateSystem(), IGTL_IMAGE_COORD_RAS); + + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + imageReceiveMsg->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); + //The imageHeader is byte-wized converted, so we skip the comparison of the image header. + int r = memcmp((const char*)imageReceiveMsg->GetPackBodyPointer()+IGTL_IMAGE_HEADER_SIZE, (const void*)(test_image_message+IGTL_HEADER_SIZE+IGTL_IMAGE_HEADER_SIZE), (size_t)(TEST_IMAGE_MESSAGE_SIZE)); + EXPECT_EQ(r, 0); + + + // Reuse message test + igtl::Matrix4x4 inMatrix2 = {{inT[1],inS[0],inN[2],inOrigin[0]}, + {inT[0],inS[2],inN[0],inOrigin[1]}, + {inT[2],inS[1],inN[1],inOrigin[2]}, + {inT[3],inS[3],inN[3],inOrigin[3]}}; + imageSendMsg->SetMatrix(inMatrix2); + imageSendMsg->Pack(); + headerMsg->InitPack(); + memcpy(headerMsg->GetPackPointer(), (const void*)imageSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + imageReceiveMsg->SetMessageHeader(headerMsg); + imageReceiveMsg->AllocatePack(); + memcpy(imageReceiveMsg->GetPackBodyPointer(), imageSendMsg->GetPackBodyPointer(), IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE); + imageReceiveMsg->Unpack(); + + messageHeader = (igtl_header *)imageReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "IMAGE"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE); + + imageReceiveMsg->GetDimensions(returnSize); + EXPECT_THAT(returnSize,testing::ElementsAreArray(size)); + imageReceiveMsg->GetSpacing(returnSpacing); + EXPECT_TRUE(ArrayFloatComparison(returnSpacing, spacing, 3, ABS_ERROR)); + imageReceiveMsg->GetSubVolume(returnSvsize, returnSvoffset); + EXPECT_THAT(returnSvsize,testing::ElementsAreArray(svsize)); + EXPECT_THAT(returnSvoffset,testing::ElementsAreArray(svoffset)); + EXPECT_EQ(imageReceiveMsg->GetScalarType(), IGTL_IMAGE_STYPE_TYPE_UINT8); + EXPECT_EQ(imageReceiveMsg->GetEndian(), IGTL_IMAGE_ENDIAN_LITTLE); + EXPECT_EQ(imageReceiveMsg->GetCoordinateSystem(), IGTL_IMAGE_COORD_RAS); + + igtl::Matrix4x4 outMatrix2 = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + imageReceiveMsg->GetMatrix(outMatrix2); + EXPECT_TRUE(MatrixComparison(outMatrix2, inMatrix2, ABS_ERROR)); + //The imageHeader is byte-wized converted, so we skip the comparison of the image header. + r = memcmp((const char*)imageReceiveMsg->GetPackBodyPointer()+IGTL_IMAGE_HEADER_SIZE, (const void*)(test_image_message+IGTL_HEADER_SIZE+IGTL_IMAGE_HEADER_SIZE), (size_t)(TEST_IMAGE_MESSAGE_SIZE)); + EXPECT_EQ(r, 0); +} + +#if OpenIGTLink_PROTOCOL_VERSION >= 3 + +TEST(ImageMessageTest, MetaDataGetsPackedAndRestoredFormatVersion2) +{ + // Message construction + int ext_x=2, ext_y=3, ext_z=4; + igtl::ImageMessage::Pointer msg = igtl::ImageMessage::New(); + msg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + msg->SetScalarTypeToUint16(); + msg->SetDimensions(2, 3, 4); + msg->SetNumComponents(1); + msg->AllocateScalars(); + igtlUint16* data = static_cast(msg->GetScalarPointer()); + for (igtlUint16 i = 0; i < ext_x*ext_y*ext_z; ++i, ++data) { + *data = 42; + } + msg->SetMetaDataElement("key", IANA_TYPE_UTF_8, "value"); + msg->Pack(); + + // Message transport + igtl::MessageHeader::Pointer header = igtl::MessageHeader::New(); + header->InitPack(); + memcpy(header->GetPackPointer(), msg->GetPackPointer(), header->GetPackSize()); + header->Unpack(); + + EXPECT_EQ(IGTL_HEADER_VERSION_2, header->GetHeaderVersion()); + + igtl::ImageMessage::Pointer target = igtl::ImageMessage::New(); + target->SetMessageHeader(header); + target->AllocatePack(); + + EXPECT_EQ(target->GetPackBodySize(), msg->GetPackBodySize()); + + memcpy(target->GetPackBodyPointer(), msg->GetPackBodyPointer(), target->GetPackBodySize()); + target->Unpack(); + + // Message comparison + EXPECT_EQ(IGTL_HEADER_VERSION_2, target->GetHeaderVersion()); + + target->GetDimensions(ext_x, ext_y, ext_z); + EXPECT_EQ(2, ext_x); // fails! + EXPECT_EQ(3, ext_y); // fails! + EXPECT_EQ(4, ext_z); // fails! + + data = static_cast(target->GetScalarPointer()); + for (igtlUint16 i = 0; i < ext_x*ext_y*ext_z; ++i, ++data) { + EXPECT_EQ(42, *data); // even leads to access violations! + } + + + // reuse message test + msg->SetMatrix(inMatrix); + msg->Pack(); + header->InitPack(); + memcpy(header->GetPackPointer(), msg->GetPackPointer(), header->GetPackSize()); + header->Unpack(); + + EXPECT_EQ(IGTL_HEADER_VERSION_2, header->GetHeaderVersion()); + + target = igtl::ImageMessage::New(); + target->SetMessageHeader(header); + target->AllocatePack(); + + EXPECT_EQ(target->GetPackBodySize(), msg->GetPackBodySize()); + + memcpy(target->GetPackBodyPointer(), msg->GetPackBodyPointer(), target->GetPackBodySize()); + target->Unpack(); + + // Message comparison + EXPECT_EQ(IGTL_HEADER_VERSION_2, target->GetHeaderVersion()); + + target->GetDimensions(ext_x, ext_y, ext_z); + EXPECT_EQ(2, ext_x); // fails! + EXPECT_EQ(3, ext_y); // fails! + EXPECT_EQ(4, ext_z); // fails! + + data = static_cast(target->GetScalarPointer()); + for (igtlUint16 i = 0; i < ext_x*ext_y*ext_z; ++i, ++data) { + EXPECT_EQ(42, *data); // even leads to access violations! + } + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + msg->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); +} +#endif + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlImageMetaMessageTest.cxx b/openigtlink/repo/Testing/igtlImageMetaMessageTest.cxx new file mode 100644 index 0000000..8623444 --- /dev/null +++ b/openigtlink/repo/Testing/igtlImageMetaMessageTest.cxx @@ -0,0 +1,180 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlImageMetaMessage.h" +#include "igtlutil/igtl_test_data_imgmeta.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_imgmeta.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +igtl::ImageMetaElement::Pointer imageMetaElement0 = igtl::ImageMetaElement::New(); +igtl::ImageMetaElement::Pointer imageMetaElement1 = igtl::ImageMetaElement::New(); +igtl::ImageMetaElement::Pointer imageMetaElement2 = igtl::ImageMetaElement::New(); +igtl::ImageMetaMessage::Pointer imageMetaSendMsg; +igtl::ImageMetaMessage::Pointer imageMetaReceiveMsg; + +void BuildUpLabelElements() +{ + igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); + timestamp->SetTime((igtlUint64)1234567892);//1234567850,1234567870,1234567890 are all fractions + imageMetaElement0->SetName("IMAGE_DESCRIPTION_0"); + imageMetaElement0->SetDeviceName("IMAGE_0"); + imageMetaElement0->SetModality("CT"); + imageMetaElement0->SetPatientName("PATIENT_0"); + imageMetaElement0->SetPatientID("PATIENT_ID_0"); + imageMetaElement0->SetTimeStamp(timestamp); + imageMetaElement0->SetScalarType(IGTL_IMAGE_STYPE_TYPE_UINT16); + imageMetaElement0->SetSize(512,512,64); + + timestamp = igtl::TimeStamp::New(); + timestamp->SetTime((igtlUint64)1234567896); + imageMetaElement1->SetName("IMAGE_DESCRIPTION_1"); + imageMetaElement1->SetDeviceName("IMAGE_1"); + imageMetaElement1->SetModality("MRI"); + imageMetaElement1->SetPatientName("PATIENT_1"); + imageMetaElement1->SetPatientID("PATIENT_ID_1"); + imageMetaElement1->SetTimeStamp(timestamp); + imageMetaElement1->SetScalarType(IGTL_IMAGE_STYPE_TYPE_UINT16); + imageMetaElement1->SetSize(256,128,32); + + timestamp = igtl::TimeStamp::New(); + timestamp->SetTime((igtl_uint64)1234567900); + imageMetaElement2->SetName("IMAGE_DESCRIPTION_2"); + imageMetaElement2->SetDeviceName("IMAGE_2"); + imageMetaElement2->SetModality("PET"); + imageMetaElement2->SetPatientName("PATIENT_2"); + imageMetaElement2->SetPatientID("PATIENT_ID_2"); + imageMetaElement2->SetTimeStamp(timestamp); + imageMetaElement2->SetScalarType(IGTL_IMAGE_STYPE_TYPE_UINT16); + imageMetaElement2->SetSize(256,256,32); + + timestamp = igtl::TimeStamp::New(); + timestamp->SetTime((igtlUint64)1234567892); + imageMetaSendMsg = igtl::ImageMetaMessage::New(); + imageMetaSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + imageMetaSendMsg->SetDeviceName("DeviceName"); + imageMetaSendMsg->SetTimeStamp(timestamp); + imageMetaSendMsg->AddImageMetaElement(imageMetaElement0); + imageMetaSendMsg->AddImageMetaElement(imageMetaElement1); + imageMetaSendMsg->AddImageMetaElement(imageMetaElement2); + imageMetaSendMsg->Pack(); +} + +TEST(ImageMetaMessageTest, TimeStampTrival) +{ + igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); + igtlUint32 tm = 1234567892; + igtlUint32 tm_forward = igtl_frac_to_nanosec(tm); + igtlUint32 tm_return; //= igtl_nanosec_to_frac(tm_forward); + tm_return = igtl_nanosec_to_frac(tm_forward); + EXPECT_EQ(tm_return, tm); +} + +TEST(ImageMetaMessageTest, Pack) +{ + BuildUpLabelElements(); + int r = memcmp((const void*)imageMetaSendMsg->GetPackPointer(), (const void*)test_imgmeta_message, + (size_t)(IGTL_HEADER_SIZE)); + TestDebugCharArrayCmp(imageMetaSendMsg->GetPackPointer(),test_imgmeta_message, 58); + + EXPECT_EQ(r, 0); + r = memcmp((const void*)imageMetaSendMsg->GetPackBodyPointer(), (const void*)(test_imgmeta_message+(size_t)(IGTL_HEADER_SIZE)), IGTL_IMGMETA_ELEMENT_SIZE*3 ); + EXPECT_EQ(r, 0); +} + + + +TEST(ImageMetaMessageTest, Unpack) +{ + BuildUpLabelElements(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)imageMetaSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + imageMetaReceiveMsg = igtl::ImageMetaMessage::New(); + imageMetaReceiveMsg->InitPack(); + imageMetaReceiveMsg->SetMessageHeader(headerMsg); + imageMetaReceiveMsg->AllocatePack(); + memcpy(imageMetaReceiveMsg->GetPackBodyPointer(), imageMetaSendMsg->GetPackBodyPointer(), IGTL_IMGMETA_ELEMENT_SIZE*3); + imageMetaReceiveMsg->Unpack(); + + igtl_header *messageHeader = (igtl_header *)imageMetaReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "IMGMETA"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_IMGMETA_ELEMENT_SIZE*3); + + std::vector > groundTruthSize(3,std::vector(3)); + igtlUint16 tempIni1[3] = {512,512,64}; + groundTruthSize[0].assign(tempIni1,tempIni1+3); + igtlUint16 tempIni2[3] = {256,128,32}; + groundTruthSize[1].assign(tempIni2,tempIni2+3); + igtlUint16 tempIni3[3] = {256,256,32}; + groundTruthSize[2].assign(tempIni3,tempIni3+3); + + std::vector name; + name.push_back((char*)"IMAGE_DESCRIPTION_0"); + name.push_back((char*)"IMAGE_DESCRIPTION_1"); + name.push_back((char*)"IMAGE_DESCRIPTION_2"); + std::vector deviceName; + deviceName.push_back((char*)"IMAGE_0"); + deviceName.push_back((char*)"IMAGE_1"); + deviceName.push_back((char*)"IMAGE_2"); + std::vector modality; + modality.push_back((char*)"CT\0"); + modality.push_back((char*)"MRI"); + modality.push_back((char*)"PET"); + std::vector patientName; + patientName.push_back((char*)"PATIENT_0"); + patientName.push_back((char*)"PATIENT_1"); + patientName.push_back((char*)"PATIENT_2"); + std::vector patientID; + patientID.push_back((char*)"PATIENT_ID_0"); + patientID.push_back((char*)"PATIENT_ID_1"); + patientID.push_back((char*)"PATIENT_ID_2"); + std::vector nanoSecond(3); + nanoSecond[0]=287445240; + nanoSecond[1]=287445241; + nanoSecond[2]=287445242; + + for (int i = 0; i<3;++i) + { + igtl::ImageMetaElement::Pointer elem = igtl::ImageMetaElement::New(); + imageMetaSendMsg->GetImageMetaElement(i, elem); + EXPECT_EQ(strncmp((char*)(elem->GetName()), name[i], 19),0); + EXPECT_EQ(strncmp((char*)(elem->GetDeviceName()), deviceName[i], 7),0); + EXPECT_EQ(strncmp((char*)(elem->GetModality()), modality[i], 3),0); + EXPECT_EQ(strncmp((char*)(elem->GetPatientName()), patientName[i], 9),0); + EXPECT_EQ(strncmp((char*)(elem->GetPatientID()), patientID[i], 12),0); + igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); + elem->GetTimeStamp(timestamp); + EXPECT_EQ(timestamp->GetNanosecond(), nanoSecond[i]); + EXPECT_EQ(timestamp->GetSecond(), 0); + + igtlUint16 returnedSize[3] ={0,0,0}; + elem->GetSize(returnedSize); + EXPECT_THAT(returnedSize, testing::ElementsAreArray(groundTruthSize[i])); + EXPECT_EQ(elem->GetScalarType(), (int)IGTL_IMAGE_STYPE_TYPE_UINT16); + } +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlLabelMetaMessageTest.cxx b/openigtlink/repo/Testing/igtlLabelMetaMessageTest.cxx new file mode 100644 index 0000000..9d29483 --- /dev/null +++ b/openigtlink/repo/Testing/igtlLabelMetaMessageTest.cxx @@ -0,0 +1,126 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlLabelMetaMessage.h" +#include "igtlutil/igtl_test_data_lbmeta.h" +#include "igtlutil/igtl_lbmeta.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +igtl::LabelMetaElement::Pointer labelMetaElement0 = igtl::LabelMetaElement::New(); +igtl::LabelMetaElement::Pointer labelMetaElement1 = igtl::LabelMetaElement::New(); +igtl::LabelMetaElement::Pointer labelMetaElement2 = igtl::LabelMetaElement::New(); +igtl::LabelMetaMessage::Pointer labelMetaSendMsg = igtl::LabelMetaMessage::New(); +igtl::LabelMetaMessage::Pointer labelMetaReceiveMsg = igtl::LabelMetaMessage::New(); + +void BuildUpLabelElements() +{ + labelMetaElement0->SetName("LABEL_DESCRIPTION_0"); + labelMetaElement0->SetDeviceName("LABEL_0"); + labelMetaElement0->SetLabel(1); + labelMetaElement0->SetRGBA(255,0,0,255); + labelMetaElement0->SetSize(256,128,32); + labelMetaElement0->SetOwner("IMAGE_0"); + labelMetaElement1->SetName("LABEL_DESCRIPTION_1"); + labelMetaElement1->SetDeviceName("LABEL_1"); + labelMetaElement1->SetLabel(2); + labelMetaElement1->SetRGBA(0,255,0,255); + labelMetaElement1->SetSize(256,128,32); + labelMetaElement1->SetOwner("IMAGE_0"); + labelMetaElement2->SetName("LABEL_DESCRIPTION_2"); + labelMetaElement2->SetDeviceName("LABEL_2"); + labelMetaElement2->SetLabel(3); + labelMetaElement2->SetRGBA(0,0,255,255); + labelMetaElement2->SetSize(256,128,32); + labelMetaElement2->SetOwner("IMAGE_0"); + labelMetaSendMsg = igtl::LabelMetaMessage::New(); + labelMetaSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + labelMetaSendMsg->SetDeviceName("DeviceName"); + labelMetaSendMsg->SetTimeStamp(0, 1234567892); + labelMetaSendMsg->AddLabelMetaElement(labelMetaElement0); + labelMetaSendMsg->AddLabelMetaElement(labelMetaElement1); + labelMetaSendMsg->AddLabelMetaElement(labelMetaElement2); + labelMetaSendMsg->Pack(); +} + +TEST(LabelMetaMessageTest, Pack) +{ + BuildUpLabelElements(); + int r = memcmp((const void*)labelMetaSendMsg->GetPackPointer(), (const void*)test_lbmeta_message, + (size_t)(IGTL_HEADER_SIZE)); + //The header comparison, however, the crc is different. because the igtl_lbmeta_get_crc() is different from the crc generation in MessageBase::Pack() + EXPECT_EQ(r, 0); + r = memcmp((const void*)labelMetaSendMsg->GetPackBodyPointer(), (const void*)(test_lbmeta_message+(size_t)(IGTL_HEADER_SIZE)), IGTL_LBMETA_ELEMENT_SIZE*3 ); + EXPECT_EQ(r, 0); +} + + +TEST(LabelMetaMessageTest, Unpack) +{ + BuildUpLabelElements(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)labelMetaSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + labelMetaReceiveMsg->SetMessageHeader(headerMsg); + labelMetaReceiveMsg->AllocatePack(); + memcpy(labelMetaReceiveMsg->GetPackBodyPointer(), labelMetaSendMsg->GetPackBodyPointer(), IGTL_LBMETA_ELEMENT_SIZE*3); + labelMetaReceiveMsg->Unpack(); + igtl_header *messageHeader = (igtl_header *)labelMetaReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "LBMETA"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, 348); + + std::vector > groundTruthRGBA(3,std::vector(4)); + igtlUint8 tempIni1[4] = {255,0,0,255}; + groundTruthRGBA[0].assign(tempIni1,tempIni1+4); + igtlUint8 tempIni2[4] = {0,255,0,255}; + groundTruthRGBA[1].assign(tempIni2,tempIni2+4); + igtlUint8 tempIni3[4] = {0,0,255,255}; + groundTruthRGBA[2].assign(tempIni3,tempIni3+4); + igtlUint16 groundTruthSize[3] = {256,128,32}; + + std::vector labelDescription; + labelDescription.push_back((char*)"LABEL_DESCRIPTION_0"); + labelDescription.push_back((char*)"LABEL_DESCRIPTION_1"); + labelDescription.push_back((char*)"LABEL_DESCRIPTION_2"); + std::vector label; + label.push_back((char*)"LABEL_0"); + label.push_back((char*)"LABEL_1"); + label.push_back((char*)"LABEL_2"); + for (int i = 0; i<3;++i) + { + igtl::LabelMetaElement::Pointer elem = igtl::LabelMetaElement::New(); + labelMetaReceiveMsg->GetLabelMetaElement(i, elem); + EXPECT_EQ(strncmp((char*)(elem->GetName()), labelDescription[i], 19),0); + EXPECT_EQ(strncmp((char*)(elem->GetDeviceName()), label[i], 7),0); + igtlUint8 returnedRGBA[4] ={0,0,0,0}; + elem->GetRGBA(returnedRGBA); + EXPECT_THAT(returnedRGBA, testing::ElementsAreArray(groundTruthRGBA[i])); + igtlUint16 returnedSize[3] ={0,0,0}; + elem->GetSize(returnedSize); + EXPECT_THAT(returnedSize, testing::ElementsAreArray(groundTruthSize)); + EXPECT_EQ(strncmp((char*)elem->GetOwner(), "IMAGE_0", 7),0); + } +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlMessageBaseTest.cxx b/openigtlink/repo/Testing/igtlMessageBaseTest.cxx new file mode 100644 index 0000000..e977994 --- /dev/null +++ b/openigtlink/repo/Testing/igtlMessageBaseTest.cxx @@ -0,0 +1,78 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtlMessageBase.h" +#include "igtlMessageHeader.h" +#include "igtlTestConfig.h" +#include "string.h" + +TEST(MessageBaseTest, InitializationTest) +{ + igtl::MessageBase::Pointer messageBaseTest = igtl::MessageBase::New(); + messageBaseTest->SetDeviceName("DeviceTest"); + EXPECT_STREQ(messageBaseTest->GetDeviceName(), "DeviceTest"); + messageBaseTest->InitPack(); + EXPECT_STREQ(messageBaseTest->GetDeviceName(),""); +} + +TEST(MessageBaseTest, SetDeviceNameTest) +{ + igtl::MessageBase::Pointer messageBaseTest = igtl::MessageBase::New(); + messageBaseTest->InitPack(); + EXPECT_STREQ(messageBaseTest->GetDeviceName(), ""); + messageBaseTest->SetDeviceName("DeviceTest"); + EXPECT_STREQ(messageBaseTest->GetDeviceName(), "DeviceTest"); +} + +TEST(MessageBaseTest, GetDeviceNameTest) +{ + igtl::MessageBase::Pointer messageBaseTest = igtl::MessageBase::New(); + messageBaseTest->SetDeviceName("DeviceTest"); + EXPECT_STREQ(messageBaseTest->GetDeviceName(), "DeviceTest"); +} + + +TEST(MessageBaseTest, TimeStampTest) +{ + igtl::MessageBase::Pointer messageBaseTest = igtl::MessageBase::New(); + messageBaseTest->SetTimeStamp(1,2); + unsigned int sec=0, nanosec=0; + messageBaseTest->GetTimeStamp(&sec,&nanosec); + EXPECT_EQ(sec, 1); + EXPECT_EQ(nanosec, 2); + igtl::TimeStamp::Pointer ts_input = igtl::TimeStamp::New(); + ts_input->SetTime(123,500000000); //nanosecond can not be larger or equal to 1e9. + //5e8 nanosecond equals 2147483647 frac second. + messageBaseTest->SetTimeStamp(ts_input); + messageBaseTest->GetTimeStamp(&sec,&nanosec); + EXPECT_EQ(sec, 123); + EXPECT_EQ(nanosec, 2147483648); +} + +TEST(MessageBaseTest, UNPACKTEST) +{ + igtl::MessageBase::Pointer messageBaseTest = igtl::MessageBase::New(); + messageBaseTest->AllocateBuffer(); + int status = messageBaseTest->Unpack(); + EXPECT_EQ(status, static_cast(messageBaseTest->UNPACK_HEADER)); +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + + + diff --git a/openigtlink/repo/Testing/igtlMessageFactoryTest.cxx b/openigtlink/repo/Testing/igtlMessageFactoryTest.cxx new file mode 100644 index 0000000..ad74fb8 --- /dev/null +++ b/openigtlink/repo/Testing/igtlMessageFactoryTest.cxx @@ -0,0 +1,101 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include + +#include + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +namespace igtl +{ + // Create a nonsense message type that won't exist in main library. + igtlCreateDefaultQueryMessageClass(BananaMessage, "BANANA") +} + +/** + * Author: Matt Clarkson (m.clarkson@ucl.ac.uk). + */ +int main(int , char * [] ) +{ + + igtl::MessageFactory::Pointer factory = igtl::MessageFactory::New(); + + igtl::MessageHeader::Pointer header = NULL; + + if (factory->IsValid(header)) + { + std::cerr << "A null header is not valid." << std::endl; + return EXIT_FAILURE; + } + + header = igtl::MessageHeader::New(); + + if (factory->IsValid(header)) + { + std::cerr << "A header without a DeviceType e.g. STRING, TRANSFORM is invalid." << std::endl; + return EXIT_FAILURE; + } + + igtl::TransformMessage::Pointer transformMessage = igtl::TransformMessage::New(); + + if (!factory->IsValid(transformMessage.GetPointer())) + { + std::cerr << "The IsValid method should check for not null, and a valid DeviceType. TRANSFORM should be valid." << std::endl; + return EXIT_FAILURE; + } + + // Test with an invalid message. + igtl::BananaMessage::Pointer bananaMessage = igtl::BananaMessage::New(); + + // Check firstly its not valid. + if (factory->IsValid(bananaMessage.GetPointer())) + { + std::cerr << "The IsValid method should fail for BANANA messages." << std::endl; + return EXIT_FAILURE; + } + + header->SetDeviceType("BANANA"); + header->SetHeaderVersion(IGTL_HEADER_VERSION_1); + + if (factory->GetMessage(header)) + { + std::cerr << "The GetMessage method should return NULL for BANANA messages." << std::endl; + return EXIT_FAILURE; + } + + if (factory->CreateReceiveMessage(header)) + { + std::cerr << "The CreateReceiveMessage method should return NULL for BANANA messages." << std::endl; + return EXIT_FAILURE; + } + + if (factory->CreateSendMessage("BANANA", IGTL_HEADER_VERSION_1)) + { + std::cerr << "The CreateSendMessage method should return NULL for BANANA messages." << std::endl; + return EXIT_FAILURE; + } + + if (factory->GetMessageTypeNewPointer("BANANA")) + { + std::cerr << "The CreateSendMessage method should return NULL for BANANA messages." << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + diff --git a/openigtlink/repo/Testing/igtlMessageFormat2TestMacro.h b/openigtlink/repo/Testing/igtlMessageFormat2TestMacro.h new file mode 100644 index 0000000..1bdb556 --- /dev/null +++ b/openigtlink/repo/Testing/igtlMessageFormat2TestMacro.h @@ -0,0 +1,55 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C++ + Web page: http://openigtlink.org/ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __igltMessageFormat2TestMarco_h +#define __igltMessageFormat2TestMarco_h + +#include + +#define EXTENDED_CONTENT_SIZE 69 // the extended content size variable sums up the size of the Extended header, meta data header and meta data. + + +#define igtlMetaDataAddElementMacro(object) \ + object->SetHeaderVersion(IGTL_HEADER_VERSION_2);\ + IANA_ENCODING_TYPE codingScheme = IANA_TYPE_US_ASCII; /* 3 corresponding to US-ASCII */ \ + object->SetMetaDataElement("First patient age", codingScheme, "22");\ + object->SetMetaDataElement("Second patient age",codingScheme, "25");\ + object->SetMessageID(1); + +#define igtlMetaDataComparisonMacro(object) \ + {\ + std::vector groundTruth(0); \ + groundTruth.push_back("First patient age");\ + groundTruth.push_back("Second patient age");\ + \ + std::vector groundTruthAge(0);\ + groundTruthAge.push_back("22");\ + groundTruthAge.push_back("25");\ + \ + EXPECT_EQ(object->GetMessageID(),1);\ + \ + \ + int i = 0;\ + for (igtl::MessageBase::MetaDataMap::const_iterator it = object->GetMetaData().begin(); it != object->GetMetaData().end(); ++it, ++i)\ + {\ + EXPECT_STREQ(it->first.c_str(), groundTruth[i].c_str());\ + EXPECT_EQ(it->second.first, IANA_TYPE_US_ASCII);\ + EXPECT_STREQ(it->second.second.c_str(), groundTruthAge[i].c_str());\ + }\ + } + + +#endif // __igltMessageFormat2TestMarco_h + + diff --git a/openigtlink/repo/Testing/igtlMessageRTPWrapperTest.cxx b/openigtlink/repo/Testing/igtlMessageRTPWrapperTest.cxx new file mode 100644 index 0000000..74a8a61 --- /dev/null +++ b/openigtlink/repo/Testing/igtlMessageRTPWrapperTest.cxx @@ -0,0 +1,229 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlMessageRTPWrapper.h" +#include "igtlImageMessage.h" +#include "igtlutil/igtl_test_data_rtpwrapper.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_image.h" +#include "igtl_util.h" +#include "igtlTestConfig.h" +#include "string.h" + +igtl::ImageMessage::Pointer imageSendMsg = igtl::ImageMessage::New(); +igtl::ImageMessage::Pointer imageReceiveMsg = igtl::ImageMessage::New(); +igtl::MessageRTPWrapper::Pointer messageWrapperSenderSide = igtl::MessageRTPWrapper::New(); +igtl::MessageRTPWrapper::Pointer messageWrapperReceiverSide = igtl::MessageRTPWrapper::New(); +float inT[4] = {-0.954892f, 0.196632f, -0.222525f, 0.0}; +float inS[4] = {-0.196632f, 0.142857f, 0.970014f, 0.0}; +float inN[4] = {0.222525f, 0.970014f, -0.0977491f, 0.0}; +float inOrigin[4] = {46.0531f,19.4709f,46.0531f, 1.0}; +igtl::Matrix4x4 inMatrix = {{inT[0],inS[0],inN[0],inOrigin[0]}, + {inT[1],inS[1],inN[1],inOrigin[1]}, + {inT[2],inS[2],inN[2],inOrigin[2]}, + {inT[3],inS[3],inN[3],inOrigin[3]}}; +int size[3] = {50, 50, 1}; // image dimension +float spacing[3] = {1.0f, 1.0f, 1.0f}; // spacing (mm/pixel) +int svsize[3] = {50, 50, 1}; // sub-volume size +int svoffset[3] = {0, 0, 0}; // sub-volume offset +int scalarType = igtl::ImageMessage::TYPE_UINT8;// scalar type +int UDPPacketLength = 1300; + +#if OpenIGTLink_PROTOCOL_VERSION >= 3 +#include "igtlMessageFormat2TestMacro.h" +void BuildUp() +{ + imageSendMsg = igtl::ImageMessage::New(); + imageSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + imageSendMsg->SetTimeStamp(0, 1234567892); + imageSendMsg->SetDeviceName("DeviceName"); + //Initialization of a image message + imageSendMsg->SetDimensions(size); + imageSendMsg->SetSpacing(spacing); + imageSendMsg->SetScalarType(scalarType); + imageSendMsg->SetSubVolume(svsize, svoffset); + imageSendMsg->SetNumComponents(1); + imageSendMsg->SetScalarType(IGTL_IMAGE_STYPE_TYPE_UINT8); + imageSendMsg->SetEndian(IGTL_IMAGE_ENDIAN_LITTLE); + imageSendMsg->SetCoordinateSystem(IGTL_IMAGE_COORD_RAS); + imageSendMsg->SetMatrix(inMatrix); + igtlMetaDataAddElementMacro(imageSendMsg); + imageSendMsg->AllocateScalars(); + memcpy((void*)imageSendMsg->GetScalarPointer(), test_image, TEST_IMAGE_MESSAGE_SIZE);//here m_Image is set. + imageSendMsg->Pack(); + messageWrapperSenderSide = igtl::MessageRTPWrapper::New(); + messageWrapperSenderSide->SetRTPPayloadType(0); // 0 corresponding to PCMU payload type, default is 96 for dynamic allocation. + messageWrapperSenderSide->SetRTPPayloadLength(UDPPacketLength); + messageWrapperSenderSide->SetSeqNum(0); + messageWrapperSenderSide->WrapMessageAndPushToBuffer((igtl_uint8*)imageSendMsg->GetPackPointer(), imageSendMsg->GetPackSize()); +} + +TEST(MessageRTPWrapperTest, WrapMessageFormatVersion2) +{ + BuildUp(); + igtl::PacketBuffer bufferedMsg = messageWrapperSenderSide->GetOutGoingPackets(); + //First Packet excluding time stamp comparison + int r = memcmp(bufferedMsg.pBsBuf.data(), (const void*)test_RTPWrapper_PacketBuffer, 4); + EXPECT_EQ(r, 0); + r = memcmp(bufferedMsg.pBsBuf.data()+8, (const void*)(test_RTPWrapper_PacketBuffer+8), 4); + EXPECT_EQ(r, 0); + r = memcmp(bufferedMsg.pBsBuf.data()+RTP_HEADER_LENGTH, (const void*)(test_RTPWrapper_PacketBuffer+RTP_HEADER_LENGTH), UDPPacketLength); + EXPECT_EQ(r, 0); + + //Second Packet excluding time stamp comparison + r = memcmp(bufferedMsg.pBsBuf.data()+UDPPacketLength+RTP_HEADER_LENGTH, (const void*)(test_RTPWrapper_PacketBuffer+UDPPacketLength+RTP_HEADER_LENGTH), 4); + EXPECT_EQ(r, 0); + r = memcmp(bufferedMsg.pBsBuf.data()+UDPPacketLength+RTP_HEADER_LENGTH+8, (const void*)(test_RTPWrapper_PacketBuffer+UDPPacketLength+RTP_HEADER_LENGTH+8), 4); + EXPECT_EQ(r, 0);// + r = memcmp(bufferedMsg.pBsBuf.data()+UDPPacketLength+2*RTP_HEADER_LENGTH, (const void*)(test_RTPWrapper_PacketBuffer+UDPPacketLength+2*RTP_HEADER_LENGTH), UDPPacketLength); + EXPECT_EQ(r, 0);// + + //Third Packet excluding time stamp comparison + r = memcmp(bufferedMsg.pBsBuf.data()+2*UDPPacketLength+2*RTP_HEADER_LENGTH, (const void*)(test_RTPWrapper_PacketBuffer+2*UDPPacketLength+2*RTP_HEADER_LENGTH), 4); + EXPECT_EQ(r, 0); + r = memcmp(bufferedMsg.pBsBuf.data()+2*UDPPacketLength+2*RTP_HEADER_LENGTH+8, (const void*)(test_RTPWrapper_PacketBuffer+2*UDPPacketLength+2*RTP_HEADER_LENGTH+8), 4); + EXPECT_EQ(r, 0);// + r = memcmp(bufferedMsg.pBsBuf.data()+2*UDPPacketLength+3*RTP_HEADER_LENGTH, (const void*)(test_RTPWrapper_PacketBuffer+2*UDPPacketLength+3*RTP_HEADER_LENGTH),bufferedMsg.totalLength-2*UDPPacketLength-3*RTP_HEADER_LENGTH); + EXPECT_EQ(r, 0); + //TestDebugCharArrayCmp(bufferedMsg.pBsBuf.data(), (igtlUint8*)test_RTPWrapper_PacketBuffer , bufferedMsg.totalLength); +} + +TEST(MessageRTPWrapperTest, UnwrapMessageFormatVersion2) +{ + BuildUp(); + messageWrapperReceiverSide = igtl::MessageRTPWrapper::New(); + messageWrapperReceiverSide->SetRTPPayloadLength(UDPPacketLength); + igtl::PacketBuffer bufferedMsg = messageWrapperSenderSide->GetOutGoingPackets(); + igtlUint8* UDPPacket = bufferedMsg.pBsBuf.data(); + for (int i= 0; iPushDataIntoPacketBuffer(UDPPacket, bufferedMsg.pPacketLengthInByte[i]); + UDPPacket += bufferedMsg.pPacketLengthInByte[i]; + } + while(1) + { + int iRet = messageWrapperReceiverSide->UnWrapPacketWithTypeAndName("IMAGE", "DeviceName"); + if(iRet == 0) + break; + } + EXPECT_EQ(messageWrapperReceiverSide->unWrappedMessages.size(), 1); + igtl::ImageMessage::Pointer imageReceiveMsg = igtl::ImageMessage::New(); + std::map::iterator it = messageWrapperReceiverSide->unWrappedMessages.begin(); + igtl::MessageHeader::Pointer header = igtl::MessageHeader::New(); + header->InitPack(); + memcpy(header->GetPackPointer(), it->second->messagePackPointer, IGTL_HEADER_SIZE); + header->Unpack(); + imageReceiveMsg->SetMessageHeader(header); + imageReceiveMsg->AllocateBuffer(); + memcpy(imageReceiveMsg->GetPackBodyPointer(), it->second->messagePackPointer + IGTL_HEADER_SIZE, it->second->messageDataLength - IGTL_HEADER_SIZE); + int c = imageReceiveMsg->Unpack(1); + EXPECT_EQ(c, 2); + igtl_header *messageHeader = (igtl_header *)imageReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "IMAGE"); + EXPECT_EQ(messageHeader->header_version, IGTL_HEADER_VERSION_2); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, imageReceiveMsg->GetPackBodySize()); + + int returnSize[3] = { 0, 0, 0 }; + imageReceiveMsg->GetDimensions(returnSize); + EXPECT_THAT(returnSize, testing::ElementsAreArray(size)); + float returnSpacing[3] = { 0.0f, 0.0f, 0.0f }; + imageReceiveMsg->GetSpacing(returnSpacing); + EXPECT_TRUE(ArrayFloatComparison(returnSpacing, spacing, 3, ABS_ERROR)); + int returnSvsize[3] = { 0, 0, 0 }, returnSvoffset[3] = { 0, 0, 0 }; + imageReceiveMsg->GetSubVolume(returnSvsize, returnSvoffset); + EXPECT_THAT(returnSvsize, testing::ElementsAreArray(svsize)); + EXPECT_THAT(returnSvoffset, testing::ElementsAreArray(svoffset)); + EXPECT_EQ(imageReceiveMsg->GetScalarType(), IGTL_IMAGE_STYPE_TYPE_UINT8); + EXPECT_EQ(imageReceiveMsg->GetEndian(), IGTL_IMAGE_ENDIAN_LITTLE); + EXPECT_EQ(imageReceiveMsg->GetCoordinateSystem(), IGTL_IMAGE_COORD_RAS); + EXPECT_EQ(imageReceiveMsg->GetMessageID(), 1); + + + igtl::Matrix4x4 outMatrix = { { 0.0, 0.0, 0.0, 0.0 }, + { 0.0, 0.0, 0.0, 0.0 }, + { 0.0, 0.0, 0.0, 0.0 }, + { 0.0, 0.0, 0.0, 0.0 } }; + imageReceiveMsg->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); + //The imageHeader is byte-wized converted, so we skip the comparison of the image header. + int r = memcmp((const char*)imageReceiveMsg->GetPackBodyPointer() + IGTL_IMAGE_HEADER_SIZE + IGTL_EXTENDED_HEADER_SIZE, (const void*)(test_image), (size_t)(TEST_IMAGE_MESSAGE_SIZE)); + EXPECT_EQ(r, 0); + // Test the packet reorder function of the RTP Wrapper. In the following lines, we reverse the order of received UDPPackets. + messageWrapperReceiverSide = igtl::MessageRTPWrapper::New(); + messageWrapperReceiverSide->SetRTPPayloadLength(UDPPacketLength); + UDPPacket = bufferedMsg.pBsBuf.data()+bufferedMsg.totalLength; + for (int i = bufferedMsg.pPacketLengthInByte.size()-1; i>=0;i--) + { + UDPPacket -= bufferedMsg.pPacketLengthInByte[i]; + messageWrapperReceiverSide->PushDataIntoPacketBuffer(UDPPacket, bufferedMsg.pPacketLengthInByte[i]); + } + while(1) + { + int iRet = messageWrapperReceiverSide->UnWrapPacketWithTypeAndName("IMAGE", "DeviceName"); + if(iRet == 0) + break; + } + EXPECT_EQ(messageWrapperReceiverSide->unWrappedMessages.size(), 1); + imageReceiveMsg = igtl::ImageMessage::New(); + it = messageWrapperReceiverSide->unWrappedMessages.begin(); + header = igtl::MessageHeader::New(); + header->InitPack(); + memcpy(header->GetPackPointer(), it->second->messagePackPointer, IGTL_HEADER_SIZE); + header->Unpack(); + imageReceiveMsg->SetMessageHeader(header); + imageReceiveMsg->AllocateBuffer(); + memcpy(imageReceiveMsg->GetPackBodyPointer(), it->second->messagePackPointer + IGTL_HEADER_SIZE, it->second->messageDataLength - IGTL_HEADER_SIZE); + c = imageReceiveMsg->Unpack(1); + EXPECT_EQ(c, 2); + messageHeader = (igtl_header *)imageReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "IMAGE"); + EXPECT_EQ(messageHeader->header_version, IGTL_HEADER_VERSION_2); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, imageReceiveMsg->GetPackBodySize()); + + imageReceiveMsg->GetDimensions(returnSize); + EXPECT_THAT(returnSize, testing::ElementsAreArray(size)); + imageReceiveMsg->GetSpacing(returnSpacing); + EXPECT_TRUE(ArrayFloatComparison(returnSpacing, spacing, 3, ABS_ERROR)); + imageReceiveMsg->GetSubVolume(returnSvsize, returnSvoffset); + EXPECT_THAT(returnSvsize, testing::ElementsAreArray(svsize)); + EXPECT_THAT(returnSvoffset, testing::ElementsAreArray(svoffset)); + EXPECT_EQ(imageReceiveMsg->GetScalarType(), IGTL_IMAGE_STYPE_TYPE_UINT8); + EXPECT_EQ(imageReceiveMsg->GetEndian(), IGTL_IMAGE_ENDIAN_LITTLE); + EXPECT_EQ(imageReceiveMsg->GetCoordinateSystem(), IGTL_IMAGE_COORD_RAS); + EXPECT_EQ(imageReceiveMsg->GetMessageID(), 1); + + + igtl::Matrix4x4 outMatrix2 = { { 0.0, 0.0, 0.0, 0.0 }, + { 0.0, 0.0, 0.0, 0.0 }, + { 0.0, 0.0, 0.0, 0.0 }, + { 0.0, 0.0, 0.0, 0.0 } }; + imageReceiveMsg->GetMatrix(outMatrix2); + EXPECT_TRUE(MatrixComparison(outMatrix2, inMatrix, ABS_ERROR)); + //The imageHeader is byte-wized converted, so we skip the comparison of the image header. + r = memcmp((const char*)imageReceiveMsg->GetPackBodyPointer() + IGTL_IMAGE_HEADER_SIZE + IGTL_EXTENDED_HEADER_SIZE, (const void*)(test_image), (size_t)(TEST_IMAGE_MESSAGE_SIZE)); + EXPECT_EQ(r, 0); +} +#endif + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlMultiThreaderTest1.cxx b/openigtlink/repo/Testing/igtlMultiThreaderTest1.cxx new file mode 100644 index 0000000..2fa3be4 --- /dev/null +++ b/openigtlink/repo/Testing/igtlMultiThreaderTest1.cxx @@ -0,0 +1,123 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +//========================================================================= +// +// MultiThreader Test 1 --- Single Method Test +// +// This test check the behaviour of igtl::MultiThreader::SingleMethodExecute() +// and igtl::MutexLock. +// The test create NUM_THREAD threads from a single method that repeats: +// +// s1 = s; +// sleep(interval) +// s2 = s; +// s = s1 + s2; +// +// for NUM_REPEAT times, where 's' is a global variable (shared by all +// threads) initialized with 1, and 's1', 's2' and 'interval' are local +// variables. 'interval' differs from thread to thread. +// If the threads work correctly, and the code block above is properly +// protected by a semaphore, 's' finally becomes 2^(NUM_REPEAT * NUM_THREAD-1). +// +//========================================================================= + + +#include "igtlMultiThreader.h" +#include "igtlOSUtil.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +// NOTE: (NUM_THREAD + NUM_REPEAT) < 32 on 32-bit environment +#if IGTL_MAX_THREADS > 1 + #define NUM_THREAD 5 + #define NUM_REPEAT 4 +#else + #define NUM_THREAD 1 + #define NUM_REPEAT 4 +#endif + + +typedef struct { + int nloop; + int *sum; + igtl::MutexLock::Pointer glock; +} ThreadData; + + +void* ThreadFunction(void* ptr) +{ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + int id = info->ThreadID; + + // Set interval at 100 * id (ms) + long interval = 10*id; + + ThreadData* data = static_cast(info->UserData); + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + int s1 = *(data->sum); + igtl::Sleep(interval); + int s2 = *(data->sum); + *(data->sum) = s1 + s2; + glock->Unlock(); + } + + return NULL; +} + + +int main(int, char * [] ) +{ + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + + int sum = 1; + + ThreadData td; + td.nloop = NUM_REPEAT; + td.sum = ∑ + td.glock = glock; + + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + + threader->SetNumberOfThreads(NUM_THREAD); + threader->SetSingleMethod((igtl::ThreadFunctionType) &ThreadFunction, &td); + threader->SingleMethodExecute(); + + int answer = 0x00000001; + answer <<= (NUM_THREAD * NUM_REPEAT); + + //std::cerr << "sum = " << sum << " answer = " << answer << std::endl; + + if (sum == answer) + { + return EXIT_SUCCESS; + } + else + { + return EXIT_FAILURE; + } +} + + + + + diff --git a/openigtlink/repo/Testing/igtlMultiThreaderTest2.cxx b/openigtlink/repo/Testing/igtlMultiThreaderTest2.cxx new file mode 100644 index 0000000..c462d60 --- /dev/null +++ b/openigtlink/repo/Testing/igtlMultiThreaderTest2.cxx @@ -0,0 +1,229 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +//========================================================================= +// +// MultiThreader Test 2 --- Multiple Method Test +// +// This test check the behaviour of igtl::MultiThreader::MultipleMethodExecute() +// and igtl::MutexLock. +// The test create NUM_THREAD threads from methods that repeats: +// +// s1 = s; +// sleep(interval) +// s2 = s; +// s = s1 + s2; +// +// for NUM_REPEAT times, where 's' is a global variable (shared by all +// threads) initialized with 1, and 's1', 's2' and 'interval' are local +// variables. 'interval' differs from thread to thread. +// If the threads work correctly, and the code block above is properly +// protected by a semaphore, 's' finally becomes 2^(NUM_REPEAT * NUM_THREAD-1). +// +//========================================================================= + + +#include "igtlMultiThreader.h" +#include "igtlOSUtil.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +// NOTE: (NUM_THREAD + NUM_REPEAT) < 32 on 32-bit environment +#if IGTL_MAX_THREADS > 1 + #define NUM_THREAD 5 + #define NUM_REPEAT 4 +#else + #define NUM_THREAD 1 + #define NUM_REPEAT 4 +#endif + + +typedef struct { + int nloop; + int *sum; + igtl::MutexLock::Pointer glock; +} ThreadData; + + +void* ThreadFunction1(void* ptr) +{ + long interval = 10; // (ms) + + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + ThreadData* data = static_cast(info->UserData); + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + int s1 = *(data->sum); + igtl::Sleep(interval); + int s2 = *(data->sum); + *(data->sum) = s1 + s2; + glock->Unlock(); + } + + return NULL; +} + +void* ThreadFunction2(void* ptr) +{ + long interval = 20; // (ms) + + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + ThreadData* data = static_cast(info->UserData); + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + int s1 = *(data->sum); + igtl::Sleep(interval); + int s2 = *(data->sum); + *(data->sum) = s1 + s2; + glock->Unlock(); + } + + return NULL; +} + +void* ThreadFunction3(void* ptr) +{ + long interval = 30; // (ms) + + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + ThreadData* data = static_cast(info->UserData); + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + int s1 = *(data->sum); + igtl::Sleep(interval); + int s2 = *(data->sum); + *(data->sum) = s1 + s2; + glock->Unlock(); + } + + return NULL; +} + +void* ThreadFunction4(void* ptr) +{ + long interval = 40; // (ms) + + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + ThreadData* data = static_cast(info->UserData); + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + int s1 = *(data->sum); + igtl::Sleep(interval); + int s2 = *(data->sum); + *(data->sum) = s1 + s2; + glock->Unlock(); + } + + return NULL; +} + + +void* ThreadFunction5(void* ptr) +{ + long interval = 50; // (ms) + + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + + ThreadData* data = static_cast(info->UserData); + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + int s1 = *(data->sum); + igtl::Sleep(interval); + int s2 = *(data->sum); + *(data->sum) = s1 + s2; + glock->Unlock(); + } + + return NULL; +} + + +int main(int , char * [] ) +{ + + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + + int sum = 1; + + ThreadData td; + td.nloop = NUM_REPEAT; + td.sum = ∑ + td.glock = glock; + + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + + threader->SetNumberOfThreads(NUM_THREAD); + threader->SetMultipleMethod(0, (igtl::ThreadFunctionType) &ThreadFunction1, &td); +#if IGTL_MAX_THREADS > 1 + threader->SetMultipleMethod(1, (igtl::ThreadFunctionType) &ThreadFunction2, &td); + threader->SetMultipleMethod(2, (igtl::ThreadFunctionType) &ThreadFunction3, &td); + threader->SetMultipleMethod(3, (igtl::ThreadFunctionType) &ThreadFunction4, &td); + threader->SetMultipleMethod(4, (igtl::ThreadFunctionType) &ThreadFunction5, &td); +#endif + threader->MultipleMethodExecute(); + + int answer = 0x00000001; + answer <<= (NUM_THREAD * NUM_REPEAT); + + //std::cerr << "sum = " << sum << " answer = " << answer << std::endl; + + if (sum == answer) + { + return EXIT_SUCCESS; + } + else + { + return EXIT_FAILURE; + } +} + + + + + diff --git a/openigtlink/repo/Testing/igtlMultiThreaderTest3.cxx b/openigtlink/repo/Testing/igtlMultiThreaderTest3.cxx new file mode 100644 index 0000000..7631da3 --- /dev/null +++ b/openigtlink/repo/Testing/igtlMultiThreaderTest3.cxx @@ -0,0 +1,133 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +//========================================================================= +// +// MultiThreader Test 1 --- Spawn Thread Test +// +// This test check the behaviour of igtl::MultiThreader::SpawnThread +// and igtl::MutexLock. +// The test create NUM_THREAD threads from a single method that repeats: +// +// s1 = s; +// sleep(interval) +// s2 = s; +// s = s1 + s2; +// +// for NUM_REPEAT times, where 's' is a global variable (shared by all +// threads) initialized with 1, and 's1', 's2' and 'interval' are local +// variables. 'interval' differs from thread to thread. +// If the threads work correctly, and the code block above is properly +// protected by a semaphore, 's' finally becomes 2^(NUM_REPEAT * NUM_THREAD-1). +// +//========================================================================= + + +#include "igtlMultiThreader.h" +#include "igtlOSUtil.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +// NOTE: (NUM_THREAD + NUM_REPEAT) < 32 on 32-bit environment +#if IGTL_MAX_THREADS > 1 + #define NUM_THREAD 5 + #define NUM_REPEAT 4 +#else + #define NUM_THREAD 1 + #define NUM_REPEAT 4 +#endif + + +typedef struct { + int nloop; + int *sum; + igtl::MutexLock::Pointer glock; +} ThreadData; + + +void* ThreadFunction(void* ptr) +{ + // Get thread information + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + int id = info->ThreadID; + + // Set interval at 100 * id (ms) + long interval = 10*id; + + ThreadData* data = static_cast(info->UserData); + int nloop = data->nloop; + igtl::MutexLock::Pointer glock = data->glock; + + for (int i = 0; i < nloop; i ++) + { + glock->Lock(); + int s1 = *(data->sum); + igtl::Sleep(interval); + int s2 = *(data->sum); + *(data->sum) = s1 + s2; + glock->Unlock(); + } + + return NULL; +} + + +int main(int , char * [] ) +{ + + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + + int sum = 1; + + ThreadData td; + td.nloop = NUM_REPEAT; + td.sum = ∑ + td.glock = glock; + + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + + int id1 = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + int id2 = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + int id3 = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + int id4 = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + int id5 = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &td); + + // wait for the threads + threader->TerminateThread(id1); + threader->TerminateThread(id2); + threader->TerminateThread(id3); + threader->TerminateThread(id4); + threader->TerminateThread(id5); + + int answer = 0x00000001; + answer <<= (NUM_THREAD * NUM_REPEAT); + + //std::cerr << "sum = " << sum << " answer = " << answer << std::endl; + + if (sum == answer) + { + return EXIT_SUCCESS; + } + else + { + return EXIT_FAILURE; + } +} + + + + + diff --git a/openigtlink/repo/Testing/igtlNDArrayMessageTest.cxx b/openigtlink/repo/Testing/igtlNDArrayMessageTest.cxx new file mode 100644 index 0000000..f0dff18 --- /dev/null +++ b/openigtlink/repo/Testing/igtlNDArrayMessageTest.cxx @@ -0,0 +1,140 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlNDArrayMessage.h" +#include "igtlutil/igtl_test_data_ndarray.h" +#include "igtl_ndarray.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +#define NDARRAY_MESSAGE_BODY_SIZE 488 + +igtl::NDArrayMessage::Pointer NDArraySendMsg = igtl::NDArrayMessage::New(); +igtl::NDArrayMessage::Pointer NDArrayReceiveMsg = igtl::NDArrayMessage::New(); +igtl::Array array; +std::vector size(3); + +void BuildUpArrayElements() +{ + size[0] = 5; + size[1] = 4; + size[2] = 3; + array.SetSize(size); + int i,j,k; + igtl_float64 arrayFloat[120]; + for (i = 0; i < size[0]; i ++) + { + for (j = 0; j < size[1]; j ++) + { + for (k = 0; k < size[2]; k ++) + { + arrayFloat[i*(4*3) + j*3 + k] = (igtl_float64) (i*(4*3) + j*3 + k); + } + } + } + array.SetArray((void*) arrayFloat); + NDArraySendMsg = igtl::NDArrayMessage::New(); + NDArraySendMsg->SetDeviceName("DeviceName"); + NDArraySendMsg->SetArray(igtl::NDArrayMessage::TYPE_FLOAT64, &array); + NDArraySendMsg->SetTimeStamp(0, 1234567892); + NDArraySendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + NDArraySendMsg->Pack(); +} + +TEST(NDArrayMessageTest, SetAndGetValue) +{ + BuildUpArrayElements(); + igtl::ArrayBase::IndexType index(array.GetSize()); + index.at(0) = 1; + index.at(1) = 2; + index.at(2) = 3; + igtl_float64 returnValue = 1.0; + array.GetValue(index, returnValue); + // The value at index(1,2,3) = (i*(4*3) + j*3 + k) = 21 + EXPECT_FLOAT_EQ(returnValue, 21); + igtl_float64 inputValue = 3.0; + array.SetValue(index, inputValue); + array.GetValue(index, returnValue); + EXPECT_FLOAT_EQ(inputValue, returnValue); +} + +TEST(NDArrayMessageTest, Pack) +{ + BuildUpArrayElements(); + + int r = memcmp((const void*)NDArraySendMsg->GetPackPointer(), (const void*)(test_ndarray_message_header), IGTL_HEADER_SIZE); + EXPECT_EQ(r, 0); + r = memcmp((const void*)NDArraySendMsg->GetPackBodyPointer(), (const void*)(test_ndarray_message_body), NDArraySendMsg->GetPackSize()-IGTL_HEADER_SIZE); + EXPECT_EQ(r, 0); +} + +TEST(NDArrayMessageTest, Unpack) +{ + BuildUpArrayElements(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)NDArraySendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + NDArrayReceiveMsg->InitPack(); + NDArrayReceiveMsg->SetMessageHeader(headerMsg); + NDArrayReceiveMsg->AllocatePack(); + memcpy(NDArrayReceiveMsg->GetPackBodyPointer(), NDArraySendMsg->GetPackBodyPointer(), NDARRAY_MESSAGE_BODY_SIZE); + NDArrayReceiveMsg->Unpack(); + + memcpy(NDArrayReceiveMsg->GetPackBodyPointer(), test_ndarray_message_body, NDArraySendMsg->GetPackSize()-IGTL_HEADER_SIZE); + NDArrayReceiveMsg->Unpack(); + igtl::ArrayBase *tempArrayBase = NDArrayReceiveMsg->GetArray(); + igtl_float64* arraytemp = (igtl_float64 *)tempArrayBase->GetRawArray(); + int i,j,k; + for (i = 0; i < size[0]; i ++) + { + for (j = 0; j < size[1]; j ++) + { + for (k = 0; k < size[2]; k ++) + { + EXPECT_EQ(i*(4*3) + j*3 + k, (igtl_float64)(*(arraytemp+i*(4*3) + j*3 + k))); + } + } + } + +} + +TEST(NDArrayMessageTest, 64BitConversion) +{ + igtl_ndarray_info info; + igtl_ndarray_init_info(&info); + info.dim = 3; + info.type = igtl::NDArrayMessage::TYPE_FLOAT64; + igtlUint16 sizeTemp[3] = {5,4,3}; + info.size = sizeTemp; + unsigned char *data = new unsigned char [480]; + memcpy(data, (const void*)(test_ndarray_message_body+8), 480); + info.array = (void*)data; + + unsigned char *dataArray = new unsigned char [488]; + igtl_ndarray_pack(&info, dataArray, IGTL_TYPE_PREFIX_NONE); + igtl_ndarray_info info_return; + igtl_ndarray_init_info(&info_return); + igtl_ndarray_unpack(IGTL_TYPE_PREFIX_NONE, dataArray, &info_return, 488); + int r = memcmp(info.array, info_return.array,480); + EXPECT_EQ(r, 0); +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlPointMessageTest.cxx b/openigtlink/repo/Testing/igtlPointMessageTest.cxx new file mode 100644 index 0000000..d88c8ac --- /dev/null +++ b/openigtlink/repo/Testing/igtlPointMessageTest.cxx @@ -0,0 +1,134 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlPointMessage.h" +#include "igtlutil/igtl_test_data_point.h" +#include "igtl_point.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +igtl::PointMessage::Pointer pointSendMsg = igtl::PointMessage::New(); +igtl::PointMessage::Pointer pointReceiveMsg = igtl::PointMessage::New(); + +igtl::PointElement::Pointer pointElement0 = igtl::PointElement::New(); +igtl::PointElement::Pointer pointElement1 = igtl::PointElement::New(); +igtl::PointElement::Pointer pointElement2 = igtl::PointElement::New(); + +void BuildUpElements() +{ + pointElement0->SetName("POINT_DESCRIPTION_0"); + pointElement0->SetGroupName("Landmark"); + pointElement0->SetRGBA(255,0,0,255); + pointElement0->SetPosition(10.0, 15.0, 20.0); + pointElement0->SetRadius(5.0); + pointElement0->SetOwner("IMAGE_0"); + pointElement1->SetName("POINT_DESCRIPTION_1"); + pointElement1->SetGroupName("Landmark"); + pointElement1->SetRGBA(0,255,0,255); + pointElement1->SetPosition(25.0, 30.0, 35.0); + pointElement1->SetRadius(3.0); + pointElement1->SetOwner("IMAGE_0"); + pointElement2->SetName("POINT_DESCRIPTION_2"); + pointElement2->SetGroupName("Landmark"); + pointElement2->SetRGBA(0,0,255,255); + pointElement2->SetPosition(40.0, 45.0, 50.0); + pointElement2->SetRadius(1.0); + pointElement2->SetOwner("IMAGE_0"); + pointSendMsg = igtl::PointMessage::New(); + pointSendMsg->SetDeviceName("DeviceName"); + pointSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + pointSendMsg->SetTimeStamp(0, 1234567892); + pointSendMsg->AddPointElement(pointElement0); + pointSendMsg->AddPointElement(pointElement1); + pointSendMsg->AddPointElement(pointElement2); + pointSendMsg->Pack(); +} + +TEST(PointMessageTest, Pack) +{ + BuildUpElements(); + int r = memcmp((const void*)pointSendMsg->GetPackPointer(), (const void*)test_point_message, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)pointSendMsg->GetPackBodyPointer(), (const void*)(test_point_message+(size_t)(IGTL_HEADER_SIZE)), IGTL_POINT_ELEMENT_SIZE*3 ); + EXPECT_EQ(r, 0); +} + + +TEST(PointMessageTest, Unpack) +{ + BuildUpElements(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), pointSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + pointReceiveMsg = igtl::PointMessage::New(); + pointReceiveMsg->SetMessageHeader(headerMsg); + pointReceiveMsg->AllocatePack(); + memcpy(pointReceiveMsg->GetPackBodyPointer(), pointSendMsg->GetPackBodyPointer(), IGTL_POINT_ELEMENT_SIZE*3); + pointReceiveMsg->Unpack(); + + igtl_header *messageHeader = (igtl_header *)pointReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "POINT"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_POINT_ELEMENT_SIZE*3); + + std::vector > groundTruthRGBA(3,std::vector(4)); + igtlUint8 tempIni1[4] = {255,0,0,255}; + groundTruthRGBA[0].assign(tempIni1,tempIni1+4); + igtlUint8 tempIni2[4] = {0,255,0,255}; + groundTruthRGBA[1].assign(tempIni2,tempIni2+4); + igtlUint8 tempIni3[4] = {0,0,255,255}; + groundTruthRGBA[2].assign(tempIni3,tempIni3+4); + + std::vector > groundTruthPos(3,std::vector(3)); + igtlFloat32 tempFloat1[3] = {10.0,15.0,20.0}; + groundTruthPos[0].assign(tempFloat1,tempFloat1+3); + igtlFloat32 tempFloat2[3] = {25.0,30.0,35.0}; + groundTruthPos[1].assign(tempFloat2,tempFloat2+3); + igtlFloat32 tempFloat3[3] = {40.0,45.0,50.0}; + groundTruthPos[2].assign(tempFloat3,tempFloat3+3); + + igtlFloat32 groundTruthRadius[3] = {5.0,3.0,1.0}; + + std::vector pointDescription; + pointDescription.push_back((char*)"POINT_DESCRIPTION_0"); + pointDescription.push_back((char*)"POINT_DESCRIPTION_1"); + pointDescription.push_back((char*)"POINT_DESCRIPTION_2"); + + for (int i = 0; i<3;++i) + { + igtl::PointElement::Pointer elem = igtl::PointElement::New(); + pointReceiveMsg->GetPointElement(i, elem); + EXPECT_EQ(strncmp((char*)(elem->GetName()), pointDescription[i], 19),0); + igtlUint8 returnedRGBA[4] ={0,0,0,0}; + elem->GetRGBA(returnedRGBA); + EXPECT_THAT(returnedRGBA, testing::ElementsAreArray(groundTruthRGBA[i])); + igtlFloat32 returnedPosition[3] ={0,0,0}; + elem->GetPosition(returnedPosition); + EXPECT_THAT(returnedPosition, testing::ElementsAreArray(groundTruthPos[i])); + EXPECT_EQ(elem->GetRadius(), groundTruthRadius[i]); + EXPECT_EQ(strncmp((char*)elem->GetOwner(), "IMAGE_0", 7),0); + } +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlPolyDataMessageTest.cxx b/openigtlink/repo/Testing/igtlPolyDataMessageTest.cxx new file mode 100644 index 0000000..3881eee --- /dev/null +++ b/openigtlink/repo/Testing/igtlPolyDataMessageTest.cxx @@ -0,0 +1,133 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlPolyDataMessage.h" +#include "igtlutil/igtl_test_data_polydata.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_polydata.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +#include + +#define POLY_BODY_SIZE 300 + +igtl::PolyDataMessage::Pointer polyDataSendMsg = igtl::PolyDataMessage::New(); +igtl::PolyDataMessage::Pointer polyDataReceiveMsg = igtl::PolyDataMessage::New(); + +igtl::PolyDataPointArray::Pointer polyPoint = igtl::PolyDataPointArray::New(); +igtl::PolyDataCellArray::Pointer polyGon = igtl::PolyDataCellArray::New(); +igtl::PolyDataAttribute::Pointer polyAttr = igtl::PolyDataAttribute::New(); + +static igtl_float32 points[8][3]={{0,0,0}, {1,0,0}, {1,1,0}, {0,1,0}, + {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1}}; +static igtl_uint32 polyArray[6][4]={{0,1,2,3}, {4,5,6,7}, {0,1,5,4}, + {1,2,6,5}, {2,3,7,6}, {3,0,4,7}}; +static igtl_float32 attribute[8]={0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; +std::vector >poly(6, std::list(4)); + +void BuildUpElements() +{ + polyPoint->Clear(); + polyGon->Clear(); + for (int i =0; i<6; i++) + { + poly[i].assign(polyArray[i],polyArray[i]+4); + } + for (int i = 0; i < 8 ;i++) + { + polyPoint->AddPoint(points[i]); + } + for (int i = 0; i < 6 ;i++) + { + polyGon->AddCell(poly[i]); + } + polyAttr->SetType(IGTL_POLY_ATTR_TYPE_SCALAR); + polyAttr->SetSize(8); + polyAttr->SetName("attr"); + polyAttr->SetData(attribute); + polyDataSendMsg = igtl::PolyDataMessage::New(); + polyDataSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + polyDataSendMsg->SetPoints(polyPoint.GetPointer()); + polyDataSendMsg->SetPolygons(polyGon.GetPointer()); + polyDataSendMsg->AddAttribute(polyAttr.GetPointer()); + polyDataSendMsg->SetDeviceName("DeviceName"); + polyDataSendMsg->SetTimeStamp(0, 1234567892); + polyDataSendMsg->Pack(); +} + +TEST(PolyDataMessageTest, Pack) +{ + BuildUpElements(); + int r = memcmp((const void*)polyDataSendMsg->GetPackPointer(), (const void*)test_polydata_message_header, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)polyDataSendMsg->GetPackBodyPointer(), (const void*)test_polydata_message_body, POLY_BODY_SIZE); + EXPECT_EQ(r, 0); +} + + +TEST(PolyDataMessageTest, Unpack) +{ + BuildUpElements(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)test_polydata_message_header, IGTL_HEADER_SIZE); + headerMsg->Unpack(); + polyDataReceiveMsg = igtl::PolyDataMessage::New(); + polyDataReceiveMsg->SetMessageHeader(headerMsg); + polyDataReceiveMsg->AllocatePack(); + igtl_header *messageHeader = (igtl_header *)polyDataReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "POLYDATA"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, POLY_BODY_SIZE); + + memcpy(polyDataReceiveMsg->GetPackBodyPointer(), polyDataSendMsg->GetPackBodyPointer(), POLY_BODY_SIZE); + polyDataReceiveMsg->Unpack(); + + igtl::PolyDataPointArray::Pointer pointUnpacked = polyDataReceiveMsg->GetPoints();; + igtl::PolyDataCellArray::Pointer polygonUnpacked = polyDataReceiveMsg->GetPolygons(); + igtl::PolyDataAttribute::Pointer attrUnpacked = polyDataReceiveMsg->GetAttribute(0); + + for (int i = 0; i<8; i++) + { + igtlFloat32 point[3] = {0,0,0}; + pointUnpacked->GetPoint(i, point); + EXPECT_TRUE(ArrayFloatComparison(point, points[i], 3, ABS_ERROR)); + } + for (int i = 0; i<6; i++) + { + igtl_uint32 polygon[4] = {0,0,0,0}; + polygonUnpacked->GetCell(i, polygon); + EXPECT_THAT(polygon, ::testing::ElementsAreArray(polyArray[i])); + } + igtl_float32 attributeValue[8]; + for (int i = 0; i<8; i++) + { + igtl_float32 value[1]; + attrUnpacked->GetNthData(i, value); + attributeValue[i] = *value; + } + EXPECT_TRUE(ArrayFloatComparison(attributeValue, attribute,8,ABS_ERROR)); +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlPositionMessageTest.cxx b/openigtlink/repo/Testing/igtlPositionMessageTest.cxx new file mode 100644 index 0000000..01acb07 --- /dev/null +++ b/openigtlink/repo/Testing/igtlPositionMessageTest.cxx @@ -0,0 +1,131 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlPositionMessage.h" +#include "igtlutil/igtl_test_data_position.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_position.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +#define PositionBodySize 28 + +igtl::PositionMessage::Pointer positionSendMsg = igtl::PositionMessage::New(); +igtl::PositionMessage::Pointer positionReceiveMsg = igtl::PositionMessage::New(); + +TEST(PositionMessageTest, PackFormateVersion1) +{ + positionSendMsg->AllocatePack(); + positionSendMsg->SetTimeStamp(0, 1234567892); + positionSendMsg->SetDeviceName("DeviceName"); + positionSendMsg->SetPosition(46.0531f, 19.4709f, 46.0531f); + positionSendMsg->SetQuaternion(0.0f, 0.5773502691f, 0.5773502692f, 0.3333333333f); + positionSendMsg->Pack(); + int r = memcmp((const void*)positionSendMsg->GetPackPointer(), (const void*)test_position_message, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)positionSendMsg->GetPackBodyPointer(), (const void*)(test_position_message+IGTL_HEADER_SIZE), PositionBodySize); + EXPECT_EQ(r, 0); +} + + +TEST(PositionMessageTest, UnpackFormateVersion1) +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)test_position_message, IGTL_HEADER_SIZE); + headerMsg->Unpack(); + positionReceiveMsg->SetMessageHeader(headerMsg); + positionReceiveMsg->AllocatePack(); + + memcpy(positionReceiveMsg->GetPackBodyPointer(), positionSendMsg->GetPackBodyPointer(), positionSendMsg->GetPackBodySize()); + positionReceiveMsg->Unpack(); + + igtl_float32 position_Truth[3] = {46.0531f, 19.4709f, 46.0531f}; + igtl_float32 position[3] = {0.0,0.0,0.0}; + positionReceiveMsg->GetPosition(position); + EXPECT_THAT(position, ::testing::ElementsAreArray(position_Truth)); + + igtl_float32 quaternion_Truth[4] = {0.0f, 0.5773502691f, 0.5773502692f, 0.3333333333f}; + igtl_float32 quaternion[4] = {0.0,0.0,0.0,0.0}; + positionReceiveMsg->GetQuaternion(quaternion); + EXPECT_THAT(quaternion, ::testing::ElementsAreArray(quaternion_Truth)); +} + + +#if OpenIGTLink_PROTOCOL_VERSION >= 3 +#include "igtlutil/igtl_test_data_positionFormat2.h" +#include "igtlMessageFormat2TestMacro.h" + +TEST(PositionMessageTest, PackFormatVersion2) +{ + positionSendMsg = igtl::PositionMessage::New(); + positionSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + positionSendMsg->AllocatePack(); + positionSendMsg->SetTimeStamp(0, 1234567892); + positionSendMsg->SetDeviceName("DeviceName"); + positionSendMsg->SetPosition(46.0531f, 19.4709f, 46.0531f); + positionSendMsg->SetQuaternion(0.0f, 0.5773502691f, 0.5773502692f, 0.3333333333f); + igtlMetaDataAddElementMacro(positionSendMsg); + positionSendMsg->Pack(); + /*FILE *fp; + fp = fopen("position.bin", "w"); + fwrite(positionSendMsg->GetPackPointer(), positionSendMsg->GetPackBodySize()+IGTL_HEADER_SIZE, 1, fp); + fclose(fp);*/ + int r = memcmp((const void*)positionSendMsg->GetPackPointer(), (const void*)test_position_messageFormat2, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)positionSendMsg->GetPackBodyPointer(), (const void*)(test_position_messageFormat2+IGTL_HEADER_SIZE),PositionBodySize + EXTENDED_CONTENT_SIZE); + EXPECT_EQ(r, 0); +} + +TEST(PositionMessageTest, UnpackFormatVersion2) +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)test_position_messageFormat2, IGTL_HEADER_SIZE); + headerMsg->Unpack(); + positionReceiveMsg = igtl::PositionMessage::New(); + positionReceiveMsg->SetMessageHeader(headerMsg); + positionReceiveMsg->AllocatePack(); + + memcpy(positionReceiveMsg->GetPackBodyPointer(), positionSendMsg->GetPackBodyPointer(), positionSendMsg->GetPackBodySize()); + positionReceiveMsg->Unpack(1); + + igtl_float32 position_Truth[3] = {46.0531f, 19.4709f, 46.0531f}; + igtl_float32 position[3] = {0.0,0.0,0.0}; + positionReceiveMsg->GetPosition(position); + for(int i = 0; i<3 ; i++) + { + EXPECT_FLOAT_EQ(position_Truth[i], position[i]); + } + + igtl_float32 quaternion_Truth[4] = {0.0f, 0.5773502691f, 0.5773502692f, 0.3333333333f}; + igtl_float32 quaternion[4] = {0.0,0.0,0.0,0.0}; + positionReceiveMsg->GetQuaternion(quaternion); + for(int i = 0; i<4 ; i++) + { + EXPECT_FLOAT_EQ(quaternion_Truth[i], quaternion[i]); + } + + igtlMetaDataComparisonMacro(positionReceiveMsg); +} + +#endif +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlSensorMessageTest.cxx b/openigtlink/repo/Testing/igtlSensorMessageTest.cxx new file mode 100644 index 0000000..653627e --- /dev/null +++ b/openigtlink/repo/Testing/igtlSensorMessageTest.cxx @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlSensorMessage.h" +#include "igtlutil/igtl_test_data_sensor.h" +#include "igtlUnit.h" +#include "igtl_sensor.h" +#include "igtl_unit.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +igtl::SensorMessage::Pointer sensorDataSendMsg = igtl::SensorMessage::New(); +igtl::SensorMessage::Pointer sensorDataReceiveMsg = igtl::SensorMessage::New(); +igtlFloat64 sensorValues[6] = {123456.78,12345.678,1234.5678,123.45678,12.345678,1.2345678}; +igtl::Unit::Pointer unit = igtl::Unit::New(); + +void UnitInitization() +{ + unit = igtl::Unit::New(); + unit->Init(); + unit->SetPrefix(IGTL_UNIT_PREFIX_NONE); + unit->Append(IGTL_UNIT_SI_BASE_METER, (igtl_int8) 1); + unit->Append(IGTL_UNIT_SI_BASE_SECOND, (igtl_int8) -2); + unit->Pack(); +} + +TEST(SensorMessageTest, Pack) +{ + UnitInitization(); + sensorDataSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + sensorDataSendMsg->AllocatePack(); + sensorDataSendMsg->SetLength(6); + sensorDataSendMsg->SetDeviceName("DeviceName"); + sensorDataSendMsg->SetTimeStamp(0, 1234567892); + + sensorDataSendMsg->SetUnit(unit); + for (int i =0; i < 6; i++) + { + sensorDataSendMsg->SetValue(i, sensorValues[i]); + } + sensorDataSendMsg->Pack(); + int r = memcmp((const void*)sensorDataSendMsg->GetPackPointer(), (const void*)test_sensor_message, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)sensorDataSendMsg->GetPackBodyPointer(), (const void*)(test_sensor_message+IGTL_HEADER_SIZE),sensorDataSendMsg->GetPackBodySize()); + EXPECT_EQ(r, 0); +} + + +TEST(SensorMessageTest, Unpack) +{ + UnitInitization(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)test_sensor_message, IGTL_HEADER_SIZE); + headerMsg->Unpack(); + sensorDataReceiveMsg = igtl::SensorMessage::New(); + sensorDataReceiveMsg->SetMessageHeader(headerMsg); + sensorDataReceiveMsg->AllocatePack(); + memcpy(sensorDataReceiveMsg->GetPackBodyPointer(), sensorDataSendMsg->GetPackBodyPointer(), 58); + sensorDataReceiveMsg->Unpack(); + + igtl::igtlUnit unitTruth = 0x443E0000000000; + EXPECT_EQ(sensorDataReceiveMsg->GetUnit(), unitTruth); + EXPECT_EQ(sensorDataReceiveMsg->GetLength(),6); + EXPECT_EQ(sensorDataReceiveMsg->GetValue(0),123456.78); + EXPECT_EQ(sensorDataReceiveMsg->GetValue(1),12345.678); + EXPECT_EQ(sensorDataReceiveMsg->GetValue(2),1234.5678); + EXPECT_EQ(sensorDataReceiveMsg->GetValue(3),123.45678); + EXPECT_EQ(sensorDataReceiveMsg->GetValue(4),12.345678); + EXPECT_EQ(sensorDataReceiveMsg->GetValue(5),1.2345678); +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlServerSocketTest.cxx b/openigtlink/repo/Testing/igtlServerSocketTest.cxx new file mode 100644 index 0000000..bf60993 --- /dev/null +++ b/openigtlink/repo/Testing/igtlServerSocketTest.cxx @@ -0,0 +1,320 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlServerSocket.h" +#include "igtlImageMessage2.h" +#include "igtlutil/igtl_test_data_image.h" +#include "igtlClientSocket.h" +#include "igtlMultiThreader.h" +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_image.h" +#include "igtl_util.h" +#include "igtlOSUtil.h" +#include "igtlTestConfig.h" +#include "string.h" + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Invoke; +using igtl::ServerSocket; +using ::testing::IsNull; + +class ServerSocketMock { +public: + //typedef igtl::SmartPointer Pointer; + //ServerSocketMock(){}; + ServerSocketMock(ServerSocket::Pointer pointer) { + real_ = pointer; + // By default, all calls are delegated to the real object. + ON_CALL(*this, CreateServer(_)) + .WillByDefault(Invoke(real_.GetPointer(), &ServerSocket::CreateServer)); + ON_CALL(*this, GetServerPort()) + .WillByDefault(Invoke(real_.GetPointer(), &ServerSocket::GetServerPort)); + ON_CALL(*this, WaitForConnection(_)) + .WillByDefault(Invoke(real_.GetPointer(), &ServerSocket::WaitForConnection)); + ON_CALL(*this, Send(_,_)) + .WillByDefault(Invoke(real_.GetPointer(), &ServerSocket::Send)); + } + ~ServerSocketMock(){real_.~SmartPointer();}; + ServerSocket::Pointer getPointer(){return real_;}; + void setPointer(ServerSocket::Pointer server){real_ = server;}; + MOCK_METHOD0(GetServerPort, int()); + MOCK_METHOD1(CreateServer, int(int port)); + MOCK_METHOD1(WaitForConnection, igtl::ClientSocket::Pointer(unsigned long msec)); + MOCK_METHOD2(Send, int(const void* data, int length)); +private: + ServerSocket::Pointer real_; + +}; +void* ThreadFunction(void* ptr); +int ReceiveImageData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header); +class StopImageSendingMessage: public igtl::MessageBase +{ +public: + igtlTypeMacro(StopImageSendingMessage, igtl::MessageBase); + igtlNewMacro(StopImageSendingMessage); + +protected: + StopImageSendingMessage() : MessageBase() { this->m_SendMessageType = "STP_IMAGE"; }; + ~StopImageSendingMessage() {}; + +protected: + virtual int GetBodyPackSize() { return 0; }; + virtual int PackBody() { AllocatePack(); return 1; }; + virtual int UnpackBody() { return 1; }; + +}; + +class StartImageSendingMessage: public igtl::MessageBase +{ +public: + typedef StartImageSendingMessage Self; + typedef MessageBase Superclass; + typedef igtl::SmartPointer Pointer; + typedef igtl::SmartPointer ConstPointer; + + igtlTypeMacro(StartImageSendingMessage, igtl::MessageBase); + igtlNewMacro(StartImageSendingMessage); + +protected: + StartImageSendingMessage() : MessageBase() { this->m_SendMessageType = "STT_IMAGE"; }; + ~StartImageSendingMessage() {}; + +protected: + virtual int GetBodyPackSize() { return 0; }; + virtual int PackBody() { AllocatePack(); return 1; }; + virtual int UnpackBody() { return 1; }; + +}; + + +igtl::ImageMessage2::Pointer imageMessage2Test = igtl::ImageMessage2::New(); +long interval = 200; +int threadID; +int port = 18944; +int size[] = {50, 50, 1}; // image dimension +float spacing[] = {1.0, 1.0, 5.0}; // spacing (mm/pixel) +int svsize[] = {50, 50, 1}; // sub-volume size +int svoffset[] = {0, 0, 0}; // sub-volume offset +int scalarType = igtl::ImageMessage2::TYPE_UINT8;// scalar type +void setupTest() +{ + //Initialization of a image message + imageMessage2Test->SetDimensions(size); + imageMessage2Test->SetSpacing(spacing); + imageMessage2Test->SetScalarType(scalarType); + imageMessage2Test->SetDeviceName("Image"); + imageMessage2Test->SetSubVolume(svsize, svoffset); + imageMessage2Test->AllocateBuffer(IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE); + imageMessage2Test->AllocateScalars(); + memcpy((void*)imageMessage2Test->GetPackBodyPointer(), test_image_message+IGTL_HEADER_SIZE, IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE);//here m_Body is set. + imageMessage2Test->SetScalarPointer((void*)test_image); + imageMessage2Test->Pack(); +} + +TEST(ServerSocketTest, ConnectionAndSending) +{ + igtl::ServerSocket::Pointer tempServerSocket = igtl::ServerSocket::New(); + ServerSocketMock mockServerSocket(tempServerSocket); + EXPECT_CALL(mockServerSocket, CreateServer(port)).Times(1); + int waitingTime = 3000; + //EXPECT_CALL(*mockServerSocket, GetServerPort()).Times(1); + //EXPECT_CALL(*mockServerSocket, WaitForConnection(_)).Times(2); + //EXPECT_CALL(*mockServerSocket, Send(_,_)).Times(0); + //mockServerSocket.GetServerPort(); + int bCreation = mockServerSocket.CreateServer(port); + EXPECT_EQ(bCreation,0); + if(1==0) + { + igtl::ClientSocket::Pointer returnSocket = mockServerSocket.WaitForConnection(waitingTime); + /**Connecting to a established server, however, time out happened, return NULL */ + EXPECT_TRUE(returnSocket.IsNull()); + //EXPECT_EQ(mockServerSocket->CreateServer(port),-1); + //----------------------- + //Use multi threader to create a subprocess, which connects to the server. + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + int loop = 0; + threadID = threader->SpawnThread((igtl::ThreadFunctionType) &ThreadFunction, &mockServerSocket); + igtl::ClientSocket::Pointer clientSocket; + clientSocket = igtl::ClientSocket::New(); + bool notConnected = true; + while(notConnected) + { + int r = clientSocket->ConnectToServer("localhost", port); + if(r!=0) + { + continue; + } + else + { + notConnected=false; + } + } + StartImageSendingMessage::Pointer StartImageSending; + StartImageSending = StartImageSendingMessage::New(); + StartImageSending->Pack(); + clientSocket->Send(StartImageSending->GetPackPointer(), StartImageSending->GetPackSize()); + + while(1) + { + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + int rs = clientSocket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize()); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + clientSocket->CloseSocket(); + exit(0); + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceName(),"Image")== 0) + { + ReceiveImageData(clientSocket, headerMsg); + } + else + { + EXPECT_TRUE(false)<< "Receiving : " << headerMsg->GetDeviceName() << std::endl; + clientSocket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + if (++loop >= 10) // if received 10 times + { + StopImageSendingMessage::Pointer StopImageSending; + StopImageSending = StopImageSendingMessage::New(); + StopImageSending->Pack(); + clientSocket->Send(StopImageSending->GetPackPointer(), StopImageSending->GetPackSize()); + threadID = -1; + break; + //---------------------------------------- + } + } + } + else + { + mockServerSocket.getPointer()->CloseSocket(); + } + //delete mockServerSocket; + //clientSocket::send +} + + +int ReceiveImageData(igtl::ClientSocket::Pointer& socket, igtl::MessageHeader::Pointer& header) +{ + std::cerr << "Receiving QTDATA data type." << std::endl; + + igtl::ImageMessage2::Pointer imageData; + imageData = igtl::ImageMessage2::New(); + imageData->SetDimensions(size); + imageData->SetSpacing(spacing); + imageData->SetScalarType(scalarType); + imageData->SetSubVolume(svsize, svoffset); + imageData->AllocateBuffer(IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE); + imageData->AllocateScalars(); + // Receive imageHeader from the socket + socket->Receive(imageData->GetPackBodyPointer(), imageData->GetPackBodySize()); + + // Deserialize position and quaternion (orientation) data + // If you want to skip CRC check, call Unpack() without argument. + int c = imageData->Unpack(); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + std::cout << "================================" << std::endl; + std::cout << " Name : " << imageData->GetDeviceType(); + std::cout << "================================" << std::endl; + } + return 1; +} + + +void* ThreadFunction(void* ptr) +{ + //------------------------------------------------------------ + // Get the server socket + igtl::MultiThreader::ThreadInfo* info = + static_cast(ptr); + ServerSocketMock* mockServerSocket = static_cast(info->UserData); + + //------------------------------------------------------------ + // Get user data + std::cout << "Interval = " << interval << " (ms)" << std::endl; + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + //------------------------------------------------------------ + // Loop + igtl::Socket::Pointer socket; + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + socket = mockServerSocket->WaitForConnection(10000); + if (socket.IsNotNull()) + { + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + for (;;) + { + headerMsg->InitPack(); + int rs = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize()); + if (rs == 0) + { + EXPECT_TRUE(false) << "Disconnecting the client."; + socket->CloseSocket(); + break; + } + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "StartSending") == 0) + { + while(!(threadID==-1)) + { + glock->Lock(); + for (int i = 0; i < imageMessage2Test->GetNumberOfPackFragments(); i ++) + { + socket->Send(imageMessage2Test->GetPackFragmentPointer(i), imageMessage2Test->GetPackFragmentSize(i)); + } + glock->Unlock(); + igtl::Sleep(interval); + } + } + else if (strcmp(headerMsg->GetDeviceType(), "StopSending") == 0) + { + std::cerr << "Received a stop message." << std::endl; + socket->CloseSocket(); + break; + } + } + } + else + { + EXPECT_TRUE(false) << "No client connected."; + } + delete mockServerSocket; + return NULL; +} + +int main(int argc, char **argv) +{ + setupTest(); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlSocketTest.cxx b/openigtlink/repo/Testing/igtlSocketTest.cxx new file mode 100644 index 0000000..2f09544 --- /dev/null +++ b/openigtlink/repo/Testing/igtlSocketTest.cxx @@ -0,0 +1,284 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlServerSocket.h" +#include "igtlSocket.h" +#include "igtlMessageHeader.h" +#include "igtlClientSocket.h" +#include "igtlMultiThreader.h" +#include "igtlQuaternionTrackingDataMessage.h" + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_util.h" +#include "igtlOSUtil.h" +#include "igtlTestConfig.h" +#include "string.h" + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::Invoke; +using igtl::ServerSocket; +using igtl::ClientSocket; +using igtl::Socket; +using ::testing::IsNull; + + +class SocketMock { +public: + SocketMock(Socket::Pointer pointer) { + real_ = pointer; + // By default, all calls are delegated to the real object. + ON_CALL(*this, GetConnected()) + .WillByDefault(Invoke(real_.GetPointer(), &Socket::GetConnected)); + ON_CALL(*this, Send(_,_)) + .WillByDefault(Invoke(real_.GetPointer(), &Socket::Send)); + ON_CALL(*this, Receive(_,_,_)) + .WillByDefault(Invoke(real_.GetPointer(), &Socket::Receive)); + ON_CALL(*this, SetTimeout(_)) + .WillByDefault(Invoke(real_.GetPointer(), &Socket::SetTimeout)); + ON_CALL(*this, SetReceiveTimeout(_)) + .WillByDefault(Invoke(real_.GetPointer(), &Socket::SetReceiveTimeout)); + ON_CALL(*this, SetSendTimeout(_)) + .WillByDefault(Invoke(real_.GetPointer(), &Socket::SetSendTimeout)); + ON_CALL(*this, SetReceiveBlocking(_)) + .WillByDefault(Invoke(real_.GetPointer(), &Socket::SetReceiveBlocking)); + ON_CALL(*this, SetSendBlocking(_)) + .WillByDefault(Invoke(real_.GetPointer(), &Socket::SetSendBlocking)); + ON_CALL(*this, GetSocketAddressAndPort(_,_)) + .WillByDefault(Invoke(real_.GetPointer(), &Socket::GetSocketAddressAndPort)); + ON_CALL(*this, Skip(_,_)) + .WillByDefault(Invoke(real_.GetPointer(), &Socket::Skip)); + } + ~SocketMock(){real_.~SmartPointer();}; + Socket::Pointer getPointer(){return real_;}; + + MOCK_METHOD0(GetConnected, int()); + MOCK_METHOD1(SetTimeout, int(int timeout)); + MOCK_METHOD1(SetReceiveTimeout, int(int timeout)); + MOCK_METHOD1(SetSendTimeout, int(int timeout)); + MOCK_METHOD1(SetReceiveBlocking, int(int sw)); + MOCK_METHOD1(SetSendBlocking, int(int sw)); + MOCK_METHOD2(Send, int(const void* data, int length)); + MOCK_METHOD2(GetSocketAddressAndPort, int(std::string& address, int& port)); + MOCK_METHOD2(Skip, int(int length, int skipFully)); + MOCK_METHOD3(Receive, int(void* data, int length, int readFully)); + +private: + Socket::Pointer real_; + +}; +void* TestThreadFunction(void* ptr); +int ReceiveQuaternionTrackingData(ClientSocket::Pointer socket, igtl::MessageHeader::Pointer& header); +void clientServerProcess(); + +long interval = 200; +int threadID; +int port = 18944; +bool threadrunning = false; +bool msgReceived = true; +TEST(SocketTest, GeneralTest) +{ + igtl::MultiThreader::Pointer threader = igtl::MultiThreader::New(); + threadID = threader->SpawnThread((igtl::ThreadFunctionType) &TestThreadFunction, NULL); + clientServerProcess(); + while(threadrunning) + { + igtl::Sleep(interval); + }; +} + +void* TestThreadFunction(void* ptr) +{ + threadrunning = true; + igtl::MutexLock::Pointer glock = igtl::MutexLock::New(); + int waitingTime = 3000; + ServerSocket::Pointer serverSocket = ServerSocket::New(); + serverSocket->CreateServer(port); + SocketMock socketMock(static_cast(serverSocket->WaitForConnection(10*waitingTime))); + EXPECT_CALL(socketMock, GetConnected()).Times(1); + //The send command is called 10 times, it keep on sending at an interval(200ms) until a stop command is received. + EXPECT_CALL(socketMock, Send(_,_)).Times(10); + // Receive function should be called three times, the start command header, the start command body, and the stop command + EXPECT_CALL(socketMock, Receive(_,_,_)).Times(3); + EXPECT_CALL(socketMock, SetTimeout(_)).Times(0); + EXPECT_CALL(socketMock, SetSendTimeout(_)).Times(0); + if (socketMock.getPointer().IsNotNull()) + { + EXPECT_GT(socketMock.GetConnected(),0); + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + for (;;) + { + headerMsg->InitPack(); + int rs = socketMock.Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), 0); + if (rs != headerMsg->GetPackSize()) + { + continue; + } + + // Deserialize the header + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "STT_QTDATA") == 0) + { + std::cerr << "Received a STT_QTDATA message." << std::endl; + + igtl::StartQuaternionTrackingDataMessage::Pointer startQuaternionTracking; + startQuaternionTracking = igtl::StartQuaternionTrackingDataMessage::New(); + startQuaternionTracking->SetMessageHeader(headerMsg); + startQuaternionTracking->AllocatePack(); + + socketMock.Receive(startQuaternionTracking->GetPackBodyPointer(), startQuaternionTracking->GetPackBodySize(),0); + int c = startQuaternionTracking->Unpack(1); + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + igtl::QuaternionTrackingDataMessage::Pointer quaternionTrackingMsg; + quaternionTrackingMsg = igtl::QuaternionTrackingDataMessage::New(); + quaternionTrackingMsg->SetDeviceName("Tracker"); + igtl::QuaternionTrackingDataElement::Pointer quaternionTrackElement0; + quaternionTrackElement0 = igtl::QuaternionTrackingDataElement::New(); + quaternionTrackElement0->SetName("Channel 0"); + quaternionTrackElement0->SetType(igtl::QuaternionTrackingDataElement::TYPE_TRACKER); + quaternionTrackingMsg->AddQuaternionTrackingDataElement(quaternionTrackElement0); + while(!(threadID==-1)) + { + if(msgReceived) + { + glock->Lock(); + quaternionTrackingMsg->Pack(); + socketMock.Send(quaternionTrackingMsg->GetPackPointer(), quaternionTrackingMsg->GetPackSize()); + glock->Unlock(); + msgReceived = false; + } + igtl::Sleep(interval); + } + } + } + else if (strcmp(headerMsg->GetDeviceType(), "STP_QTDATA") == 0) + { + std::cerr << "Received a stop message." << std::endl; + socketMock.getPointer()->CloseSocket(); + threadrunning = false; + break; + } + } + } + else + { + EXPECT_TRUE(false) << "No client connected."; + } + return NULL; +} + +void clientServerProcess() +{ + igtl::ClientSocket::Pointer clientSocket; + clientSocket = igtl::ClientSocket::New(); + bool notConnected = true; + while(notConnected) + { + int r = clientSocket->ConnectToServer("localhost", port); + if(r!=0) + { + continue; + } + else + { + notConnected=false; + } + } + //socketMock.setPointer(clientSocket); + igtl::StartQuaternionTrackingDataMessage::Pointer startQuaternionTrackingMsg; + startQuaternionTrackingMsg = igtl::StartQuaternionTrackingDataMessage::New(); + startQuaternionTrackingMsg->SetDeviceName("QTDataClient"); + startQuaternionTrackingMsg->SetResolution(interval); + startQuaternionTrackingMsg->SetCoordinateName("Patient"); + startQuaternionTrackingMsg->Pack(); + clientSocket->Send(startQuaternionTrackingMsg->GetPackPointer(), startQuaternionTrackingMsg->GetPackSize()); + int loop = 0; + while (1) + { + //------------------------------------------------------------ + // Wait for a reply + igtl::Sleep(interval); + igtl::MessageHeader::Pointer headerMsg; + headerMsg = igtl::MessageHeader::New(); + headerMsg->InitPack(); + int rs = clientSocket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(),0); + if (rs == 0) + { + std::cerr << "Connection closed." << std::endl; + clientSocket->CloseSocket(); + exit(0); + } + headerMsg->Unpack(); + if (strcmp(headerMsg->GetDeviceType(), "QTDATA") == 0) + { + ReceiveQuaternionTrackingData(clientSocket, headerMsg); + msgReceived = true; + } + else + { + std::cerr << "Receiving : " << headerMsg->GetDeviceType() << std::endl; + clientSocket->Skip(headerMsg->GetBodySizeToRead(), 0); + } + if (++loop >= 10) // if received 11 times + { + //------------------------------------------------------------ + // Ask the server to stop pushing quaternion tracking data + std::cerr << "Sending STP_QTDATA message....." << std::endl; + igtl::StopQuaternionTrackingDataMessage::Pointer stopQuaternionTrackingMsg; + stopQuaternionTrackingMsg = igtl::StopQuaternionTrackingDataMessage::New(); + stopQuaternionTrackingMsg->SetDeviceName("QTDataClient"); + stopQuaternionTrackingMsg->Pack(); + clientSocket->Send(stopQuaternionTrackingMsg->GetPackPointer(), stopQuaternionTrackingMsg->GetPackSize()); + threadID = -1; + break; + } + } +} + +int ReceiveQuaternionTrackingData(ClientSocket::Pointer socket, igtl::MessageHeader::Pointer& header) +{ + std::cerr << "Receiving QTDATA data type." << std::endl; + + //------------------------------------------------------------ + // Allocate QuaternionTrackingData Message Class + + igtl::QuaternionTrackingDataMessage::Pointer quaternionTrackingData; + quaternionTrackingData = igtl::QuaternionTrackingDataMessage::New(); + quaternionTrackingData->SetMessageHeader(header); + quaternionTrackingData->AllocatePack(); + + // Receive body from the socket + socket->Receive(quaternionTrackingData->GetPackBodyPointer(), quaternionTrackingData->GetPackBodySize(),0); + + // Deserialize position and quaternion (orientation) data + // If you want to skip CRC check, call Unpack() without argument. + int c = quaternionTrackingData->Unpack(1); + + if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK + { + int nElements = quaternionTrackingData->GetNumberOfQuaternionTrackingDataElements(); + EXPECT_EQ(nElements, 1); + return 1; + } + return 0; +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlStatusMessageTest.cxx b/openigtlink/repo/Testing/igtlStatusMessageTest.cxx new file mode 100644 index 0000000..b04178f --- /dev/null +++ b/openigtlink/repo/Testing/igtlStatusMessageTest.cxx @@ -0,0 +1,98 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlStatusMessage.h" +#include "igtlutil/igtl_test_data_status.h" +#include "string.h" +#include "igtl_status.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + + +igtl::StatusMessage::Pointer statusSendMsg = igtl::StatusMessage::New(); +igtl::StatusMessage::Pointer statusReceiveMsg = igtl::StatusMessage::New(); + +#define STR_ERROR_NAME "ACTUATOR_DISABLED" /* within 20 characters */ +#define STR_ERROR_MESSAGE "Actuator A is disabled." + +TEST(StatusMessageTest, Pack) +{ + std::string statusString = "randomstringrandomstring"; + statusSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + statusSendMsg->SetStatusString(statusString.c_str());// pass an empty string with size 54,just to initialize the memory + statusSendMsg->AllocatePack(); + statusSendMsg->SetTimeStamp(0, 1234567892); + statusSendMsg->SetDeviceName("DeviceName"); + statusSendMsg->SetCode(IGTL_STATUS_DISABLED); + statusSendMsg->SetSubCode(0x0A); + statusSendMsg->SetErrorName(STR_ERROR_NAME); + statusSendMsg->SetStatusString(STR_ERROR_MESSAGE); + statusSendMsg->Pack(); + int r = memcmp((const void*)statusSendMsg->GetPackPointer(), (const void*)test_status_message, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)statusSendMsg->GetPackBodyPointer(), (const void*)(test_status_message+IGTL_HEADER_SIZE),statusSendMsg->GetPackBodySize()); + EXPECT_EQ(r, 0); +} + + +TEST(StatusMessageTest, Unpack) +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), statusSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + statusReceiveMsg->SetMessageHeader(headerMsg); + statusReceiveMsg->AllocatePack(); + memcpy(statusReceiveMsg->GetPackBodyPointer(), statusSendMsg->GetPackBodyPointer(), statusSendMsg->GetPackBodySize()); + statusReceiveMsg->Unpack(); + + EXPECT_EQ(statusReceiveMsg->GetCode(),IGTL_STATUS_DISABLED); + EXPECT_EQ(statusReceiveMsg->GetSubCode(),(igtlInt64)0x0A); + EXPECT_STREQ(statusReceiveMsg->GetErrorName(),STR_ERROR_NAME); + EXPECT_STREQ(statusReceiveMsg->GetStatusString(),STR_ERROR_MESSAGE); +} + + +#if OpenIGTLink_HEADER_VERSION >= 2 +TEST(StatusMessageTest, UnpackInvalidMetaData) +{ + statusSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + statusSendMsg->SetMetaDataElement("metaData1", 1); + statusSendMsg->AllocatePack(); + statusSendMsg->Pack(); + + // set an invalid meta data element number to force wrong memory access + ((char*)statusSendMsg->GetBufferPointer())[statusSendMsg->GetBufferSize() - 13] = 20; + + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), statusSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + + statusReceiveMsg->SetMessageHeader(headerMsg); + statusReceiveMsg->AllocatePack(); + memcpy(statusReceiveMsg->GetPackBodyPointer(), statusSendMsg->GetPackBodyPointer(), statusSendMsg->GetPackBodySize()); + + EXPECT_NE(statusReceiveMsg->Unpack(), igtl::MessageBase::UNPACK_BODY); +} +#endif + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlStringMessageTest.cxx b/openigtlink/repo/Testing/igtlStringMessageTest.cxx new file mode 100644 index 0000000..d0106ac --- /dev/null +++ b/openigtlink/repo/Testing/igtlStringMessageTest.cxx @@ -0,0 +1,67 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlStringMessage.h" +#include "igtlutil/igtl_test_data_string.h" +#include "igtl_string.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +#define IGTL_STRING_TEST_STRING "Welcome to OpenIGTLink" +#define IGTL_STRING_TEST_STRING_LEN 22 + +igtl::StringMessage::Pointer stringSendMsg = igtl::StringMessage::New(); +igtl::StringMessage::Pointer stringReceiveMsg = igtl::StringMessage::New(); + +TEST(StringMessageTest, Pack) +{ + stringSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + stringSendMsg->SetString(IGTL_STRING_TEST_STRING); + stringSendMsg->AllocatePack(); + stringSendMsg->SetTimeStamp(0, 1234567892); + stringSendMsg->SetDeviceName("DeviceName"); + stringSendMsg->SetEncoding(3); + stringSendMsg->Pack(); + int r = memcmp((const void*)stringSendMsg->GetPackPointer(), (const void*)test_string_message, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)stringSendMsg->GetPackBodyPointer(), (const void*)(test_string_message+IGTL_HEADER_SIZE),stringSendMsg->GetPackBodySize()); + EXPECT_EQ(r, 0); +} + + +TEST(StringMessageTest, Unpack) +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)test_string_message, IGTL_HEADER_SIZE); + headerMsg->Unpack(); + stringReceiveMsg->SetMessageHeader(headerMsg); + stringReceiveMsg->AllocatePack(); + + memcpy(stringReceiveMsg->GetPackBodyPointer(), stringSendMsg->GetPackBodyPointer(), stringSendMsg->GetPackBodySize()); + stringReceiveMsg->Unpack(); + + EXPECT_EQ(stringReceiveMsg->GetEncoding(),3); + EXPECT_STREQ(stringReceiveMsg->GetString(),IGTL_STRING_TEST_STRING); + +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlTestConfig.h.in b/openigtlink/repo/Testing/igtlTestConfig.h.in new file mode 100644 index 0000000..08c34c0 --- /dev/null +++ b/openigtlink/repo/Testing/igtlTestConfig.h.in @@ -0,0 +1,281 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +// +// This header file switches the definition of TEST() macro. It includes +// gtest.h if GTest supports the platform. Otherwise, this header file defines +// its own TEST() macro. +// +// This is a temporary workaround for the GTest issues in Windows. For long term, +// we will switch entirely to the GTest. +// + +#cmakedefine OpenIGTLink_USE_GTEST + +#if defined(OpenIGTLink_USE_GTEST) + #include "gtest/gtest.h" + #include "gmock/gmock.h" +#else + +#include +#include +#include +#ifdef _WIN32 +#include +#endif + +#define TEST_FAILURE 1 +#define TEST_SUCCESS 0 + +// void function to skip InitGoogleTest() call +namespace testing { + void InitGoogleTest(int* argc, char **argv) {} + + // Implements ElementsAreArray(). + template + class IGTLCommon_EXPORT ElementsAreArrayMatcher + { + public: + ElementsAreArrayMatcher(::std::vector a); + int Compare(::std::vector b); + int Compare(const T* b); + + private: + ::std::vector arrayA; + }; + + template + ElementsAreArrayMatcher::ElementsAreArrayMatcher(::std::vector a) + { + this->arrayA = a; + } + + template + int ElementsAreArrayMatcher::Compare(::std::vector b) + { + typename ::std::vector::iterator iterA = arrayA.begin(); + typename ::std::vector::iterator iterB = b.begin(); + while( iterA!=arrayA.end() && iterB!=b.end()) + { + if ((*iterA-*iterB)>1e-6 || (*iterA-*iterB)<-1e-6) + { + return 0; + } + iterA ++; + iterB ++; + } + return 1; + } + + template + int ElementsAreArrayMatcher::Compare(const T* b) + { + int N = arrayA; + for (int i = 0; i < N; i ++) + { + if ((arrayA[i] - b[i])>1e-6 || (arrayA[i] - b[i])<-1e-6) + { + return 0; + } + } + return 1; + } + + template + inline ElementsAreArrayMatcher ElementsAreArray(::std::vector & array) + { + return ElementsAreArrayMatcher(array); + } + + template + inline ElementsAreArrayMatcher ElementsAreArray(const T (&array)[N]) + { + ::std::vector vec; + for (int i = 0; i < N; i ++) vec.push_back(array[i]); + return ElementsAreArrayMatcher(vec); + } + + class IGTLCommon_EXPORT TestBase { + public: + virtual void Run() = 0; + + inline ::std::string GetCaseName() { return caseName; } + inline ::std::string GetTestName() { return testName; } + inline int GetResult() { return result; } + + protected: + ::std::string caseName; + ::std::string testName; + int result; + }; + + class IGTLCommon_EXPORT TestInfo { + public: + int Add( TestBase* ); + int Run(); + private: + static ::std::vector< TestBase* > TestList; + }; + + ::std::vector< TestBase* > TestInfo::TestList; + + TestInfo testInfo; + + int TestInfo::Add( TestBase* test ) + { + TestInfo::TestList.push_back(test); + return 1; + } + + int TestInfo::Run() + { + ::std::vector< TestBase* >::iterator iter; + + int result = TEST_SUCCESS; + for (iter = TestInfo::TestList.begin(); iter != TestInfo::TestList.end(); iter ++) + { + (*iter)->Run(); + if ((*iter)->GetResult() == TEST_FAILURE) + { + std::cerr << "[ERROR] "; + result = TEST_FAILURE; + } + else + { + std::cerr << "[ OK ] "; + } + std::cerr << (*iter)->GetCaseName() << "."; + std::cerr << (*iter)->GetTestName() << std::endl; + } + + return result; + + } + +} + + +#define EXPECT_EQ(a, b) \ + if (a != b) \ + { \ + this->result = TEST_FAILURE; \ + return; \ + } + +#define EXPECT_NE(a, b) \ + if (a == b) \ + { \ + this->result = TEST_FAILURE; \ + return; \ + } + +#define EXPECT_LT(a, b) \ + if (a >= b) \ + { \ + this->result = TEST_FAILURE; \ + return; \ + } + +#define EXPECT_NEAR(a, b, err) \ + if ((a-b) >= err || (a-b) <= -err) \ + { \ + this->result = TEST_FAILURE; \ + return; \ + } + +#define EXPECT_FLOAT_EQ(a, b) \ + if ((a-b) > 1e-6 || (a-b) < -1e-6) \ + { \ + this->result = TEST_FAILURE; \ + return; \ + } + +#define EXPECT_STREQ(a, b) \ + if (strcmp(a, b) != 0) \ + { \ + this->result = TEST_FAILURE; \ + return; \ + } + +#ifdef _WIN32 +#define EXPECT_THAT(a, comp) \ + { \ + const int N = sizeof(a)/sizeof(a[0]); \ + auto dataType = a[0]; \ + testing::ElementsAreArrayMatcher< decltype(dataType) > matcher = comp; \ + ::std::vector< decltype(dataType) > vecA; \ + for (int i = 0; i < N; i ++) vecA.push_back(a[i]); \ + if (!matcher.Compare(vecA)) \ + { \ + this->result = TEST_FAILURE; \ + return; \ + } \ + } +#else +#define EXPECT_THAT(a, comp) \ + { \ + const int N = sizeof(a)/sizeof(a[0]); \ + std::string dataType = typeid(a[0]).name(); \ + testing::ElementsAreArrayMatcher< typeof(a[0]) > matcher = comp; \ + ::std::vector< typeof(a[0]) > vecA; \ + for (int i = 0; i < N; i ++) vecA.push_back(a[i]); \ + if (!matcher.Compare(vecA)) \ + { \ + this->result = TEST_FAILURE; \ + return; \ + } \ + } +#endif + +#define EXPECT_TRUE(a) \ + if (a != true) \ + { \ + this->result = TEST_FAILURE; \ + return; \ + } + +#define TEST(test_case_name, test_name) \ + class IGTLCommon_EXPORT test_case_name##_##test_name##_Test : ::testing::TestBase { \ + public: \ + test_case_name##_##test_name##_Test(); \ + void Run(); \ + }; \ + test_case_name##_##test_name##_Test instance_##test_case_name##_##test_name##_Test; \ + test_case_name##_##test_name##_Test::test_case_name##_##test_name##_Test() \ + { \ + ::testing::testInfo.Add(this); \ + caseName = #test_case_name; \ + testName = #test_name; \ + } \ + void test_case_name##_##test_name##_Test::Run() + + +inline int RUN_ALL_TESTS() { + if (::testing::testInfo.Run() == TEST_FAILURE) + { + return 1; + } + else + { + return 0; + } +} + + +/// TestList.push_back(new test_case_name##_##test_name##_Test) \ + + +#endif + + + diff --git a/openigtlink/repo/Testing/igtlTimeStampTest1.cxx b/openigtlink/repo/Testing/igtlTimeStampTest1.cxx new file mode 100644 index 0000000..8fe0e22 --- /dev/null +++ b/openigtlink/repo/Testing/igtlTimeStampTest1.cxx @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#include + +int main(int, char * [] ) +{ + // Simply testing Setter/Getter + igtl::TimeStamp::Pointer ts = igtl::TimeStamp::New(); + ts->GetTime(); + + igtlUint64 totalNanosSinceEpochBefore = ts->GetTimeStampInNanoseconds(); + ts->SetTime(0.0); + ts->SetTimeInNanoseconds(totalNanosSinceEpochBefore); + + igtlUint64 totalNanosSinceEpochAfter = ts->GetTimeStampInNanoseconds(); + if (totalNanosSinceEpochAfter != totalNanosSinceEpochBefore) + { + std::cerr << "Expected totalNanosSinceEpochBefore=" << totalNanosSinceEpochBefore << " to equal totalNanosSinceEpochAfter=" << totalNanosSinceEpochAfter << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + + + + + diff --git a/openigtlink/repo/Testing/igtlTrackingDataMessageTest.cxx b/openigtlink/repo/Testing/igtlTrackingDataMessageTest.cxx new file mode 100644 index 0000000..27d78a1 --- /dev/null +++ b/openigtlink/repo/Testing/igtlTrackingDataMessageTest.cxx @@ -0,0 +1,252 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlTrackingDataMessage.h" +#include "igtlutil/igtl_test_data_tdata.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_tdata.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +igtl::TrackingDataMessage::Pointer trackingSendMsg = igtl::TrackingDataMessage::New(); +igtl::TrackingDataMessage::Pointer trackingReceiveMsg = igtl::TrackingDataMessage::New(); + +igtl::TrackingDataElement::Pointer trackingElement0 = igtl::TrackingDataElement::New(); +igtl::TrackingDataElement::Pointer trackingElement1 = igtl::TrackingDataElement::New(); +igtl::TrackingDataElement::Pointer trackingElement2 = igtl::TrackingDataElement::New(); +igtl::TrackingDataElement::Pointer trackingElement3 = igtl::TrackingDataElement::New(); + +float inT[4] = {-0.954892f, 0.196632f, -0.222525f, 0.0}; +float inS[4] = {-0.196632f, 0.142857f, 0.970014f, 0.0}; +float inN[4] = {0.222525f, 0.970014f, -0.0977491f, 0.0}; +float inOrigin[4] = {46.0531f,19.4709f,46.0531f, 1.0}; +igtl::Matrix4x4 inMatrix = {{inT[0],inS[0],inN[0],inOrigin[0]}, + {inT[1],inS[1],inN[1],inOrigin[1]}, + {inT[2],inS[2],inN[2],inOrigin[2]}, + {inT[3],inS[3],inN[3],inOrigin[3]}}; + +void BuildUpElements() +{ + trackingElement0->SetName("Tracker0"); + trackingElement0->SetType(IGTL_TDATA_TYPE_6D); + trackingElement0->SetMatrix(inMatrix); + + trackingElement1->SetName("Tracker1"); + trackingElement1->SetType(IGTL_TDATA_TYPE_6D); + trackingElement1->SetMatrix(inMatrix); + + trackingElement2->SetName("Tracker2"); + trackingElement2->SetType(IGTL_TDATA_TYPE_6D); + trackingElement2->SetMatrix(inMatrix); + + trackingSendMsg = igtl::TrackingDataMessage::New(); + trackingSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + trackingSendMsg->SetDeviceName("DeviceName"); + trackingSendMsg->SetTimeStamp(0, 1234567892); + trackingSendMsg->AddTrackingDataElement(trackingElement0); + trackingSendMsg->AddTrackingDataElement(trackingElement1); + trackingSendMsg->AddTrackingDataElement(trackingElement2); +} + +TEST(TrackingMessageTest, Pack) +{ + BuildUpElements(); + trackingSendMsg->Pack(); + int r = memcmp((const void*)trackingSendMsg->GetPackPointer(), (const void*)test_tdata_message, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)trackingSendMsg->GetPackBodyPointer(), (const void*)(test_tdata_message+(size_t)(IGTL_HEADER_SIZE)), IGTL_TDATA_ELEMENT_SIZE*3 ); + EXPECT_EQ(r, 0); +} + + +TEST(TrackingMessageTest, Unpack) +{ + BuildUpElements(); + trackingSendMsg->Pack(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)trackingSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + trackingReceiveMsg->SetMessageHeader(headerMsg); + trackingReceiveMsg->AllocatePack(); + memcpy(trackingReceiveMsg->GetPackBodyPointer(), trackingSendMsg->GetPackBodyPointer(), IGTL_TDATA_ELEMENT_SIZE*3); + trackingReceiveMsg->Unpack(); + igtl_header *messageHeader = (igtl_header *)trackingReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "TDATA"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_TDATA_ELEMENT_SIZE*3); + + std::vector trackerDescription; + trackerDescription.push_back((char*)"Tracker0"); + trackerDescription.push_back((char*)"Tracker1"); + trackerDescription.push_back((char*)"Tracker2"); + + for (int i = 0; i<3;++i) + { + igtl::TrackingDataElement::Pointer elem = igtl::TrackingDataElement::New(); + trackingReceiveMsg->GetTrackingDataElement(i, elem); + EXPECT_EQ(strncmp((char*)(elem->GetName()), trackerDescription[i], 8),0); + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + elem->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); + } + + // reuse message test + trackingElement3->SetName("Tracker3"); + trackingElement3->SetType(IGTL_TDATA_TYPE_6D); + trackingElement3->SetMatrix(inMatrix); + trackingSendMsg->AddTrackingDataElement(trackingElement3); // there are 4 tracking element now in the message + trackingSendMsg->Pack(); + headerMsg->InitPack(); + memcpy(headerMsg->GetPackPointer(), (const void*)trackingSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + trackingReceiveMsg->SetMessageHeader(headerMsg); + trackingReceiveMsg->AllocatePack(); + memcpy(trackingReceiveMsg->GetPackBodyPointer(), trackingSendMsg->GetPackBodyPointer(), IGTL_TDATA_ELEMENT_SIZE*4); + trackingReceiveMsg->Unpack(); + messageHeader = (igtl_header *)trackingReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "TDATA"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_TDATA_ELEMENT_SIZE*4); + + trackerDescription.push_back((char*)"Tracker3"); + + for (int i = 0; i<4;++i) + { + igtl::TrackingDataElement::Pointer elem = igtl::TrackingDataElement::New(); + trackingReceiveMsg->GetTrackingDataElement(i, elem); + EXPECT_EQ(strncmp((char*)(elem->GetName()), trackerDescription[i], 8),0); + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + elem->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); + } +} + + +#if OpenIGTLink_PROTOCOL_VERSION >= 3 +#include "igtlutil/igtl_test_data_tdataFormat2.h" +#include "igtlMessageFormat2TestMacro.h" + +TEST(TrackingMessageTest, PackFormatVersion2) +{ + BuildUpElements(); + igtlMetaDataAddElementMacro(trackingSendMsg); + trackingSendMsg->Pack(); + FILE *fp; + fp = fopen("TrackingData.bin", "w"); + fwrite(trackingSendMsg->GetPackPointer(), trackingSendMsg->GetPackBodySize()+IGTL_HEADER_SIZE, 1, fp); + fclose(fp); + int r = memcmp((const void*)trackingSendMsg->GetPackPointer(), (const void*)test_tdata_messageFormat2, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)trackingSendMsg->GetPackBodyPointer(), (const void*)(test_tdata_messageFormat2+(size_t)(IGTL_HEADER_SIZE)), IGTL_TDATA_ELEMENT_SIZE*3+EXTENDED_CONTENT_SIZE); + EXPECT_EQ(r, 0); +} + +TEST(TrackingMessageTest, UnpackFormatVersion2) +{ + BuildUpElements(); + igtlMetaDataAddElementMacro(trackingSendMsg); + trackingSendMsg->Pack(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)trackingSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + trackingReceiveMsg->SetMessageHeader(headerMsg); + trackingReceiveMsg->AllocatePack(); + memcpy(trackingReceiveMsg->GetPackBodyPointer(), trackingSendMsg->GetPackBodyPointer(), IGTL_TDATA_ELEMENT_SIZE*3 + EXTENDED_CONTENT_SIZE); + trackingReceiveMsg->Unpack(); + igtl_header *messageHeader = (igtl_header *)trackingReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "TDATA"); + EXPECT_EQ(messageHeader->header_version, 2); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_TDATA_ELEMENT_SIZE*3 + EXTENDED_CONTENT_SIZE); + + std::vector trackerDescription; + trackerDescription.push_back((char*)"Tracker0"); + trackerDescription.push_back((char*)"Tracker1"); + trackerDescription.push_back((char*)"Tracker2"); + + for (int i = 0; i<3;++i) + { + igtl::TrackingDataElement::Pointer elem = igtl::TrackingDataElement::New(); + trackingReceiveMsg->GetTrackingDataElement(i, elem); + EXPECT_EQ(strncmp((char*)(elem->GetName()), trackerDescription[i], 8),0); + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + elem->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); + } + + igtlMetaDataComparisonMacro(trackingReceiveMsg); + + // reuse message test + trackingElement3->SetName("Tracker3"); + trackingElement3->SetType(IGTL_TDATA_TYPE_6D); + trackingElement3->SetMatrix(inMatrix); + trackingSendMsg->AddTrackingDataElement(trackingElement3); // there are 4 tracking element now in the message + trackingSendMsg->Pack(); + headerMsg->InitPack(); + memcpy(headerMsg->GetPackPointer(), (const void*)trackingSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + trackingReceiveMsg->SetMessageHeader(headerMsg); + trackingReceiveMsg->AllocatePack(); + memcpy(trackingReceiveMsg->GetPackBodyPointer(), trackingSendMsg->GetPackBodyPointer(), IGTL_TDATA_ELEMENT_SIZE*4 + EXTENDED_CONTENT_SIZE); + trackingReceiveMsg->Unpack(); + messageHeader = (igtl_header *)trackingReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "TDATA"); + EXPECT_EQ(messageHeader->header_version, 2); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_TDATA_ELEMENT_SIZE*4 + EXTENDED_CONTENT_SIZE); + + trackerDescription.push_back((char*)"Tracker3"); + + for (int i = 0; i<4;++i) + { + igtl::TrackingDataElement::Pointer elem = igtl::TrackingDataElement::New(); + trackingReceiveMsg->GetTrackingDataElement(i, elem); + EXPECT_EQ(strncmp((char*)(elem->GetName()), trackerDescription[i], 8),0); + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + elem->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); + } + igtlMetaDataComparisonMacro(trackingReceiveMsg); +} + +#endif + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlTrajectoryMessageTest.cxx b/openigtlink/repo/Testing/igtlTrajectoryMessageTest.cxx new file mode 100644 index 0000000..d88a3fe --- /dev/null +++ b/openigtlink/repo/Testing/igtlTrajectoryMessageTest.cxx @@ -0,0 +1,241 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +//#define IGTL_LEGACY_TEST +#include "igtlTrajectoryMessage.h" +#include "igtlutil/igtl_test_data_trajectory.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_trajectory.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + + +igtl::TrajectoryMessage::Pointer trajectorySendMsg = igtl::TrajectoryMessage::New(); +igtl::TrajectoryMessage::Pointer trajectoryReceiveMsg = igtl::TrajectoryMessage::New(); + +igtl::TrajectoryElement::Pointer trajectoryElement0 = igtl::TrajectoryElement::New(); +igtl::TrajectoryElement::Pointer trajectoryElement1 = igtl::TrajectoryElement::New(); +igtl::TrajectoryElement::Pointer trajectoryElement2 = igtl::TrajectoryElement::New(); + +void BuildUpElements() +{ + trajectoryElement0->SetName("TRAJECTORY_DESCRIPTION_0"); + trajectoryElement0->SetGroupName("TRAJECTORY"); + trajectoryElement0->SetType(IGTL_TRAJECTORY_TYPE_ENTRY_TARGET); + trajectoryElement0->SetRGBA(255,0,0,255); + trajectoryElement0->SetEntryPosition(10.0,15.0,20.0); + trajectoryElement0->SetTargetPosition(25.0,30.0,35.0); + trajectoryElement0->SetRadius(5.0); + trajectoryElement0->SetOwner("IMAGE_0"); + trajectoryElement1->SetName("TRAJECTORY_DESCRIPTION_1"); + trajectoryElement1->SetGroupName("TRAJECTORY"); + trajectoryElement1->SetType(IGTL_TRAJECTORY_TYPE_ENTRY_TARGET); + trajectoryElement1->SetRGBA(0,255,0,255); + trajectoryElement1->SetEntryPosition(40.0,45.0,50.0); + trajectoryElement1->SetTargetPosition(55.0,60.0,65.0); + trajectoryElement1->SetRadius(2.5); + trajectoryElement1->SetOwner("IMAGE_0"); + trajectoryElement2->SetName("TRAJECTORY_DESCRIPTION_2"); + trajectoryElement2->SetGroupName("TRAJECTORY"); + trajectoryElement2->SetType(IGTL_TRAJECTORY_TYPE_ENTRY_TARGET); + trajectoryElement2->SetRGBA(0,0,255,255); + trajectoryElement2->SetEntryPosition(70.0,75.0,80.0); + trajectoryElement2->SetTargetPosition(85.0,90.0,95.0); + trajectoryElement2->SetRadius(0.0); + trajectoryElement2->SetOwner("IMAGE_0"); + trajectorySendMsg = igtl::TrajectoryMessage::New(); + trajectorySendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + trajectorySendMsg->SetDeviceName("DeviceName"); + trajectorySendMsg->SetTimeStamp(0, 1234567892); + trajectorySendMsg->AddTrajectoryElement(trajectoryElement0); + trajectorySendMsg->AddTrajectoryElement(trajectoryElement1); + trajectorySendMsg->AddTrajectoryElement(trajectoryElement2); +} + +TEST(TrajectoryMessageTest, DeprecatedMethodTest) +{ + BuildUpElements(); + int size = trajectorySendMsg->GetNumberOfTrajectoryElement(); + EXPECT_EQ(size, 3); + igtl::TrajectoryElement::Pointer trajectoryElementNotUsed = igtl::TrajectoryElement::New(); + trajectorySendMsg->ClearTrajectoryElement(trajectoryElementNotUsed); + size = trajectorySendMsg->GetNumberOfTrajectoryElement(); + EXPECT_EQ(size, 0); + BuildUpElements(); + size = trajectorySendMsg->GetNumberOfTrajectoryElement(); + EXPECT_EQ(size, 3); + trajectorySendMsg->ClearTrajectoryElement(trajectoryElementNotUsed); + size = trajectorySendMsg->GetNumberOfTrajectoryElement(); + EXPECT_EQ(size, 0); +} + +TEST(TrajectoryMessageTest, PackFormatVersion1) +{ + BuildUpElements(); + trajectorySendMsg->Pack(); + int r = memcmp((const void*)trajectorySendMsg->GetPackPointer(), (const void*)test_trajectory_message, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)trajectorySendMsg->GetPackBodyPointer(), (const void*)(test_trajectory_message+(size_t)(IGTL_HEADER_SIZE)), IGTL_TRAJECTORY_ELEMENT_SIZE*3 ); + EXPECT_EQ(r, 0); +} + + +TEST(TrajectoryMessageTest, UnpackFormatVersion1) +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), trajectorySendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + trajectoryReceiveMsg->SetMessageHeader(headerMsg); + trajectoryReceiveMsg->AllocatePack(); + memcpy(trajectoryReceiveMsg->GetPackBodyPointer(), trajectorySendMsg->GetPackBodyPointer(), IGTL_TRAJECTORY_ELEMENT_SIZE*3); + trajectoryReceiveMsg->Unpack(); + igtl_header *messageHeader = (igtl_header *)trajectoryReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "TRAJ"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_TRAJECTORY_ELEMENT_SIZE*3); + + + std::vector > groundTruthRGBA(3,std::vector(4)); + igtlUint8 tempIni1[4] = {255,0,0,255}; + groundTruthRGBA[0].assign(tempIni1,tempIni1+4); + igtlUint8 tempIni2[4] = {0,255,0,255}; + groundTruthRGBA[1].assign(tempIni2,tempIni2+4); + igtlUint8 tempIni3[4] = {0,0,255,255}; + groundTruthRGBA[2].assign(tempIni3,tempIni3+4); + + igtlFloat32 groundTruthEntryPoints[3][3] ={{10.0,15.0,20.0}, + {40.0,45.0,50.0}, + {70.0,75.0,80.0}}; + + igtlFloat32 groundTruthTargetPoints[3][3] = {{25.0,30.0,35.0}, + {55.0,60.0,65.0}, + {85.0,90.0,95.0}}; + + igtlFloat32 groundTruthRadius[3] = {5.0,2.5,0.0}; + + std::vector trajectoryDescription; + trajectoryDescription.push_back((char*)"TRAJECTORY_DESCRIPTION_0"); + trajectoryDescription.push_back((char*)"TRAJECTORY_DESCRIPTION_1"); + trajectoryDescription.push_back((char*)"TRAJECTORY_DESCRIPTION_2"); + + for (int i = 0; i<3;++i) + { + igtl::TrajectoryElement::Pointer elem = igtl::TrajectoryElement::New(); + trajectoryReceiveMsg->GetTrajectoryElement(i, elem); + EXPECT_EQ(strncmp((char*)(elem->GetName()), trajectoryDescription[i], 24),0); + igtlUint8 returnedRGBA[4] ={0,0,0,0}; + elem->GetRGBA(returnedRGBA); + EXPECT_THAT(returnedRGBA, testing::ElementsAreArray(groundTruthRGBA[i])); + igtlFloat32 returnedEntryPoint[3] ={0,0,0}; + elem->GetEntryPosition(returnedEntryPoint); + EXPECT_TRUE(ArrayFloatComparison(returnedEntryPoint, groundTruthEntryPoints[i], 3, ABS_ERROR)); + igtlFloat32 returnedTargetPoint[3] ={0,0,0}; + elem->GetTargetPosition(returnedTargetPoint); + EXPECT_TRUE(ArrayFloatComparison(returnedTargetPoint, groundTruthTargetPoints[i], 3, ABS_ERROR)); + EXPECT_EQ(elem->GetRadius(), groundTruthRadius[i]); + EXPECT_EQ(strncmp((char*)elem->GetOwner(), "IMAGE_0", 7),0); + } +} + + +#if OpenIGTLink_PROTOCOL_VERSION >= 3 +#include "igtlutil/igtl_test_data_trajectoryFormat2.h" +#include "igtlMessageFormat2TestMacro.h" + +TEST(TrajectoryMessageTest, PackFormatVersion2) +{ + trajectorySendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + BuildUpElements(); + igtlMetaDataAddElementMacro(trajectorySendMsg); + trajectorySendMsg->Pack(); + int r = memcmp((const void*)trajectorySendMsg->GetPackPointer(), (const void*)test_trajectory_message_Format2, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)trajectorySendMsg->GetPackBodyPointer(), (const void*)(test_trajectory_message_Format2+(size_t)(IGTL_HEADER_SIZE)), IGTL_TRAJECTORY_ELEMENT_SIZE*3 + EXTENDED_CONTENT_SIZE); + EXPECT_EQ(r, 0); +} + +TEST(TrajectoryMessageTest, UnpackFormatVersion2) +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), trajectorySendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + trajectoryReceiveMsg->SetMessageHeader(headerMsg); + trajectoryReceiveMsg->AllocatePack(); + memcpy(trajectoryReceiveMsg->GetPackBodyPointer(), trajectorySendMsg->GetPackBodyPointer(), IGTL_TRAJECTORY_ELEMENT_SIZE*3 + EXTENDED_CONTENT_SIZE); + trajectoryReceiveMsg->Unpack(); + igtl_header *messageHeader = (igtl_header *)trajectoryReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "TRAJ"); + EXPECT_EQ(messageHeader->header_version, 2); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_TRAJECTORY_ELEMENT_SIZE*3 + EXTENDED_CONTENT_SIZE); + + + std::vector > groundTruthRGBA(3,std::vector(4)); + igtlUint8 tempIni1[4] = {255,0,0,255}; + groundTruthRGBA[0].assign(tempIni1,tempIni1+4); + igtlUint8 tempIni2[4] = {0,255,0,255}; + groundTruthRGBA[1].assign(tempIni2,tempIni2+4); + igtlUint8 tempIni3[4] = {0,0,255,255}; + groundTruthRGBA[2].assign(tempIni3,tempIni3+4); + + igtlFloat32 groundTruthEntryPoints[3][3] ={{10.0,15.0,20.0}, + {40.0,45.0,50.0}, + {70.0,75.0,80.0}}; + + igtlFloat32 groundTruthTargetPoints[3][3] = {{25.0,30.0,35.0}, + {55.0,60.0,65.0}, + {85.0,90.0,95.0}}; + + igtlFloat32 groundTruthRadius[3] = {5.0,2.5,0.0}; + + std::vector trajectoryDescription; + trajectoryDescription.push_back((char*)"TRAJECTORY_DESCRIPTION_0"); + trajectoryDescription.push_back((char*)"TRAJECTORY_DESCRIPTION_1"); + trajectoryDescription.push_back((char*)"TRAJECTORY_DESCRIPTION_2"); + + for (int i = 0; i<3;++i) + { + igtl::TrajectoryElement::Pointer elem = igtl::TrajectoryElement::New(); + trajectoryReceiveMsg->GetTrajectoryElement(i, elem); + EXPECT_EQ(strncmp((char*)(elem->GetName()), trajectoryDescription[i], 24),0); + igtlUint8 returnedRGBA[4] ={0,0,0,0}; + elem->GetRGBA(returnedRGBA); + EXPECT_THAT(returnedRGBA, testing::ElementsAreArray(groundTruthRGBA[i])); + igtlFloat32 returnedEntryPoint[3] ={0,0,0}; + elem->GetEntryPosition(returnedEntryPoint); + EXPECT_TRUE(ArrayFloatComparison(returnedEntryPoint, groundTruthEntryPoints[i], 3, ABS_ERROR)); + igtlFloat32 returnedTargetPoint[3] ={0,0,0}; + elem->GetTargetPosition(returnedTargetPoint); + EXPECT_TRUE(ArrayFloatComparison(returnedTargetPoint, groundTruthTargetPoints[i], 3, ABS_ERROR)); + EXPECT_EQ(elem->GetRadius(), groundTruthRadius[i]); + EXPECT_EQ(strncmp((char*)elem->GetOwner(), "IMAGE_0", 7),0); + } + igtlMetaDataComparisonMacro(trajectoryReceiveMsg); +} + +#endif + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlTransformMessageTest.cxx b/openigtlink/repo/Testing/igtlTransformMessageTest.cxx new file mode 100644 index 0000000..ac4107d --- /dev/null +++ b/openigtlink/repo/Testing/igtlTransformMessageTest.cxx @@ -0,0 +1,193 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#include "igtlTransformMessage.h" +#include "igtlutil/igtl_test_data_transform.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_transform.h" +#include "igtl_header.h" +#include "igtlTestConfig.h" +#include "string.h" + +igtl::TransformMessage::Pointer transformSendMsg = igtl::TransformMessage::New(); +igtl::TransformMessage::Pointer transformReceiveMsg = igtl::TransformMessage::New(); +float inT[4] = {-0.954892f, 0.196632f, -0.222525f, 0.0}; +float inS[4] = {-0.196632f, 0.142857f, 0.970014f, 0.0}; +float inN[4] = {0.222525f, 0.970014f, -0.0977491f, 0.0}; +float inOrigin[4] = {46.0531f,19.4709f,46.0531f, 1.0}; +igtl::Matrix4x4 inMatrix = {{inT[0],inS[0],inN[0],inOrigin[0]}, + {inT[1],inS[1],inN[1],inOrigin[1]}, + {inT[2],inS[2],inN[2],inOrigin[2]}, + {inT[3],inS[3],inN[3],inOrigin[3]}}; + +TEST(TransformMessageTest, PackFormatVersion1) +{ + transformSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_1); + transformSendMsg->AllocatePack(); + transformSendMsg->SetTimeStamp(0, 1234567892); + transformSendMsg->SetDeviceName("DeviceName"); + transformSendMsg->SetMatrix(inMatrix); + transformSendMsg->Pack(); + + int r = memcmp((const void*)transformSendMsg->GetPackPointer(), (const void*)test_transform_message, + (size_t)(IGTL_HEADER_SIZE)); + EXPECT_EQ(r, 0); + r = memcmp((const void*)transformSendMsg->GetPackBodyPointer(), (const void*)(test_transform_message+IGTL_HEADER_SIZE), IGTL_TRANSFORM_SIZE); + EXPECT_EQ(r, 0); +} + + +TEST(TransformMessageTest, UnpackFormatVersion1) +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)test_transform_message, IGTL_HEADER_SIZE); + headerMsg->Unpack(); + transformReceiveMsg->SetMessageHeader(headerMsg); + transformReceiveMsg->AllocatePack(); + + memcpy(transformReceiveMsg->GetPackBodyPointer(), transformSendMsg->GetPackBodyPointer(), transformReceiveMsg->GetPackBodySize()); + transformReceiveMsg->Unpack(); + + igtl_header *messageHeader = (igtl_header *)transformReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "TRANSFORM"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_TRANSFORM_SIZE); + + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + transformReceiveMsg->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); + + //Reuse message test + igtl::Matrix4x4 inMatrix2 = {{inT[1],inS[0],inN[0],inOrigin[0]}, + {inT[2],inS[1],inN[3],inOrigin[2]}, + {inT[0],inS[3],inN[2],inOrigin[2]}, + {inT[3],inS[3],inN[3],inOrigin[3]}}; + + transformSendMsg->SetMatrix(inMatrix2); + transformSendMsg->Pack(); + headerMsg->InitPack(); + memcpy(headerMsg->GetPackPointer(), (const void*)transformSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + transformReceiveMsg->SetMessageHeader(headerMsg); + transformReceiveMsg->AllocatePack(); + memcpy(transformReceiveMsg->GetPackBodyPointer(), transformSendMsg->GetPackBodyPointer(), transformReceiveMsg->GetPackBodySize()); + transformReceiveMsg->Unpack(); + messageHeader = (igtl_header *)transformReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "TRANSFORM"); + EXPECT_EQ(messageHeader->header_version, 1); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_TRANSFORM_SIZE); + + igtl::Matrix4x4 outMatrix2 = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + transformReceiveMsg->GetMatrix(outMatrix2); + EXPECT_TRUE(MatrixComparison(outMatrix2, inMatrix2, ABS_ERROR)); +} + +#if OpenIGTLink_PROTOCOL_VERSION >= 3 +#include "igtlutil/igtl_test_data_transformFormat2.h" +#include "igtlMessageFormat2TestMacro.h" +TEST(TransformMessageTest, PackFormatVersion2) +{ + transformSendMsg = igtl::TransformMessage::New(); + transformSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + transformSendMsg->AllocatePack(); + transformSendMsg->SetTimeStamp(0, 1234567892); + transformSendMsg->SetDeviceName("DeviceName"); + transformSendMsg->SetMatrix(inMatrix); + igtlMetaDataAddElementMacro(transformSendMsg); + transformSendMsg->Pack(); + int r = memcmp((const void*)transformSendMsg->GetPackPointer(), (const void*)test_transform_message_Format2, + (size_t)(IGTL_HEADER_SIZE)); + TestDebugCharArrayCmp(transformSendMsg->GetPackPointer(), test_transform_message_Format2, IGTL_HEADER_SIZE); + EXPECT_EQ(r, 0); + r = memcmp((const void*)transformSendMsg->GetPackBodyPointer(), (const void*)(test_transform_message_Format2+IGTL_HEADER_SIZE), IGTL_TRANSFORM_SIZE + EXTENDED_CONTENT_SIZE); + EXPECT_EQ(r, 0); +} + +TEST(TransformMessageTest, UnpackFormatVersion2) +{ + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)test_transform_message_Format2, IGTL_HEADER_SIZE); + headerMsg->Unpack(); + transformReceiveMsg = igtl::TransformMessage::New(); + transformReceiveMsg->SetMessageHeader(headerMsg); + transformReceiveMsg->AllocatePack(); + + memcpy(transformReceiveMsg->GetPackBodyPointer(), transformSendMsg->GetPackBodyPointer(), transformReceiveMsg->GetPackBodySize()); + transformReceiveMsg->Unpack(1); + + igtl_header *messageHeader = (igtl_header *)transformReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "TRANSFORM"); + EXPECT_EQ(messageHeader->header_version, 2); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_TRANSFORM_SIZE + EXTENDED_CONTENT_SIZE); + + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + transformReceiveMsg->GetMatrix(outMatrix); + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix, ABS_ERROR)); + igtlMetaDataComparisonMacro(transformReceiveMsg); + + //Reuse message test + igtl::Matrix4x4 inMatrix2 = {{inT[1],inS[0],inN[0],inOrigin[0]}, + {inT[2],inS[1],inN[3],inOrigin[2]}, + {inT[0],inS[3],inN[2],inOrigin[2]}, + {inT[3],inS[3],inN[3],inOrigin[3]}}; + + transformSendMsg->SetMatrix(inMatrix2); + transformSendMsg->Pack(); + headerMsg->InitPack(); + memcpy(headerMsg->GetPackPointer(), (const void*)transformSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + transformReceiveMsg->SetMessageHeader(headerMsg); + transformReceiveMsg->AllocatePack(); + memcpy(transformReceiveMsg->GetPackBodyPointer(), transformSendMsg->GetPackBodyPointer(), transformReceiveMsg->GetPackBodySize()); + transformReceiveMsg->Unpack(); + messageHeader = (igtl_header *)transformReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "TRANSFORM"); + EXPECT_EQ(messageHeader->header_version, 2); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_TRANSFORM_SIZE + EXTENDED_CONTENT_SIZE); + + igtl::Matrix4x4 outMatrix2 = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + transformReceiveMsg->GetMatrix(outMatrix2); + EXPECT_TRUE(MatrixComparison(outMatrix2, inMatrix2, ABS_ERROR)); + igtlMetaDataComparisonMacro(transformReceiveMsg); +} + +#endif + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlVideoMessageTest.cxx b/openigtlink/repo/Testing/igtlVideoMessageTest.cxx new file mode 100644 index 0000000..196055e --- /dev/null +++ b/openigtlink/repo/Testing/igtlVideoMessageTest.cxx @@ -0,0 +1,420 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Language: C++ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ +/* + * Copyright (c) 2014 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include +#include +#include "igtlVideoMessage.h" +#include "igtlMessageDebugFunction.h" +#include "igtl_video.h" +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_util.h" +#include "igtlTestConfig.h" +#include "string.h" +#include +#include +#if OpenIGTLink_PROTOCOL_VERSION >= 3 + #include "igtlMessageFormat2TestMacro.h" +#endif + +#include "igtlI420Encoder.h" +#include "igtlI420Decoder.h" + +#if defined(OpenIGTLink_USE_H264) + #include "igtlH264Encoder.h" + #include "igtlH264Decoder.h" +#endif + +#if defined(OpenIGTLink_USE_VP9) + #include "igtlVP9Encoder.h" + #include "igtlVP9Decoder.h" +#endif + +#if defined(OpenIGTLink_USE_OpenHEVC) && defined(OpenIGTLink_USE_X265) + #include "igtlH265Encoder.h" + #include "igtlH265Decoder.h" +#endif + +#if defined (OpenIGTLink_USE_AV1) + #include "igtlAV1Encoder.h" + #include "igtlAV1Decoder.h" +#endif + +#include "igtlCodecCommonClasses.h" +#include "igtlOSUtil.h" + +using namespace igtl; + +int Width = 256; +int Height = 256; +std::string testFileName(OpenIGTLink_SOURCE_ROOTDIR); +int startIndex = 0; +int inputFrameNum = 20; + +int TestWithVersion(int version, GenericEncoder* videoStreamEncoder, GenericDecoder* videoStreamDecoder, VideoFormatType type, bool compareImage) +{ + // Get thread information + int kiPicResSize = Width*Height; + SourcePicture* pSrcPic = new SourcePicture(); + SourcePicture* pDecodedPic = new SourcePicture(); + igtl_uint8* imagePointer; + if(type == FormatI420) + { + imagePointer = new igtl_uint8[kiPicResSize*3/2]; + memset(imagePointer, 0, Width * Height * 3 / 2); + pSrcPic->colorFormat = FormatI420; + pSrcPic->picWidth = Width; // check the test image + pSrcPic->picHeight = Height; + pSrcPic->data[0] = imagePointer; + pSrcPic->data[1] = pSrcPic->data[0] + kiPicResSize; + pSrcPic->data[2] = pSrcPic->data[1] + kiPicResSize/4; + pSrcPic->stride[0] = pSrcPic->picWidth; + pSrcPic->stride[1] = pSrcPic->stride[2] = pSrcPic->stride[0] >> 1; + + pDecodedPic->data[0] = new igtl_uint8[kiPicResSize*3/2]; + memset(pDecodedPic->data[0], 0, Width * Height * 3 / 2); + } + else if(type == FormatI444) + { + imagePointer = new igtl_uint8[kiPicResSize*3]; + memset(imagePointer, 0, Width * Height * 3); + pSrcPic->colorFormat = FormatI444; + pSrcPic->picWidth = Width; // check the test image + pSrcPic->picHeight = Height; + pSrcPic->data[0] = imagePointer; + pSrcPic->data[1] = pSrcPic->data[0] + kiPicResSize; + pSrcPic->data[2] = pSrcPic->data[1] + kiPicResSize; + pSrcPic->stride[0] = pSrcPic->picWidth; + pSrcPic->stride[1] = pSrcPic->stride[2] = pSrcPic->stride[0]; + + pDecodedPic->data[0] = new igtl_uint8[kiPicResSize*3]; + memset(pDecodedPic->data[0], 0, Width * Height * 3); + } + int totalFrame = 0; + for(int i = 0; i (( std::ostringstream() << std::dec << (i%6+1))).str(); + char imageIndexStr[4]; + sprintf(imageIndexStr,"%d",i%6+1); + std::string testIndexedFileName = std::string(testFileName); + testIndexedFileName.append(sep).append("Testing").append(sep).append("img").append(sep).append("igtlTestImage").append(imageIndexStr).append(".raw"); + FILE* pFileYUV = NULL; + pFileYUV = fopen (testIndexedFileName.c_str(), "rb"); + if (pFileYUV != NULL) { + igtl_int64 i_size = 0; +#if defined(_WIN32) || defined(_WIN64) +#if _MSC_VER >= 1400 + if (!_fseeki64 (pFileYUV, 0, SEEK_END)) + { + i_size = _ftelli64 (pFileYUV); + _fseeki64 (pFileYUV, 0, SEEK_SET); + iFrameNumInFile = (i_size / kiPicResSize) > iFrameNumInFile ? (i_size / kiPicResSize):iFrameNumInFile; + } +#else + if (!fseek (pFileYUV, 0, SEEK_END)) + { + i_size = ftell (pFileYUV); + fseek (pFileYUV, 0, SEEK_SET); + iFrameNumInFile = (i_size / kiPicResSize) > iFrameNumInFile ? (i_size / kiPicResSize):iFrameNumInFile; + } +#endif +#else + if (!fseeko (pFileYUV, 0, SEEK_END)) + { + i_size = ftello (pFileYUV); + fseek(pFileYUV, 0, SEEK_SET); + iFrameNumInFile = (i_size / kiPicResSize) > iFrameNumInFile ? (i_size / kiPicResSize):iFrameNumInFile; + } +#endif +#if defined(_WIN32) || defined(_WIN64) + #if _MSC_VER >= 1400 + _fseeki64(pFileYUV, startIndex*kiPicResSize, SEEK_SET); //fix the data range issue + #else + fseek(pFileYUV, startIndex*kiPicResSize, SEEK_SET); //fix the data range issue + #endif +#else + fseek(pFileYUV, startIndex*kiPicResSize, SEEK_SET); +#endif + while(fread (imagePointer, 1, kiPicResSize, pFileYUV ) == (kiPicResSize) && totalFrameSetHeaderVersion(version); + if(version == IGTL_HEADER_VERSION_2) + igtlMetaDataAddElementMacro(videoMessageSend); + int iEncFrames = videoStreamEncoder->EncodeSingleFrameIntoVideoMSG(pSrcPic, videoMessageSend, isGrayImage); + if(iEncFrames == 0) + { + igtl::VideoMessage::Pointer videoMessageReceived = igtl::VideoMessage::New(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), videoMessageSend->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + videoMessageReceived->SetMessageHeader(headerMsg); + videoMessageReceived->AllocatePack(); + memcpy(videoMessageReceived->GetPackBodyPointer(), videoMessageSend->GetPackBodyPointer(), videoMessageSend->GetPackBodySize()); + videoMessageReceived->Unpack(); + if (memcmp(videoMessageReceived->GetPackFragmentPointer(2), videoMessageSend->GetPackFragmentPointer(2), videoMessageReceived->GetBitStreamSize()) != 0) + { + return -1; + } + int iRet= videoStreamDecoder->DecodeVideoMSGIntoSingleFrame(videoMessageReceived.GetPointer(), pDecodedPic); + if(iRet) + { + totalFrame ++; + if(version == IGTL_HEADER_VERSION_2) + { + videoMessageReceived->SetMessageID(1); // Message ID is reset by the codec, so the comparison of ID is no longer valid, manually set to 1; + //igtlMetaDataComparisonMacro(videoMessageReceived); + } + if (compareImage) + { + //TestDebugCharArrayCmp(pDecodedPic->data[0], imagePointer, kiPicResSize * 3 / 2); + if(type == FormatI420) + { + if (memcmp(pDecodedPic->data[0], imagePointer, kiPicResSize * 3 / 2) != 0) + { + return -1; + } + } + else if(type == FormatI444) + { + if (memcmp(pDecodedPic->data[0], imagePointer, kiPicResSize * 3) != 0) + { + return -1; + } + } + + } + //EXPECT_EQ(memcmp(pDecodedPic->data[0], pSrcPic->data[0],kiPicResSize*3/2),0); + } + } + igtl::Sleep(5); + } + if (pFileYUV) + { + fclose(pFileYUV); + pFileYUV = NULL; + } + } else { + fprintf (stderr, "Unable to open image file, check corresponding path!\n"); + } + } + delete pDecodedPic; + delete pSrcPic; + pDecodedPic = NULL; + pSrcPic = NULL; + return 0; +} + + +TEST(VideoMessageTest, YUVandRGBConversion) +{ +#if defined(OpenIGTLink_ENABLE_VIDEOSTREAMING) + int width = 400, height = 400; + int yuvDataLen = width*height*3/2; + igtlUint8* yuv_a = new igtlUint8[yuvDataLen]; + igtlUint8* yuv_a2 = new igtlUint8[yuvDataLen]; + igtlUint8* rgbPointer = new igtlUint8[yuvDataLen*2]; + igtlUint8* rgbPointer2 = new igtlUint8[yuvDataLen*2]; + unsigned char color = 108; + for(int i = 0 ; i< width*height*3; i++) + { + *rgbPointer = color%256; + color++; + rgbPointer++; + } + rgbPointer -=yuvDataLen*2; + //------------ + //Test of the data lost in RGB->YUV->RGB conversion + GenericEncoder::ConvertRGBToYUV(rgbPointer, yuv_a, width, height); + GenericDecoder::ConvertYUVToRGB(yuv_a, rgbPointer2, width,height); + GenericEncoder::ConvertRGBToYUV((igtlUint8*)rgbPointer2, yuv_a2, width,height); + int iReturn = memcmp(yuv_a2, yuv_a,yuvDataLen);// The conversion is not valid. Image is not the same after conversion. + //------------- + //igtlUint8* yuv_b = new igtlUint8[b->GetDimensions()[0]*b->GetDimensions()[1]*3/2]; + //encoder->ConvertRGBToYUV((igtlUint8*)b->GetScalarPointer(), yuv_b, b->GetDimensions()[0], b->GetDimensions()[1]); + //iReturn = memcmp(yuv_b, yuv_a, a->GetDimensions()[0]*a->GetDimensions()[1]*3/2); +#endif +} + +TEST(VideoMessageTest, EncodeAndDecodeFormatVersion1) + { + std::cerr << "--------------------------- " << std::endl; + std::cerr << "Begin of I420 tests " << std::endl; + I420Encoder* I420StreamEncoder = new I420Encoder(); + I420Decoder* I420StreamDecoder = new I420Decoder(); + EXPECT_EQ(TestWithVersion(IGTL_HEADER_VERSION_1, I420StreamEncoder, I420StreamDecoder, FormatI420, true), 0); + std::cerr << "End of I420 tests " << std::endl; + std::cerr << "--------------------------- " << std::endl; + +#if defined(OpenIGTLink_USE_VP9) + std::cerr<<"--------------------------- "<SetPicWidthAndHeight(Width,Height); + VPXStreamEncoder->SetLosslessLink(true); + VPXStreamEncoder->InitializeEncoder(); + EXPECT_EQ(TestWithVersion(IGTL_HEADER_VERSION_1, VPXStreamEncoder, VPXStreamDecoder,FormatI420, true),0); + VPXStreamEncoder->SetSpeed(VPXStreamEncoder->FastestSpeed); + VPXStreamEncoder->SetLosslessLink(false); + std::cerr<<"Encoding Time Using Maximum Speed: "<SetPicWidthAndHeight(Width,Height); + H264StreamEncoder->InitializeEncoder(); + TestWithVersion(IGTL_HEADER_VERSION_1, H264StreamEncoder, H264StreamDecoder, FormatI420, false); + std::cerr<<"End of H264 tests "<SetPicWidthAndHeight(Width, Height); + AOStreamEncoder->SetLosslessLink(true); + AOStreamEncoder->InitializeEncoder(); + EXPECT_EQ(TestWithVersion(IGTL_HEADER_VERSION_1, AOStreamEncoder, AOMStreamDecoder, FormatI420, true), 0); + AOStreamEncoder->SetSpeed(AOStreamEncoder->FastestSpeed); + AOStreamEncoder->SetLosslessLink(false); + std::cerr << "Encoding Time Using Maximum Speed: " << std::endl; + EXPECT_EQ(TestWithVersion(IGTL_HEADER_VERSION_1, AOStreamEncoder, AOMStreamDecoder, FormatI420, false), 0); + std::cerr << "End of AOM tests " << std::endl; + std::cerr << "--------------------------- " << std::endl; +#endif + } + +#if OpenIGTLink_PROTOCOL_VERSION >= 3 + TEST(VideoMessageTest, EncodeAndDecodeFormatVersion2) + { + std::cerr << "--------------------------- " << std::endl; + std::cerr << "Begin of I420 tests " << std::endl; + I420Encoder* I420StreamEncoder = new I420Encoder(); + I420Decoder* I420StreamDecoder = new I420Decoder(); + EXPECT_EQ(TestWithVersion(IGTL_HEADER_VERSION_2, I420StreamEncoder, I420StreamDecoder, FormatI420, true), 0); + std::cerr << "End of I420 tests " << std::endl; + std::cerr << "--------------------------- " << std::endl; + + #if defined(OpenIGTLink_USE_VP9) + std::cerr<<"--------------------------- "<SetPicWidthAndHeight(Width,Height); + VPXStreamEncoder->InitializeEncoder(); + VPXStreamEncoder->SetLosslessLink(true); + TestWithVersion(IGTL_HEADER_VERSION_2, VPXStreamEncoder, VPXStreamDecoder, FormatI420, true); + VPXStreamEncoder->SetSpeed(VPXStreamEncoder->FastestSpeed); + VPXStreamEncoder->SetLosslessLink(false); + std::cerr<<"Encoding Time Using Maximum Speed: "<SetPicWidthAndHeight(Width,Height); + H264StreamEncoder->InitializeEncoder(); + TestWithVersion(IGTL_HEADER_VERSION_2, H264StreamEncoder, H264StreamDecoder, FormatI420, false); + std::cerr<<"End of H264 tests "<SetPicWidthAndHeight(Width,Height); + H265StreamEncoder->InitializeEncoder(); + H265StreamEncoder->SetLosslessLink(true); + TestWithVersion(IGTL_HEADER_VERSION_2, H265StreamEncoder, H265StreamDecoder, FormatI420, true); + H265StreamEncoder->SetSpeed(8); + H265StreamEncoder->SetLosslessLink(false); + std::cerr<<"Encoding Time Using Maximum Speed: "<SetPicWidthAndHeight(Width, Height); + AOMStreamEncoder->InitializeEncoder(); + AOMStreamEncoder->SetLosslessLink(true); + TestWithVersion(IGTL_HEADER_VERSION_2, AOMStreamEncoder, AOMStreamDecoder, FormatI420, true); + AOMStreamEncoder->SetSpeed(AOMStreamEncoder->FastestSpeed); + AOMStreamEncoder->SetLosslessLink(false); + std::cerr << "Encoding Time Using Maximum Speed: " << std::endl; + TestWithVersion(IGTL_HEADER_VERSION_2, AOMStreamEncoder, AOMStreamDecoder, FormatI420, false); + std::cerr << "End of AOM tests " << std::endl; + std::cerr << "--------------------------- " << std::endl; + #endif + } + + TEST(VideoMessageTest, I444EncodeAndDecodeFormatVersion2) + { + #if defined(OpenIGTLink_USE_VP9) + std::cerr<<"--------------------------- "<SetPicWidthAndHeight(Width,Height); + VPXStreamEncoder->SetImageFormat(FormatI444); + bool status = VPXStreamEncoder->InitializeEncoder(); + VPXStreamEncoder->SetLosslessLink(true); + TestWithVersion(IGTL_HEADER_VERSION_2, VPXStreamEncoder, VPXStreamDecoder, FormatI444, true); + VPXStreamEncoder->SetSpeed(VPXStreamEncoder->FastestSpeed); + VPXStreamEncoder->SetLosslessLink(false); + std::cerr<<"Encoding Time Using Maximum Speed: "<SetName("VIDEO_DESCRIPTION_0"); + videoMetaElement0->SetDeviceName("VIDEO_0"); + videoMetaElement0->SetPatientName("PATIENT_0"); + videoMetaElement0->SetPatientID("PATIENT_ID_0"); + videoMetaElement0->SetZoomLevel(4); + videoMetaElement0->SetFocalLength((igtl_float64)50.0); + videoMetaElement0->SetMatrix(inMatrix0); + videoMetaElement0->SetScalarType(IGTL_VIDEO_STYPE_TYPE_UINT16); + videoMetaElement0->SetSize(512,512,64); + + videoMetaElement1->SetName("VIDEO_DESCRIPTION_1"); + videoMetaElement1->SetDeviceName("VIDEO_1"); + videoMetaElement1->SetPatientName("PATIENT_1"); + videoMetaElement1->SetPatientID("PATIENT_ID_1"); + videoMetaElement1->SetZoomLevel(-2); + videoMetaElement1->SetFocalLength((igtl_float64)100.0); + videoMetaElement1->SetMatrix(inMatrix1); + videoMetaElement1->SetScalarType(IGTL_VIDEO_STYPE_TYPE_UINT16); + videoMetaElement1->SetSize(256,128,32); + + videoMetaElement2->SetName("VIDEO_DESCRIPTION_2"); + videoMetaElement2->SetDeviceName("VIDEO_2"); + videoMetaElement2->SetPatientName("PATIENT_2"); + videoMetaElement2->SetPatientID("PATIENT_ID_2"); + videoMetaElement2->SetZoomLevel(0); + videoMetaElement2->SetMatrix(inMatrix2); + videoMetaElement2->SetFocalLength((igtl_float64)20.5); + videoMetaElement2->SetScalarType(IGTL_VIDEO_STYPE_TYPE_UINT16); + videoMetaElement2->SetSize(256,256,32); + + igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); + timestamp->SetTime((igtlUint64)1234567892);//1234567850,1234567870,1234567890 are all fractions + videoMetaSendMsg = igtl::VideoMetaMessage::New(); + videoMetaSendMsg->SetHeaderVersion(IGTL_HEADER_VERSION_2); + videoMetaSendMsg->SetDeviceName("DeviceName"); + videoMetaSendMsg->SetTimeStamp(timestamp); + videoMetaSendMsg->AddVideoMetaElement(videoMetaElement0); + videoMetaSendMsg->AddVideoMetaElement(videoMetaElement1); + videoMetaSendMsg->AddVideoMetaElement(videoMetaElement2); + videoMetaSendMsg->Pack(); +} + +TEST(VideoMetaMessageTest, Pack) +{ + BuildUpLabelElements(); + int r = memcmp((const void*)videoMetaSendMsg->GetPackPointer(), (const void*)test_videometa_message, + (size_t)(IGTL_HEADER_SIZE)); + //TestDebugCharArrayCmp(videoMetaSendMsg->GetPackPointer(),test_videometa_message, 58); + + EXPECT_EQ(r, 0); + r = memcmp((const void*)videoMetaSendMsg->GetPackBodyPointer(), (const void*)(test_videometa_message+(size_t)(IGTL_HEADER_SIZE)), videoMetaSendMsg->GetPackBodySize()); + EXPECT_EQ(r, 0); +} + + + +TEST(VideoMetaMessageTest, Unpack) +{ + BuildUpLabelElements(); + igtl::MessageHeader::Pointer headerMsg = igtl::MessageHeader::New(); + headerMsg->AllocatePack(); + memcpy(headerMsg->GetPackPointer(), (const void*)videoMetaSendMsg->GetPackPointer(), IGTL_HEADER_SIZE); + headerMsg->Unpack(); + videoMetaReceiveMsg = igtl::VideoMetaMessage::New(); + videoMetaReceiveMsg->InitPack(); + videoMetaReceiveMsg->SetMessageHeader(headerMsg); + videoMetaReceiveMsg->AllocatePack(); + memcpy(videoMetaReceiveMsg->GetPackBodyPointer(), videoMetaSendMsg->GetPackBodyPointer(), videoMetaSendMsg->GetPackBodySize()); + videoMetaReceiveMsg->Unpack(); + + igtl_header *messageHeader = (igtl_header *)videoMetaReceiveMsg->GetPackPointer(); + EXPECT_STREQ(messageHeader->device_name, "DeviceName"); + EXPECT_STREQ(messageHeader->name, "VIDEOMETA"); + EXPECT_EQ(messageHeader->header_version, IGTL_HEADER_VERSION_2); + EXPECT_EQ(messageHeader->timestamp, 1234567892); + EXPECT_EQ(messageHeader->body_size, IGTL_VIDEOMETA_ELEMENT_SIZE*3+IGTL_EXTENDED_HEADER_SIZE+videoMetaReceiveMsg->GetMetaDataHeaderSize() + videoMetaReceiveMsg->GetMetaDataSize()); + + std::vector > groundTruthSize(3,std::vector(3)); + igtlUint16 tempIni1[3] = {512,512,64}; + groundTruthSize[0].assign(tempIni1,tempIni1+3); + igtlUint16 tempIni2[3] = {256,128,32}; + groundTruthSize[1].assign(tempIni2,tempIni2+3); + igtlUint16 tempIni3[3] = {256,256,32}; + groundTruthSize[2].assign(tempIni3,tempIni3+3); + + std::vector name; + name.push_back((char*)"VIDEO_DESCRIPTION_0"); + name.push_back((char*)"VIDEO_DESCRIPTION_1"); + name.push_back((char*)"VIDEO_DESCRIPTION_2"); + std::vector deviceName; + deviceName.push_back((char*)"VIDEO_0"); + deviceName.push_back((char*)"VIDEO_1"); + deviceName.push_back((char*)"VIDEO_2"); + std::vector patientName; + patientName.push_back((char*)"PATIENT_0"); + patientName.push_back((char*)"PATIENT_1"); + patientName.push_back((char*)"PATIENT_2"); + std::vector patientID; + patientID.push_back((char*)"PATIENT_ID_0"); + patientID.push_back((char*)"PATIENT_ID_1"); + patientID.push_back((char*)"PATIENT_ID_2"); + std::vector zoomLevels(3); + zoomLevels[0]=4; + zoomLevels[1]=-2; + zoomLevels[2]=0; + std::vector focalLength(3); + focalLength[0]=50.0; + focalLength[1]=100.0; + focalLength[2]=20.5; + + for (int i = 0; i<3;++i) + { + igtl::VideoMetaElement::Pointer elem = igtl::VideoMetaElement::New(); + videoMetaReceiveMsg->GetVideoMetaElement(i, elem); + EXPECT_EQ(strncmp((char*)(elem->GetName()), name[i], 19),0); + EXPECT_EQ(strncmp((char*)(elem->GetDeviceName()), deviceName[i], 7),0); + EXPECT_EQ(strncmp((char*)(elem->GetPatientName()), patientName[i], 9),0); + EXPECT_EQ(strncmp((char*)(elem->GetPatientID()), patientID[i], 12),0); + EXPECT_EQ(elem->GetZoomLevel(), zoomLevels[i]); + EXPECT_EQ(elem->GetFocalLength(), focalLength[i]); + igtlUint16 returnedSize[3] ={0,0,0}; + elem->GetSize(returnedSize[0],returnedSize[1],returnedSize[2]); + EXPECT_THAT(returnedSize, testing::ElementsAreArray(groundTruthSize[i])); + EXPECT_EQ(elem->GetScalarType(), (int)IGTL_VIDEO_STYPE_TYPE_UINT16); + igtl::Matrix4x4 outMatrix = {{0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0}}; + elem->GetMatrix(outMatrix); + if(i==0) + { + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix0, ABS_ERROR)); + } + else if(i == 1) + { + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix1, ABS_ERROR)); + } + else if(i == 2) + { + EXPECT_TRUE(MatrixComparison(outMatrix, inMatrix2, ABS_ERROR)); + } + } +} + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/openigtlink/repo/Testing/igtlutil/CMakeLists.txt b/openigtlink/repo/Testing/igtlutil/CMakeLists.txt new file mode 100644 index 0000000..667b54d --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/CMakeLists.txt @@ -0,0 +1,65 @@ +ADD_EXECUTABLE(igtl_image_test igtl_image_test.c) +ADD_EXECUTABLE(igtl_header_test igtl_header_test.c) +ADD_EXECUTABLE(igtl_transform_test igtl_transform_test.c) +ADD_EXECUTABLE(igtl_status_test igtl_status_test.c) +ADD_EXECUTABLE(igtl_util_test igtl_util_test.c) +ADD_EXECUTABLE(igtl_position_test igtl_position_test.c) +ADD_EXECUTABLE(igtl_capability_test igtl_capability_test.c) + +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "1") + ADD_EXECUTABLE(igtl_colortable_test igtl_colortable_test.c) + ADD_EXECUTABLE(igtl_imgmeta_test igtl_imgmeta_test.c) + ADD_EXECUTABLE(igtl_lbmeta_test igtl_lbmeta_test.c) + ADD_EXECUTABLE(igtl_point_test igtl_point_test.c) + ADD_EXECUTABLE(igtl_tdata_test igtl_tdata_test.c) + ADD_EXECUTABLE(igtl_trajectory_test igtl_trajectory_test.c) + ADD_EXECUTABLE(igtl_sensor_test igtl_sensor_test.c) + ADD_EXECUTABLE(igtl_string_test igtl_string_test.c) + ADD_EXECUTABLE(igtl_bind_test igtl_bind_test.c) + ADD_EXECUTABLE(igtl_ndarray_test igtl_ndarray_test.c) + ADD_EXECUTABLE(igtl_polydata_test igtl_polydata_test.c) +ENDIF() + +TARGET_LINK_LIBRARIES(igtl_image_test OpenIGTLink) +TARGET_LINK_LIBRARIES(igtl_header_test OpenIGTLink) +TARGET_LINK_LIBRARIES(igtl_transform_test OpenIGTLink) +TARGET_LINK_LIBRARIES(igtl_status_test OpenIGTLink) +TARGET_LINK_LIBRARIES(igtl_util_test OpenIGTLink) +TARGET_LINK_LIBRARIES(igtl_position_test OpenIGTLink) +TARGET_LINK_LIBRARIES(igtl_capability_test OpenIGTLink) + +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "1") + TARGET_LINK_LIBRARIES(igtl_colortable_test OpenIGTLink) + TARGET_LINK_LIBRARIES(igtl_imgmeta_test OpenIGTLink) + TARGET_LINK_LIBRARIES(igtl_lbmeta_test OpenIGTLink) + TARGET_LINK_LIBRARIES(igtl_point_test OpenIGTLink) + TARGET_LINK_LIBRARIES(igtl_tdata_test OpenIGTLink) + TARGET_LINK_LIBRARIES(igtl_trajectory_test OpenIGTLink) + TARGET_LINK_LIBRARIES(igtl_sensor_test OpenIGTLink) + TARGET_LINK_LIBRARIES(igtl_string_test OpenIGTLink) + TARGET_LINK_LIBRARIES(igtl_bind_test OpenIGTLink) + TARGET_LINK_LIBRARIES(igtl_ndarray_test OpenIGTLink) + TARGET_LINK_LIBRARIES(igtl_polydata_test OpenIGTLink) +ENDIF() + +ADD_TEST(igtl_image_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_image_test ) +ADD_TEST(igtl_header_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_header_test ) +ADD_TEST(igtl_transform_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_transform_test ) +ADD_TEST(igtl_status_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_status_test ) +ADD_TEST(igtl_util_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_util_test ) +ADD_TEST(igtl_position_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_position_test ) +ADD_TEST(igtl_capability_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_capability_test ) + +IF(${OpenIGTLink_PROTOCOL_VERSION} GREATER "1") + ADD_TEST(igtl_colortable_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_colortable_test ) + ADD_TEST(igtl_imgmeta_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_imgmeta_test ) + ADD_TEST(igtl_lbmeta_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_lbmeta_test ) + ADD_TEST(igtl_point_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_point_test ) + ADD_TEST(igtl_tdata_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_tdata_test ) + ADD_TEST(igtl_trajectory_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_trajectory_test ) + ADD_TEST(igtl_sensor_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_sensor_test ) + ADD_TEST(igtl_string_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_string_test ) + ADD_TEST(igtl_bind_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_bind_test ) + ADD_TEST(igtl_ndarray_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_ndarray_test ) + ADD_TEST(igtl_polydata_test_01 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/igtl_polydata_test ) +ENDIF() diff --git a/openigtlink/repo/Testing/igtlutil/igtl_bind_test.c b/openigtlink/repo/Testing/igtlutil/igtl_bind_test.c new file mode 100644 index 0000000..77c4094 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_bind_test.c @@ -0,0 +1,290 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_image.h" +#include "igtl_sensor.h" +#include "igtl_bind.h" +#include "igtl_util.h" +#include "igtl_transform.h" +#include +#include +#include + + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* Include serialized test data (gold standard) */ +#include "igtl_test_data_bind.h" +#include "igtl_test_data_transform.h" +#include "igtl_test_data_image.h" +#include "igtl_test_data_status.h" + +#pragma pack(1) + +/* + * Structure for byte array of test message body. + * Since sizes of all child messages in this test program are even, + * there is no padding inserted at the end of each child message. + * In general, a padding byte is added to the end of each message body, + * if the message body size is odd. + * + */ + +typedef struct { + igtl_float32 transform[12]; +} transform_message_body; + +typedef struct { + igtl_image_header iheader; /* image header */ + igtl_uint8 image[TEST_IMAGE_MESSAGE_SIZE]; +} image_message_body; + +typedef struct { + igtl_sensor_header sensor; + igtl_float64 value[6]; +} sensor_message_body; + +typedef struct { + transform_message_body transform; + image_message_body image; + sensor_message_body sensor; +} child_message_body; + +#pragma pack() + + +void generate_transform_body(transform_message_body * body) +{ + body->transform[0] = -0.954892f; + body->transform[1] = 0.196632f; + body->transform[2] = -0.222525f; + body->transform[3] = -0.196632f; + body->transform[4] = 0.142857f; + body->transform[5] = 0.970014f; + body->transform[6] = 0.222525f; + body->transform[7] = 0.970014f; + body->transform[8] = -0.0977491f; + body->transform[9] = 46.0531f; + body->transform[10] = 19.4709f; + body->transform[11] = 46.0531f; + + igtl_transform_convert_byte_order(body->transform); +} + + +igtl_uint64 generate_image_body(image_message_body * body) +{ + igtl_uint64 image_size; + + igtl_float32 spacing[] = {1.0f, 1.0f, 1.0f}; + igtl_float32 origin[] = {46.0531f, 19.4709f, 46.0531f}; + igtl_float32 norm_i[] = {-0.954892f, 0.196632f, -0.222525f}; + igtl_float32 norm_j[] = {-0.196632f, 0.142857f, 0.970014f}; + igtl_float32 norm_k[] = {0.222525f, 0.970014f, -0.0977491f}; + + /* Set data */ + body->iheader.header_version = 1; + body->iheader.num_components = 1; /* Scalar */ + body->iheader.scalar_type = 3; /* uint8 */ + body->iheader.endian = 2; /* Little endian */ + body->iheader.coord = 1; /* RAS */ + body->iheader.size[0] = 50; + body->iheader.size[1] = 50; + body->iheader.size[2] = 1; + + /* Dimensions */ + body->iheader.subvol_offset[0] = 0; + body->iheader.subvol_offset[1] = 0; + body->iheader.subvol_offset[2] = 0; + body->iheader.subvol_size[0] = 50; + body->iheader.subvol_size[1] = 50; + body->iheader.subvol_size[2] = 1; + + igtl_image_set_matrix(spacing, origin, norm_i, norm_j, norm_k, &(body->iheader)); + + /* Copy image data */ + memcpy((void*)body->image, (void*)test_image, TEST_IMAGE_MESSAGE_SIZE); + + /* Get image data size -- note that this should be done before byte order swapping. */ + image_size = igtl_image_get_data_size(&(body->iheader)); + + /* Swap byte order if necessary */ + igtl_image_convert_byte_order(&(body->iheader)); + + return image_size; +} + + +unsigned int generate_sensor_body(sensor_message_body * body) +{ + igtl_unit_data unit_data; + + /*igtl_uint64 crc;*/ + unsigned int value_size; + + /* Create unit (m/s^2) */ + igtl_unit_init(&unit_data); + unit_data.prefix = IGTL_UNIT_PREFIX_NONE; + unit_data.unit[0] = IGTL_UNIT_SI_BASE_METER; + unit_data.exp[0] = (igtl_int8) 1; + unit_data.unit[1] = IGTL_UNIT_SI_BASE_SECOND; + unit_data.exp[1] = (igtl_int8) -2; + + /* Set dummy sensor header and values */ + body->sensor.larray = 6; + body->sensor.status = 0; + body->sensor.unit = igtl_unit_pack(&(unit_data)); + + body->value[0] = 123456.78; + body->value[1] = 12345.678; + body->value[2] = 1234.5678; + body->value[3] = 123.45678; + body->value[4] = 12.345678; + body->value[5] = 1.2345678; + + value_size = igtl_sensor_get_data_size(&(body->sensor)); + igtl_sensor_convert_byte_order(&(body->sensor), body->value); + + return value_size; +} + + +int main( int argc, char * argv [] ) +{ + /* Message structures and byte array */ + igtl_header header; + void* bind_header; + child_message_body child_body; + + igtl_bind_info bind_info; + size_t bind_size; + size_t child_body_size; + int rh; /* Comparison result for header */ + int rb; /* Comparison result for BIND header section*/ + int rc; /* Comparison result for child body section */ + + int s; + + igtl_bind_init_info(&bind_info); + + /* Generate transform message */ + generate_transform_body(&(child_body.transform)); + + /* Generate image message */ + generate_image_body(&(child_body.image)); + + /* Generate sensor message */ + generate_sensor_body(&(child_body.sensor)); + + /* Set up BIND info structure */ + if (igtl_bind_alloc_info(&bind_info, 3) == 0) + { + return EXIT_FAILURE; + } + + strncpy(bind_info.child_info_array[0].type, "TRANSFORM", IGTL_HEADER_TYPE_SIZE); + strncpy(bind_info.child_info_array[0].name, "ChildTrans", IGTL_HEADER_NAME_SIZE); + bind_info.child_info_array[0].size = sizeof(transform_message_body); + bind_info.child_info_array[0].ptr = (void*)&child_body.transform; + + strncpy(bind_info.child_info_array[1].type, "IMAGE", IGTL_HEADER_TYPE_SIZE); + strncpy(bind_info.child_info_array[1].name, "ChildImage", IGTL_HEADER_NAME_SIZE); + bind_info.child_info_array[1].size = sizeof(image_message_body); + bind_info.child_info_array[1].ptr = (void*)&child_body.image; + + strncpy(bind_info.child_info_array[2].type, "SENSOR", IGTL_HEADER_TYPE_SIZE); + strncpy(bind_info.child_info_array[2].name, "ChildSensor", IGTL_HEADER_NAME_SIZE); + bind_info.child_info_array[2].size = sizeof(sensor_message_body); + bind_info.child_info_array[2].ptr = (void*)&child_body.sensor; + + bind_size = (size_t)igtl_bind_get_size(&bind_info, IGTL_TYPE_PREFIX_NONE); + bind_header = malloc(bind_size); + + + + if (bind_header == NULL) + { + igtl_bind_free_info(&bind_info); + return EXIT_FAILURE; + } + + igtl_bind_pack(&bind_info, bind_header, IGTL_TYPE_PREFIX_NONE); + + /* Calculate the sum of child body size and paddings (0 in this test program) */ + child_body_size = (size_t) + (bind_info.child_info_array[0].size + + bind_info.child_info_array[1].size + + bind_info.child_info_array[2].size); + + /* Set header */ + header.header_version = 1; + strncpy( (char*)&(header.name), "BIND", 12 ); + strncpy( (char*)&(header.device_name), "DeviceName", 20 ); + header.timestamp = 1234567892; + header.body_size = bind_size + sizeof(child_message_body); + header.crc = igtl_bind_get_crc(&bind_info, IGTL_TYPE_PREFIX_NONE, bind_header); + igtl_header_convert_byte_order( &(header) ); + + + /* Dumping data -- for testing */ + /* + FILE *fp; + fp = fopen("bind.bin", "w"); + fwrite(&(header), IGTL_HEADER_SIZE, 1, fp); + fwrite(bind_header, bind_size, 1, fp); + fwrite(&(child_body), child_body_size, 1, fp); + fclose(fp); + */ + + + /* Compare the serialized byte array with the gold standard */ + rh = memcmp((const void*)&header, (const void*)test_bind_message_header, IGTL_HEADER_SIZE); + rb = memcmp((const void*)bind_header, (const void*)test_bind_message_bind_header, bind_size); + rc = memcmp((const void*)&child_body, (const void*)test_bind_message_bind_body, child_body_size); + + igtl_bind_free_info(&bind_info); + free(bind_header); + + if (rh == 0 && rb == 0 && rc == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+bind_size+child_body_size; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&header, s); + + return EXIT_FAILURE; + } + +} + + + + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_capability_test.c b/openigtlink/repo/Testing/igtlutil/igtl_capability_test.c new file mode 100644 index 0000000..e0a0190 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_capability_test.c @@ -0,0 +1,103 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_capability.h" +#include "igtl_util.h" + +/* include test capability data and serialized capability message */ +#include "igtl_test_data_capability.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#define TEST_CAPABILITY_SIZE 256 + +#pragma pack(1) +struct capability_message { + igtl_header header; + unsigned char body[IGTL_HEADER_TYPE_SIZE*4]; +}; +#pragma pack() + + +int main( int argc, char * argv [] ) +{ + + igtl_capability_info info; + struct capability_message message; + int r; + int s; + + igtl_capability_alloc_info(&info, 4); + + /* Test structure size */ + if (sizeof(message) != IGTL_HEADER_SIZE+igtl_capability_get_length(&info)) + { + fprintf(stdout, "Invalid size of capability message structure.\n"); + return EXIT_FAILURE; + } + + strcpy((char*)info.typenames[0], "IMAGE"); + strcpy((char*)info.typenames[1], "GET_IMAGE"); + strcpy((char*)info.typenames[2], "TRANSFORM"); + strcpy((char*)info.typenames[3], "GET_TRANS"); + + igtl_capability_pack(&info, message.body); + + /* Create OpenIGTLink header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "CAPABILITY", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = igtl_capability_get_length(&info); + message.header.crc = igtl_capability_get_crc(&info, message.body); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for debugging */ + /* + FILE *fp; + fp = fopen("capability.bin", "w"); + fwrite(&(message), IGTL_HEADER_SIZE+igtl_capability_get_length(&info), 1, fp); + fclose(fp); + */ + + /* Compare the serialized byte array with the gold standard */ + r = memcmp((const void*)&message, (const void*)test_capability_message, + (size_t)(IGTL_HEADER_SIZE+igtl_capability_get_length(&info))); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+igtl_capability_get_length(&info); + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&message, s); + + return EXIT_FAILURE; + } +} diff --git a/openigtlink/repo/Testing/igtlutil/igtl_colortable_test.c b/openigtlink/repo/Testing/igtlutil/igtl_colortable_test.c new file mode 100644 index 0000000..1fb7a47 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_colortable_test.c @@ -0,0 +1,111 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_colortable.h" +#include "igtl_util.h" + +/* include test colortable data and serialized colortable message */ +#include "igtl_test_data_colortable.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#define TEST_COLORTABLE_SIZE 256 + +#pragma pack(1) +struct colortable_message { + igtl_header header; + igtl_colortable_header cheader; /* colortable header */ + igtl_uint8 table[TEST_COLORTABLE_SIZE]; +}; +#pragma pack() + + +int main( int argc, char * argv [] ) +{ + + struct colortable_message message; + igtl_uint64 table_size; + int r; + int s; + int i; + + /* Test structure size */ + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_COLORTABLE_HEADER_SIZE+TEST_COLORTABLE_SIZE) + { + fprintf(stdout, "Invalid size of colortable message structure.\n"); + return EXIT_FAILURE; + } + + /* Set COLORTABLE message */ + message.cheader.indexType = IGTL_COLORTABLE_INDEX_UINT8; + message.cheader.mapType = IGTL_COLORTABLE_MAP_UINT8; + for (i = 0; i < 256; i ++) + { + message.table[i] = i; + } + + /* Get image data size -- note that this should be done before byte order swapping. */ + table_size = igtl_colortable_get_table_size(&(message.cheader)); + + /* Swap byte order if necessary */ + igtl_colortable_convert_byte_order(&(message.cheader), (void*)&(message.table)); + + /* Create OpenIGTLink header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "COLORTABLE", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_COLORTABLE_HEADER_SIZE + table_size; + message.header.crc = igtl_colortable_get_crc(&(message.cheader), (void*)message.table); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for debugging */ + /* + FILE *fp; + fp = fopen("colortable.bin", "w"); + fwrite(&(message), IGTL_HEADER_SIZE+IGTL_COLORTABLE_HEADER_SIZE+TEST_COLORTABLE_SIZE, 1, fp); + fclose(fp); + */ + + /* Compare the serialized byte array with the gold standard */ + r = memcmp((const void*)&message, (const void*)test_colortable_message, + (size_t)(IGTL_HEADER_SIZE+IGTL_COLORTABLE_HEADER_SIZE)); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+IGTL_COLORTABLE_HEADER_SIZE+(int)table_size; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&message, s); + + return EXIT_FAILURE; + } +} diff --git a/openigtlink/repo/Testing/igtlutil/igtl_header_test.c b/openigtlink/repo/Testing/igtlutil/igtl_header_test.c new file mode 100644 index 0000000..ae2d7e0 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_header_test.c @@ -0,0 +1,73 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include "igtl_util.h" +#include "igtl_header.h" + + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +char barray[] = { + 0x00, 0x01, /* Version number */ + 0x54, 0x59, 0x50, 0x45, 0x4e, 0x41, 0x4d, 0x45, + 0x00, 0x00, 0x00, 0x00, /* TYPENAME */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd2, /* Time stamp */ + 0x00, 0x00, 0x00, 0x07, 0x50, 0x88, 0xFF, 0x06, /* Body size */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x7E, 0xA7, /* CRC */ +}; + + +int main( int argc, char * argv [] ) +{ + + igtl_header header; + + // Test structure size + if (sizeof(header) != IGTL_HEADER_SIZE) + { + fprintf(stdout, "Invalid size of header structure.\n"); + return EXIT_FAILURE; + } + + // Test binary + header.header_version = 1; + strncpy( header.name, "TYPENAME", 12 ); + strncpy( header.device_name, "DeviceName", 20 ); + header.timestamp = 1234567890; + header.body_size = 31415926534; + header.crc = 1343143; + + igtl_header_convert_byte_order( &header ); + + if (memcmp((const void*)&header, (const void*)barray, IGTL_HEADER_SIZE) == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print message as HEX values in STDERR for debug */ + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", IGTL_HEADER_SIZE); + igtl_message_dump_hex(stdout, (const void*)&header, IGTL_HEADER_SIZE); + + return EXIT_FAILURE; + } + +} diff --git a/openigtlink/repo/Testing/igtlutil/igtl_image_test.c b/openigtlink/repo/Testing/igtlutil/igtl_image_test.c new file mode 100644 index 0000000..707b860 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_image_test.c @@ -0,0 +1,130 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_image.h" +#include "igtl_util.h" + +/* include test image data and serialized image message */ +#include "igtl_test_data_image.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + + +#pragma pack(1) +struct image_message { + igtl_header header; + igtl_image_header iheader; /* image header */ + igtl_uint8 image[TEST_IMAGE_MESSAGE_SIZE]; +}; +#pragma pack() + + +int main( int argc, char * argv [] ) +{ + + struct image_message message; + int r; + igtl_uint64 image_size; + int s; + + igtl_float32 spacing[] = {1.0f, 1.0f, 1.0f}; + igtl_float32 origin[] = {46.0531f, 19.4709f, 46.0531f}; + igtl_float32 norm_i[] = {-0.954892f, 0.196632f, -0.222525f}; + igtl_float32 norm_j[] = {-0.196632f, 0.142857f, 0.970014f}; + igtl_float32 norm_k[] = {0.222525f, 0.970014f, -0.0977491f}; + + /* Test structure size */ + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_IMAGE_HEADER_SIZE+TEST_IMAGE_MESSAGE_SIZE) + { + fprintf(stdout, "Invalid size of image message structure.\n"); + return EXIT_FAILURE; + } + + /* Set data */ + message.iheader.header_version = 1; + message.iheader.num_components = 1; /* Scalar */ + message.iheader.scalar_type = 3; /* uint8 */ + message.iheader.endian = 2; /* Little endian */ + message.iheader.coord = 1; /* RAS */ + message.iheader.size[0] = 50; + message.iheader.size[1] = 50; + message.iheader.size[2] = 1; + + /* Dimensions */ + message.iheader.subvol_offset[0] = 0; + message.iheader.subvol_offset[1] = 0; + message.iheader.subvol_offset[2] = 0; + message.iheader.subvol_size[0] = 50; + message.iheader.subvol_size[1] = 50; + message.iheader.subvol_size[2] = 1; + + igtl_image_set_matrix(spacing, origin, norm_i, norm_j, norm_k, &(message.iheader)); + + /* Copy image data */ + memcpy((void*)message.image, (void*)test_image, TEST_IMAGE_MESSAGE_SIZE); + + /* Get image data size -- note that this should be done before byte order swapping. */ + image_size = igtl_image_get_data_size(&(message.iheader)); + + /* Swap byte order if necessary */ + igtl_image_convert_byte_order(&(message.iheader)); + + /* Create OpenIGTLink header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "IMAGE", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_IMAGE_HEADER_SIZE + image_size; + message.header.crc = igtl_image_get_crc(&(message.iheader), message.image); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for debugging */ + /* + FILE *fp; + fp = fopen("image.bin", "w"); + fwrite(&(message), IGTL_HEADER_SIZE+IGTL_IMAGE_HEADER_SIZE+image_size, 1, fp); + fclose(fp); + */ + + /* Compare the serialized byte array with the gold standard */ + r = memcmp((const void*)&message, (const void*)test_image_message, + (size_t)(IGTL_HEADER_SIZE+IGTL_IMAGE_HEADER_SIZE+image_size)); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+IGTL_IMAGE_HEADER_SIZE+ (int)image_size; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&message, s); + + return EXIT_FAILURE; + } +} diff --git a/openigtlink/repo/Testing/igtlutil/igtl_imgmeta_test.c b/openigtlink/repo/Testing/igtlutil/igtl_imgmeta_test.c new file mode 100644 index 0000000..19b5965 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_imgmeta_test.c @@ -0,0 +1,135 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_imgmeta.h" +#include "igtl_util.h" + +/* include test imgmeta data and serialized imgmeta message */ +#include "igtl_test_data_imgmeta.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#define TEST_IMGMETA_NUM 3 + +#pragma pack(1) +struct imgmeta_message { + igtl_header header; + igtl_imgmeta_element metalist[TEST_IMGMETA_NUM]; +}; +#pragma pack() + + +int main( int argc, char * argv [] ) +{ + + struct imgmeta_message message; + int r; + int s; + + /* Test structure size */ + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_IMGMETA_ELEMENT_SIZE*TEST_IMGMETA_NUM) + { + fprintf(stdout, "Invalid size of imgmeta message structure.\n"); + return EXIT_FAILURE; + } + + /* Image meta data 0 */ + strncpy((char*)&(message.metalist[0].name), "IMAGE_DESCRIPTION_0", 64); + strncpy((char*)&(message.metalist[0].device_name), "IMAGE_0", 20); + strncpy((char*)&(message.metalist[0].modality), "CT", 32); + strncpy((char*)&(message.metalist[0].patient_name), "PATIENT_0", 64); + strncpy((char*)&(message.metalist[0].patient_id), "PATIENT_ID_0", 64); + message.metalist[0].timestamp = 1234567892; + message.metalist[0].size[0] = 512; + message.metalist[0].size[1] = 512; + message.metalist[0].size[2] = 64; + message.metalist[0].scalar_type = IGTL_IMAGE_STYPE_TYPE_UINT16; + message.metalist[0].reserved = 0; + + /* Image meta data 1 */ + strncpy((char*)&(message.metalist[1].name), "IMAGE_DESCRIPTION_1", 64); + strncpy((char*)&(message.metalist[1].device_name), "IMAGE_1", 20); + strncpy((char*)&(message.metalist[1].modality), "MRI", 32); + strncpy((char*)&(message.metalist[1].patient_name), "PATIENT_1", 64); + strncpy((char*)&(message.metalist[1].patient_id), "PATIENT_ID_1", 64); + message.metalist[1].timestamp = 1234567896; + message.metalist[1].size[0] = 256; + message.metalist[1].size[1] = 128; + message.metalist[1].size[2] = 32; + message.metalist[1].scalar_type = IGTL_IMAGE_STYPE_TYPE_UINT16; + message.metalist[1].reserved = 0; + + /* Image meta data 2 */ + strncpy((char*)&(message.metalist[2].name), "IMAGE_DESCRIPTION_2", 64); + strncpy((char*)&(message.metalist[2].device_name), "IMAGE_2", 20); + strncpy((char*)&(message.metalist[2].modality), "PET", 32); + strncpy((char*)&(message.metalist[2].patient_name), "PATIENT_2", 64); + strncpy((char*)&(message.metalist[2].patient_id), "PATIENT_ID_2", 64); + message.metalist[2].timestamp = 1234567900; + message.metalist[2].size[0] = 256; + message.metalist[2].size[1] = 256; + message.metalist[2].size[2] = 32; + message.metalist[2].scalar_type = IGTL_IMAGE_STYPE_TYPE_UINT16; + message.metalist[2].reserved = 0; + + /* Swap byte order if necessary */ + igtl_imgmeta_convert_byte_order(message.metalist, TEST_IMGMETA_NUM); + + /* Create OpenIGTLink header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "IMGMETA", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_IMGMETA_ELEMENT_SIZE*TEST_IMGMETA_NUM; + message.header.crc = igtl_imgmeta_get_crc(message.metalist, TEST_IMGMETA_NUM); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for debugging */ + /* + FILE *fp; + fp = fopen("imgmeta.bin", "w"); + fwrite(&(message), IGTL_HEADER_SIZE+IGTL_IMGMETA_ELEMENT_SIZE*TEST_IMGMETA_NUM, 1, fp); + fclose(fp); + */ + + /* Compare the serialized byte array with the gold standard */ + r = memcmp((const void*)&message, (const void*)test_imgmeta_message, + (size_t)(IGTL_HEADER_SIZE+IGTL_IMGMETA_ELEMENT_SIZE*TEST_IMGMETA_NUM)); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+IGTL_IMGMETA_ELEMENT_SIZE*TEST_IMGMETA_NUM; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&message, s); + + return EXIT_FAILURE; + } +} diff --git a/openigtlink/repo/Testing/igtlutil/igtl_lbmeta_test.c b/openigtlink/repo/Testing/igtlutil/igtl_lbmeta_test.c new file mode 100644 index 0000000..e0f1529 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_lbmeta_test.c @@ -0,0 +1,138 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_lbmeta.h" +#include "igtl_util.h" + +/* include test lbmeta data and serialized lbmeta message */ +#include "igtl_test_data_lbmeta.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#define TEST_LBMETA_NUM 3 + +#pragma pack(1) +struct lbmeta_message { + igtl_header header; + igtl_lbmeta_element metalist[TEST_LBMETA_NUM]; +}; +#pragma pack() + + +int main( int argc, char * argv [] ) +{ + + struct lbmeta_message message; + int r; + int s; + + // Test structure size + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_LBMETA_ELEMENT_SIZE*TEST_LBMETA_NUM) + { + fprintf(stdout, "Invalid size of lbmeta message structure.\n"); + return EXIT_FAILURE; + } + + /* Label meta data 0 */ + strncpy((char*)&(message.metalist[0].name), "LABEL_DESCRIPTION_0", 64); + strncpy((char*)&(message.metalist[0].device_name), "LABEL_0", 20); + message.metalist[0].label = 1; + message.metalist[0].reserved = 0; + message.metalist[0].rgba[0] = 255; + message.metalist[0].rgba[1] = 0; + message.metalist[0].rgba[2] = 0; + message.metalist[0].rgba[3] = 255; + message.metalist[0].size[0] = 256; + message.metalist[0].size[1] = 128; + message.metalist[0].size[2] = 32; + strncpy((char*)&(message.metalist[0].owner), "IMAGE_0", 20); + + /* Label meta data 1 */ + strncpy((char*)&(message.metalist[1].name), "LABEL_DESCRIPTION_1", 64); + strncpy((char*)&(message.metalist[1].device_name), "LABEL_1", 20); + message.metalist[1].label = 2; + message.metalist[1].reserved = 0; + message.metalist[1].rgba[0] = 0; + message.metalist[1].rgba[1] = 255; + message.metalist[1].rgba[2] = 0; + message.metalist[1].rgba[3] = 255; + message.metalist[1].size[0] = 256; + message.metalist[1].size[1] = 128; + message.metalist[1].size[2] = 32; + strncpy((char*)&(message.metalist[1].owner), "IMAGE_0", 20); + + /* Label meta data 2 */ + strncpy((char*)&(message.metalist[2].name), "LABEL_DESCRIPTION_2", 64); + strncpy((char*)&(message.metalist[2].device_name), "LABEL_2", 20); + message.metalist[2].label = 3; + message.metalist[2].reserved = 0; + message.metalist[2].rgba[0] = 0; + message.metalist[2].rgba[1] = 0; + message.metalist[2].rgba[2] = 255; + message.metalist[2].rgba[3] = 255; + message.metalist[2].size[0] = 256; + message.metalist[2].size[1] = 128; + message.metalist[2].size[2] = 32; + strncpy((char*)&(message.metalist[2].owner), "IMAGE_0", 20); + + /* Swap byte order if necessary */ + igtl_lbmeta_convert_byte_order(message.metalist, TEST_LBMETA_NUM); + + /* Create OpenIGTLink header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "LBMETA", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_LBMETA_ELEMENT_SIZE*TEST_LBMETA_NUM; + message.header.crc = igtl_lbmeta_get_crc(message.metalist, TEST_LBMETA_NUM); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for debugging */ + /* + FILE *fp; + fp = fopen("lbmeta.bin", "w"); + fwrite(&(message), IGTL_HEADER_SIZE+IGTL_LBMETA_ELEMENT_SIZE*TEST_LBMETA_NUM, 1, fp); + fclose(fp); + */ + + /* Compare the serialized byte array with the gold standard */ + r = memcmp((const void*)&message, (const void*)test_lbmeta_message, + (size_t)(IGTL_HEADER_SIZE+IGTL_LBMETA_ELEMENT_SIZE*TEST_LBMETA_NUM)); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+IGTL_LBMETA_ELEMENT_SIZE*TEST_LBMETA_NUM; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&message, s); + + return EXIT_FAILURE; + } +} diff --git a/openigtlink/repo/Testing/igtlutil/igtl_ndarray_test.c b/openigtlink/repo/Testing/igtlutil/igtl_ndarray_test.c new file mode 100644 index 0000000..b0ce50b --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_ndarray_test.c @@ -0,0 +1,140 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_ndarray.h" +#include "igtl_util.h" +#include +#include +#include + + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* Include serialized test data (gold standard) */ +#include "igtl_test_data_ndarray.h" + + +int main( int argc, char * argv [] ) +{ + /*** Message structures and byte array ***/ + igtl_header header; + void * body; + + igtl_ndarray_info info; + size_t body_size; + igtl_uint16 size[3]; + + int i, j, k; + igtl_float64 * array; + + int rh; /* Comparison result for header */ + int rb; /* Comparison result for body */ + + int s; + + /*** Generate test data ***/ + igtl_ndarray_init_info(&info); + info.type = IGTL_NDARRAY_STYPE_TYPE_FLOAT64; + /* Array size is 5x4x3 */ + info.dim = 3; + size[0] = 5; + size[1] = 4; + size[2] = 3; + + if (igtl_ndarray_alloc_info(&info, size) == 0) + { + return EXIT_FAILURE; + } + + /* Generate dummy array */ + array = (igtl_float64 *) info.array; + for (i = 0; i < 5; i ++) + { + for (j = 0; j < 4; j ++) + { + for (k = 0; k < 3; k ++) + { + array[i*(4*3) + j*3 + k] = (igtl_float64) (i*(4*3) + j*3 + k); + } + } + } + + /** Allocate memory for pack **/ + body_size = (size_t)igtl_ndarray_get_size(&info, IGTL_TYPE_PREFIX_NONE); + body = malloc(body_size); + + if (body == NULL) + { + igtl_ndarray_free_info(&info); + return EXIT_FAILURE; + } + + igtl_ndarray_pack(&info, body, IGTL_TYPE_PREFIX_NONE); + + /*** Set OpenIGTLink header ***/ + header.header_version = 1; + strncpy( (char*)&(header.name), "NDARRAY", 12 ); + strncpy( (char*)&(header.device_name), "DeviceName", 20 ); + header.timestamp = 1234567892; + header.body_size = body_size; + header.crc = igtl_ndarray_get_crc(&info, IGTL_TYPE_PREFIX_NONE, body); + igtl_header_convert_byte_order( &(header) ); + + /* Dumping data -- for testing */ + /* + FILE *fp; + fp = fopen("ndarray.bin", "w"); + fwrite(&(header), IGTL_HEADER_SIZE, 1, fp); + fwrite(body, body_size, 1, fp); + fclose(fp); + */ + + rh = memcmp((const void*)&header, (const void*)test_ndarray_message_header, IGTL_HEADER_SIZE); + rb = memcmp((const void*)body, (const void*)test_ndarray_message_body, body_size); + + igtl_ndarray_free_info(&info); + free(body); + + if (rh == 0 && rb == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE + body_size; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&header, s); + + return EXIT_FAILURE; + } + +} + + + + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_point_test.c b/openigtlink/repo/Testing/igtlutil/igtl_point_test.c new file mode 100644 index 0000000..2e368cf --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_point_test.c @@ -0,0 +1,136 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_point.h" +#include "igtl_util.h" + +/* include test point data and serialized point message */ +#include "igtl_test_data_point.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#define TEST_POINT_NUM 3 + +#pragma pack(1) +struct point_message { + igtl_header header; + igtl_point_element pointlist[TEST_POINT_NUM]; +}; +#pragma pack() + + +int main( int argc, char * argv [] ) +{ + + struct point_message message; + int r; + int s; + + /* Test structure size */ + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_POINT_ELEMENT_SIZE*TEST_POINT_NUM) + { + fprintf(stdout, "Invalid size of point message structure.\n"); + return EXIT_FAILURE; + } + + /* Point data 0 */ + strncpy((char*)&(message.pointlist[0].name), "POINT_DESCRIPTION_0", 64); + strncpy((char*)&(message.pointlist[0].group_name), "Landmark", 32); + message.pointlist[0].rgba[0] = 255; + message.pointlist[0].rgba[1] = 0; + message.pointlist[0].rgba[2] = 0; + message.pointlist[0].rgba[3] = 255; + message.pointlist[0].position[0] = 10.0; + message.pointlist[0].position[1] = 15.0; + message.pointlist[0].position[2] = 20.0; + message.pointlist[0].radius = 5.0; + strncpy((char*)&(message.pointlist[0].owner), "IMAGE_0", 20); + + /* Point data 1 */ + strncpy((char*)&(message.pointlist[1].name), "POINT_DESCRIPTION_1", 64); + strncpy((char*)&(message.pointlist[1].group_name), "Landmark", 32); + message.pointlist[1].rgba[0] = 0; + message.pointlist[1].rgba[1] = 255; + message.pointlist[1].rgba[2] = 0; + message.pointlist[1].rgba[3] = 255; + message.pointlist[1].position[0] = 25.0; + message.pointlist[1].position[1] = 30.0; + message.pointlist[1].position[2] = 35.0; + message.pointlist[1].radius = 3.0; + strncpy((char*)&(message.pointlist[1].owner), "IMAGE_0", 20); + + /* Point data 2 */ + strncpy((char*)&(message.pointlist[2].name), "POINT_DESCRIPTION_2", 64); + strncpy((char*)&(message.pointlist[2].group_name), "Landmark", 32); + message.pointlist[2].rgba[0] = 0; + message.pointlist[2].rgba[1] = 0; + message.pointlist[2].rgba[2] = 255; + message.pointlist[2].rgba[3] = 255; + message.pointlist[2].position[0] = 40.0; + message.pointlist[2].position[1] = 45.0; + message.pointlist[2].position[2] = 50.0; + message.pointlist[2].radius = 1.0; + strncpy((char*)&(message.pointlist[2].owner), "IMAGE_0", 20); + + /* Swap byte order if necessary */ + igtl_point_convert_byte_order(message.pointlist, TEST_POINT_NUM); + + /* Create OpenIGTLink header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "POINT", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_POINT_ELEMENT_SIZE*TEST_POINT_NUM; + message.header.crc = igtl_point_get_crc(message.pointlist, TEST_POINT_NUM); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for debugging */ + /* + FILE *fp; + fp = fopen("point.bin", "w"); + fwrite(&(message), IGTL_HEADER_SIZE+IGTL_POINT_ELEMENT_SIZE*TEST_POINT_NUM, 1, fp); + fclose(fp); + */ + + /* Compare the serialized byte array with the gold standard */ + r = memcmp((const void*)&message, (const void*)test_point_message, + (size_t)(IGTL_HEADER_SIZE+IGTL_POINT_ELEMENT_SIZE*TEST_POINT_NUM)); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+IGTL_POINT_ELEMENT_SIZE*TEST_POINT_NUM; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&message, s); + + return EXIT_FAILURE; + } +} diff --git a/openigtlink/repo/Testing/igtlutil/igtl_polydata_test.c b/openigtlink/repo/Testing/igtlutil/igtl_polydata_test.c new file mode 100644 index 0000000..e9f89a0 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_polydata_test.c @@ -0,0 +1,185 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_polydata.h" +#include "igtl_util.h" +#include +#include +#include + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* Include serialized test data (gold standard) */ +#include "igtl_test_data_polydata.h" + +int main( int argc, char * argv [] ) +{ + /*** Message structures and byte array ***/ + igtl_header header; + void * body; + + igtl_polydata_info info; + + int rh; /* Comparison result for header */ + int rb; /* Comparison result for body */ + + unsigned int i; + int s; + igtl_float32 * ptr_f; + igtl_uint32 * ptr_i; + igtl_uint64 body_size; + + + static igtl_float32 points[8][3]={{0,0,0}, {1,0,0}, {1,1,0}, {0,1,0}, + {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1}}; + static igtl_uint32 poly[6][4]={{0,1,2,3}, {4,5,6,7}, {0,1,5,4}, + {1,2,6,5}, {2,3,7,6}, {3,0,4,7}}; + static igtl_float32 attribute[8]={0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + + /*** Generate test data ***/ + /* Note that the size of polygon data (or other cell data) is calculated by + * number of polygons * (number of points + 1) + * '+ 1' is required because of the number of points in the polygon (uint32) + * is stored at the begining of polygon data. + */ + igtl_polydata_init_info(&info); + info.header.npoints = 8; + info.header.nvertices = 0; + info.header.size_vertices = 0; + info.header.nlines = 0; + info.header.size_lines = 0; + info.header.npolygons = 6; + info.header.size_polygons = 6 * ((4+1) * sizeof(igtl_float32)); + info.header.ntriangle_strips = 0; + info.header.size_triangle_strips = 0; + info.header.nattributes = 1; + + if (igtl_polydata_alloc_info(&info) == 0) + { + return EXIT_FAILURE; + } + + /*** Substitute cube point data ***/ + if (info.points) + { + ptr_f = info.points; + for (i = 0; i < info.header.npoints; i ++) + { + *(ptr_f++) = points[i][0]; + *(ptr_f++) = points[i][1]; + *(ptr_f++) = points[i][2]; + } + } + else + { + return EXIT_FAILURE; + } + + /*** Substitute polygon data ***/ + if (info.polygons) + { + ptr_i = info.polygons; + for (i = 0; i < info.header.npolygons; i ++) + { + *(ptr_i++) = 4; /* Number of points in the polygon */ + *(ptr_i++) = poly[i][0]; + *(ptr_i++) = poly[i][1]; + *(ptr_i++) = poly[i][2]; + *(ptr_i++) = poly[i][3]; + } + } + + /*** Substitute attribute data ***/ + if (info.attributes) + { + info.attributes[0].type = IGTL_POLY_ATTR_TYPE_SCALAR; + info.attributes[0].ncomponents = 1; + info.attributes[0].n = 8; + info.attributes[0].name = malloc(5); + strcpy(info.attributes[0].name, "attr"); + info.attributes[0].data = malloc(sizeof(igtl_float32) * 8); + ptr_f = info.attributes[0].data; + for (i = 0; i < 8; i ++) + { + *(ptr_f++) = attribute[i]; + } + } + + /** Allocate memory for pack **/ + body_size = igtl_polydata_get_size(&info, IGTL_TYPE_PREFIX_NONE); + body = malloc((igtl_uint32)body_size); + + if (body == NULL) + { + igtl_polydata_free_info(&info); + return EXIT_FAILURE; + } + + igtl_polydata_pack(&info, body, IGTL_TYPE_PREFIX_NONE); + + /*** Set OpenIGTLink header ***/ + header.header_version = 1; + strncpy( (char*)&(header.name), "POLYDATA", 12 ); + strncpy( (char*)&(header.device_name), "DeviceName", 20 ); + header.timestamp = 1234567892; + header.body_size = body_size; + header.crc = igtl_polydata_get_crc(&info, IGTL_TYPE_PREFIX_NONE, body); + igtl_header_convert_byte_order( &(header) ); + + /* Dumping data -- for testing */ + /* + FILE *fp; + fp = fopen("polydata.bin", "w"); + fwrite(&(header), IGTL_HEADER_SIZE, 1, fp); + fwrite(body, body_size, 1, fp); + fclose(fp); + */ + + rh = memcmp((const void*)&header, (const void*)test_polydata_message_header, IGTL_HEADER_SIZE); + rb = memcmp((const void*)body, (const void*)test_polydata_message_body, (size_t) body_size); + + igtl_polydata_free_info(&info); + free(body); + + if (rh == 0 && rb == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE + (int)body_size; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&header, s); + + return EXIT_FAILURE; + } + +} + + + + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_position_test.c b/openigtlink/repo/Testing/igtlutil/igtl_position_test.c new file mode 100644 index 0000000..cfbc7ed --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_position_test.c @@ -0,0 +1,103 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_position.h" +#include "igtl_util.h" +#include +#include + + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* The decimal is rounded when it is converted to IEEE 754 floating point */ + +/* Include serialized test data (gold standard) */ +#include "igtl_test_data_position.h" + +#pragma pack(1) +struct position_message { + igtl_header header; + igtl_position position; +}; +#pragma pack() + +int main( int argc, char * argv [] ) +{ + + struct position_message message; + int r; + + // Test structure size + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_POSITION_MESSAGE_DEFAULT_SIZE) + { + fprintf(stdout, "Invalid size of position message structure.\n"); + return EXIT_FAILURE; + } + + /* Set dummy position */ + message.position.position[0] = 46.0531f; + message.position.position[1] = 19.4709f; + message.position.position[2] = 46.0531f; + + message.position.quaternion[0] = 0.0; + message.position.quaternion[1] = 0.5773502691f; + message.position.quaternion[2] = 0.5773502692f; + message.position.quaternion[3] = 0.3333333333f; + + igtl_position_convert_byte_order(&(message.position)); + + /* Set header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "POSITION", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_POSITION_MESSAGE_DEFAULT_SIZE; + message.header.crc = igtl_position_get_crc(&(message.position)); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for testing */ + /* + FILE *fp; + fp = fopen("position.bin", "w"); + fwrite(&(message.header), IGTL_HEADER_SIZE+IGTL_POSITION_MESSAGE_DEFAULT_SIZE, 1, fp); + fclose(fp); + */ + + /* Compare the serialized byte array with the gold standard */ + + r = memcmp((const void*)&message, (const void*)test_position_message, + IGTL_HEADER_SIZE+IGTL_POSITION_MESSAGE_DEFAULT_SIZE); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print message as HEX values in STDERR for debug */ + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", IGTL_HEADER_SIZE+IGTL_POSITION_MESSAGE_DEFAULT_SIZE); + igtl_message_dump_hex(stdout, (const void*)&message, IGTL_HEADER_SIZE+IGTL_POSITION_MESSAGE_DEFAULT_SIZE); + + return EXIT_FAILURE; + } + +} + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_sensor_test.c b/openigtlink/repo/Testing/igtlutil/igtl_sensor_test.c new file mode 100644 index 0000000..0852552 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_sensor_test.c @@ -0,0 +1,128 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_sensor.h" +#include "igtl_util.h" +#include +#include + + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* Include serialized test data (gold standard) */ +#include "igtl_test_data_sensor.h" + +#pragma pack(1) + +/* Test sensor message data (6-ch 64-bit float data, m/s^2) */ +struct sensor_message { + igtl_header header; + igtl_sensor_header sensor; + igtl_float64 value[6]; +}; +#pragma pack() + +int main( int argc, char * argv [] ) +{ + + struct sensor_message message; + igtl_unit_data unit_data; + + /*igtl_uint64 crc;*/ + unsigned int value_size; + int r; + int s; + + // Test structure size + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_SENSOR_HEADER_SIZE+sizeof(igtl_float64)*6) + { + fprintf(stdout, "Invalid size of sensor message structure.\n"); + return EXIT_FAILURE; + } + + /* Create unit (m/s^2) */ + igtl_unit_init(&unit_data); + unit_data.prefix = IGTL_UNIT_PREFIX_NONE; + unit_data.unit[0] = IGTL_UNIT_SI_BASE_METER; + unit_data.exp[0] = (igtl_int8) 1; + unit_data.unit[1] = IGTL_UNIT_SI_BASE_SECOND; + unit_data.exp[1] = (igtl_int8) -2; + + /* Set dummy sensor header and values */ + message.sensor.larray = 6; + message.sensor.status = 0; + message.sensor.unit = igtl_unit_pack(&(unit_data)); + + message.value[0] = 123456.78; + message.value[1] = 12345.678; + message.value[2] = 1234.5678; + message.value[3] = 123.45678; + message.value[4] = 12.345678; + message.value[5] = 1.2345678; + + value_size = igtl_sensor_get_data_size(&(message.sensor)); + igtl_sensor_convert_byte_order(&(message.sensor), message.value); + + /* Set header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "SENSOR", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_SENSOR_HEADER_SIZE + value_size; + message.header.crc = igtl_sensor_get_crc(&(message.sensor), message.value); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for testing */ + + /* + FILE *fp; + fp = fopen("sensor.bin", "w"); + fwrite(&(message.header), IGTL_HEADER_SIZE+IGTL_SENSOR_HEADER_SIZE + value_size, 1, fp); + fclose(fp); + */ + + + /* Compare the serialized byte array with the gold standard */ + + r = memcmp((const void*)&message, (const void*)test_sensor_message, + IGTL_HEADER_SIZE+IGTL_SENSOR_HEADER_SIZE+value_size); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+IGTL_SENSOR_HEADER_SIZE+value_size; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&message, s); + + return EXIT_FAILURE; + } + +} + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_status_test.c b/openigtlink/repo/Testing/igtlutil/igtl_status_test.c new file mode 100644 index 0000000..f856f7c --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_status_test.c @@ -0,0 +1,112 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_status.h" +#include "igtl_util.h" +#include +#include + + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* Include serialized test data (gold standard) */ +#include "igtl_test_data_status.h" + +#define STR_ERROR_NAME "ACTUATOR_DISABLED" /* within 20 characters */ +#define STR_ERROR_MESSAGE "Actuator A is disabled." + +#pragma pack(1) +struct status_message { + igtl_header header; + igtl_status_header status; + char err_msg[sizeof(STR_ERROR_MESSAGE)]; +}; +#pragma pack() + +int main( int argc, char * argv [] ) +{ + + struct status_message message; + /*igtl_uint64 crc;*/ + unsigned int msglen; + int r; + int s; + + // Test structure size + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_STATUS_HEADER_SIZE+sizeof(STR_ERROR_MESSAGE)) + { + fprintf(stdout, "Invalid size of image message structure.\n"); + return EXIT_FAILURE; + } + + // Test binary + msglen = sizeof(STR_ERROR_MESSAGE); + + /* Set dummy status */ + message.status.code = IGTL_STATUS_DISABLED; + message.status.subcode = 0x0A; + strcpy(message.err_msg, STR_ERROR_MESSAGE); + strncpy(message.status.error_name, STR_ERROR_NAME, 20); + + igtl_status_convert_byte_order(&message.status); + + /* Set header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "STATUS", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_STATUS_HEADER_SIZE + msglen; + message.header.crc = igtl_status_get_crc(&(message.status), msglen, message.err_msg); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for testing */ + + /* + FILE *fp; + fp = fopen("status.bin", "w"); + fwrite(&(message.header), IGTL_HEADER_SIZE+IGTL_STATUS_HEADER_SIZE + msglen, 1, fp); + fclose(fp); + */ + + + /* Compare the serialized byte array with the gold standard */ + r = memcmp((const void*)&message, (const void*)test_status_message, + IGTL_HEADER_SIZE+IGTL_STATUS_HEADER_SIZE+msglen); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+IGTL_STATUS_HEADER_SIZE+msglen; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&message, s); + + return EXIT_FAILURE; + } + +} + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_string_test.c b/openigtlink/repo/Testing/igtlutil/igtl_string_test.c new file mode 100644 index 0000000..32b4bec --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_string_test.c @@ -0,0 +1,111 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_string.h" +#include "igtl_util.h" +#include +#include + + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* Include serialized test data (gold standard) */ +#include "igtl_test_data_string.h" + +#pragma pack(1) + +#define IGTL_STRING_TEST_STRING "Welcome to OpenIGTLink" +#define IGTL_STRING_TEST_STRING_LEN 22 + +/* Test string message data (6-ch 64-bit float data, m/s^2) */ +struct string_message { + igtl_header header; + igtl_string_header string_header; + igtl_uint8 string[IGTL_STRING_TEST_STRING_LEN]; +}; +#pragma pack() + +int main( int argc, char * argv [] ) +{ + + struct string_message message; + + /*igtl_uint64 crc;*/ + int r; + int s; + + // Test structure size + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_STRING_HEADER_SIZE+IGTL_STRING_TEST_STRING_LEN) + { + fprintf(stdout, "Invalid size of image message structure.\n"); + return EXIT_FAILURE; + } + + /* Set dummy string header and values */ + message.string_header.encoding = 3; + message.string_header.length = IGTL_STRING_TEST_STRING_LEN; + strncpy((char*)message.string, IGTL_STRING_TEST_STRING, IGTL_STRING_TEST_STRING_LEN); + igtl_string_convert_byte_order(&(message.string_header)); + + /* Set header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "STRING", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_STRING_HEADER_SIZE + IGTL_STRING_TEST_STRING_LEN; + message.header.crc = igtl_string_get_crc(&(message.string_header), (void*) message.string); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for testing */ + + /* + FILE *fp; + fp = fopen("string.bin", "w"); + fwrite(&(message.header), IGTL_HEADER_SIZE+IGTL_STRING_HEADER_SIZE + IGTL_STRING_TEST_STRING_LEN, 1, fp); + fclose(fp); + */ + + /* Compare the serialized byte array with the gold standard */ + + r = memcmp((const void*)&message, (const void*)test_string_message, + IGTL_HEADER_SIZE+IGTL_STRING_HEADER_SIZE+IGTL_STRING_TEST_STRING_LEN); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+IGTL_STRING_HEADER_SIZE+IGTL_STRING_TEST_STRING_LEN; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + igtl_message_dump_hex(stdout, (const void*)&message, s); + + return EXIT_FAILURE; + } + +} + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_tdata_test.c b/openigtlink/repo/Testing/igtlutil/igtl_tdata_test.c new file mode 100644 index 0000000..1937991 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_tdata_test.c @@ -0,0 +1,149 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_tdata.h" +#include "igtl_util.h" + +/* include test tdata data and serialized tdata message */ +#include "igtl_test_data_tdata.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#define TEST_TDATA_NUM 3 + +#pragma pack(1) +struct tdata_message { + igtl_header header; + igtl_tdata_element tlist[TEST_TDATA_NUM]; +}; +#pragma pack() + + +int main( int argc, char * argv [] ) +{ + + struct tdata_message message; + int r; + int s; + + // Test structure size + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_TDATA_ELEMENT_SIZE*TEST_TDATA_NUM) + { + fprintf(stdout, "Invalid size of tdata message structure.\n"); + return EXIT_FAILURE; + } + + /* Tracking data 0 */ + strncpy((char*)&(message.tlist[0].name), "Tracker0", 20); + message.tlist[0].type = IGTL_TDATA_TYPE_6D; + message.tlist[0].reserved = 0; + message.tlist[0].transform[0] = -0.954892f; + message.tlist[0].transform[1] = 0.196632f; + message.tlist[0].transform[2] = -0.222525f; + message.tlist[0].transform[3] = -0.196632f; + message.tlist[0].transform[4] = 0.142857f; + message.tlist[0].transform[5] = 0.970014f; + message.tlist[0].transform[6] = 0.222525f; + message.tlist[0].transform[7] = 0.970014f; + message.tlist[0].transform[8] = -0.0977491f; + message.tlist[0].transform[9] = 46.0531f; + message.tlist[0].transform[10] = 19.4709f; + message.tlist[0].transform[11] = 46.0531f; + + /* Tracking data 1 */ + strncpy((char*)&(message.tlist[1].name), "Tracker1", 20); + message.tlist[1].type = IGTL_TDATA_TYPE_6D; + message.tlist[1].reserved = 0; + message.tlist[1].transform[0] = -0.954892f; + message.tlist[1].transform[1] = 0.196632f; + message.tlist[1].transform[2] = -0.222525f; + message.tlist[1].transform[3] = -0.196632f; + message.tlist[1].transform[4] = 0.142857f; + message.tlist[1].transform[5] = 0.970014f; + message.tlist[1].transform[6] = 0.222525f; + message.tlist[1].transform[7] = 0.970014f; + message.tlist[1].transform[8] = -0.0977491f; + message.tlist[1].transform[9] = 46.0531f; + message.tlist[1].transform[10] = 19.4709f; + message.tlist[1].transform[11] = 46.0531f; + + /* Tracking data 2 */ + strncpy((char*)&(message.tlist[2].name), "Tracker2", 20); + message.tlist[2].type = IGTL_TDATA_TYPE_6D; + message.tlist[2].reserved = 0; + message.tlist[2].transform[0] = -0.954892f; + message.tlist[2].transform[1] = 0.196632f; + message.tlist[2].transform[2] = -0.222525f; + message.tlist[2].transform[3] = -0.196632f; + message.tlist[2].transform[4] = 0.142857f; + message.tlist[2].transform[5] = 0.970014f; + message.tlist[2].transform[6] = 0.222525f; + message.tlist[2].transform[7] = 0.970014f; + message.tlist[2].transform[8] = -0.0977491f; + message.tlist[2].transform[9] = 46.0531f; + message.tlist[2].transform[10] = 19.4709f; + message.tlist[2].transform[11] = 46.0531f; + + + /* Swap byte order if necessary */ + igtl_tdata_convert_byte_order(message.tlist, TEST_TDATA_NUM); + + /* Create OpenIGTLink header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "TDATA", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_TDATA_ELEMENT_SIZE*TEST_TDATA_NUM; + message.header.crc = igtl_tdata_get_crc(message.tlist, TEST_TDATA_NUM); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for debugging */ + /* + FILE *fp; + fp = fopen("tdata.bin", "w"); + fwrite(&(message), IGTL_HEADER_SIZE+IGTL_TDATA_ELEMENT_SIZE*TEST_TDATA_NUM, 1, fp); + fclose(fp); + */ + + + /* Compare the serialized byte array with the gold standard */ + r = memcmp((const void*)&message, (const void*)test_tdata_message, + (size_t)(IGTL_HEADER_SIZE+IGTL_TDATA_ELEMENT_SIZE*TEST_TDATA_NUM)); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+IGTL_TDATA_ELEMENT_SIZE*TEST_TDATA_NUM; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + /*igtl_message_dump_hex(stdout, (const void*)&message, s);*/ + + return EXIT_FAILURE; + } +} diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_bind.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_bind.h new file mode 100644 index 0000000..bee3711 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_bind.h @@ -0,0 +1,266 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy status data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_BIND_H +#define __IGTL_TEST_DATA_BIND_H + +unsigned char test_bind_message_header[] = { + 0x00, 0x01, /* Version number */ + 0x42, 0x49, 0x4e, 0x44, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* BIND */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xd8, /* Body size */ + 0xd3, 0x4d, 0x56, 0xba, 0x63, 0xaf, 0x8a, 0x6a, /* CRC */ +}; + +unsigned char test_bind_message_bind_header[] = { /* 98 bytes */ + + 0x00, 0x03, /* Number of child messages */ + + 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x4f, 0x52, + 0x4d, 0x00, 0x00, 0x00, /* Device type 0 (TRANSFORM) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, /* Data size 0 */ + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device type 1 (IMAGE) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0c, /* Data size 1 */ + 0x53, 0x45, 0x4e, 0x53, 0x4f, 0x52, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device type 2 (SENSOR)*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, /* Body size 2 */ + + 0x00, 0x22, /* Length of device name table */ + + 0x43, 0x68, 0x69, 0x6c, 0x64, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x00, /* Device name 0 ("ChildTrans") */ + + 0x43, 0x68, 0x69, 0x6c, 0x64, 0x49, 0x6d, 0x61, + 0x67, 0x65, 0x00, /* Device name 1 ("ChildImage") */ + 0x43, 0x68, 0x69, 0x6c, 0x64, 0x53, 0x65, 0x6e, + 0x73, 0x6f, 0x72, 0x00, /* Device name 2 ("ChildSensor") */ + +}; + + +unsigned char test_bind_message_bind_body[] = { /* 48+2572+58 = 2678 bytes */ + + /* TRANSFORM */ + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, /* tx, ty */ + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, /* tz, sx */ + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, /* sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, /* nx, ny */ + 0xBD, 0xC8, 0x30, 0xAE, 0x42, 0x38, 0x36, 0x60, /* nz, px */ + 0x41, 0x9B, 0xC4, 0x67, 0x42, 0x38, 0x36, 0x60, /* py, pz */ + + /* IMAGE */ + /* Image header */ + 0x00, 0x01, /* Version number */ + 0x01, /* Number of components (scalar) */ + 0x03, /* Scalar type (8-bit unsigned int) */ + 0x02, /* Little endian */ + 0x01, /* Image coordinate */ + 0x00, 0x32, 0x00, 0x32, 0x00, 0x01, /* Number of pixels */ + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, + 0xBE, 0x63, 0xDD, 0x98, /* tx, ty, tz */ + 0xBE, 0x49, 0x59, 0xE6, 0x3E, 0x12, 0x49, 0x1B, + 0x3F, 0x78, 0x52, 0xD6, /* sx, sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, + 0xBD, 0xC8, 0x30, 0xAE, /* nx, ny, nz */ + 0x42, 0x38, 0x36, 0x60, 0x41, 0x9B, 0xC4, 0x67, + 0x42, 0x38, 0x36, 0x60, /* px, py, pz */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Starting index of subvolume */ + 0x00, 0x32, 0x00, 0x32, 0x00, 0x01, /* Number of pixels in subvolume */ + + /* Image data */ + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x44, 0x14, 0xfd, 0x27, 0x13, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x77, 0x9a, 0xfd, 0xfd, 0xfd, 0xfd, 0x52, 0xfd, 0x98, 0xfd, 0x2f, + 0xfd, 0x2d, 0x46, 0x1f, 0x0d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2b, 0xfd, 0xfd, 0x86, 0xfd, 0xfd, 0xfd, 0xfd, 0x66, 0xfd, 0x00, + 0xfd, 0x22, 0x83, 0xfd, 0x34, 0x79, 0x62, 0x00, 0x23, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x08, 0x39, 0xfd, 0x5c, 0x76, 0xfd, 0x20, 0xfd, 0x45, 0xfd, 0xfd, 0x58, + 0x4f, 0xb0, 0xfd, 0x73, 0xfd, 0x13, 0xa0, 0x23, 0x44, 0x26, 0xfd, 0x03, 0x9e, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2c, 0x0d, 0x16, 0xfd, 0x1b, 0x67, 0x59, 0x51, 0x72, 0x41, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x1c, 0x27, 0x9c, 0x3d, 0x4e, 0x95, 0xfd, 0x53, 0xfd, 0x26, 0x20, + 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0c, 0xd5, 0x22, 0x09, 0x01, 0x67, 0xfd, 0x98, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0xfd, 0x6f, 0x74, 0xfd, + 0xfd, 0x34, 0x80, 0x61, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x00, 0x2f, 0x44, 0xfd, 0x7b, 0x5e, 0xb9, 0x5e, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x28, 0x06, 0x7e, 0x43, 0x09, 0x00, 0x85, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x78, 0xfd, 0xfd, 0x9a, 0x9c, 0xb6, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x0f, 0x36, 0xfd, 0x05, 0x01, 0x31, 0xa0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x25, 0x01, 0x2a, 0xfd, 0x24, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x15, 0x18, 0x6d, 0x2a, 0xa2, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xa8, 0xfd, 0xfd, 0x17, 0x14, 0x40, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x36, 0xfd, 0x18, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x01, 0xfd, 0x7c, 0x64, 0x74, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5d, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x08, 0x66, 0xfd, 0xfd, + 0x5f, 0x3b, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xc0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xb9, 0xfd, + 0xfd, 0xfd, 0x71, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x95, 0x6c, 0xca, 0x08, 0x39, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x09, + 0x39, 0x09, 0x8d, 0x20, 0xfd, 0x06, 0x34, 0x19, 0x19, 0x19, 0x19, 0x33, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0a, 0xfd, 0xb0, 0x30, 0x9e, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x06, 0xfd, 0xfd, 0x64, 0xfd, 0x1c, 0x70, 0x9f, 0xdb, 0xdd, 0x9f, 0xd8, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0c, 0xfd, 0x18, 0x2a, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x64, 0x6f, 0x92, 0x38, 0x46, 0xfd, 0xfd, 0xfd, 0xfd, 0x8b, 0xfc, 0xac, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x8f, 0x55, 0xfd, 0x22, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x14, 0x10, 0xfd, 0x96, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, + 0x21, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x34, 0xfd, 0xfd, + 0xab, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x60, 0x61, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, + 0xfc, 0xfc, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0a, 0xeb, 0xfc, 0xc5, 0xea, 0x57, 0x0a, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x32, + 0x15, 0x41, 0xfd, 0x1f, 0xfd, 0xfd, 0xfd, 0xfd, 0x6e, 0x53, 0x4a, 0xa9, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x6e, 0x8a, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x57, 0xfc, 0xfc, 0xd0, 0xfd, 0xfd, + 0xfd, 0x78, 0x57, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x3c, 0x49, 0x2f, 0x16, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0x2b, 0x16, 0x05, 0xfd, 0xfd, + 0xfd, 0x0d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe3, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xaa, + 0xfd, 0xfd, 0xfd, 0xfd, 0x13, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x3e, 0x69, 0xfd, 0x68, 0xfd, 0xfd, 0xfd, 0x43, 0x35, 0x8e, 0x39, 0x05, + 0xfd, 0xfd, 0xfd, 0x1c, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xac, 0xfd, 0xfd, 0xba, 0xfc, 0xfc, 0xfc, + 0xfc, 0x82, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x69, 0x12, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x92, 0x17, 0x58, 0x2c, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x99, 0xfd, 0xfd, 0xfd, 0xfd, 0x06, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xaa, 0xfd, 0xfd, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xcd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x39, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x01, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x57, 0xfd, 0x97, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xaf, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x70, + 0xfd, 0xda, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x1d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x06, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xe2, 0xfd, 0xc0, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xae, 0xfd, 0xa7, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0xa1, 0x70, 0xe8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xea, 0xaa, 0xe3, 0xfc, 0x96, 0xb6, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x62, 0xfd, 0xfd, 0x84, 0xfd, 0xfd, 0xfd, 0xfd, 0x1e, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xd0, 0xfd, 0x51, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xed, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x64, 0x97, 0xfd, 0x2d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x6b, 0xfd, 0xfd, 0xfd, 0xfd, + 0x2e, 0x42, 0x1f, 0x25, 0xfd, 0xfd, 0xfd, 0x49, 0x20, 0x42, 0x31, 0xfd, 0xfd, 0xfd, 0xfd, 0x1f, + 0xa1, 0x47, 0x47, 0x47, 0x47, 0xd2, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xc9, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xa8, 0xfd, 0xfd, 0x6d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x1b, 0xfd, 0xfd, + 0xfd, 0xfd, 0x29, 0x2f, 0x1e, 0x8e, 0xfd, 0xfd, 0xfd, 0x59, 0xfd, 0xfd, 0xfd, 0x01, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf7, 0xfc, 0xfc, 0xfc, 0xfc, 0x70, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0xd1, 0xfd, 0xfd, 0x4d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x14, + 0xfd, 0xfd, 0xfd, 0xfd, 0x13, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0x04, 0x8a, 0x35, 0x58, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, + 0xfc, 0x57, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd, 0x85, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0x7a, 0xfd, 0xfd, 0xfd, 0xfd, 0x42, 0x52, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5c, 0x0a, + 0x58, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, + 0xfc, 0xfc, 0xfc, 0x82, 0xfd, 0xfd, 0xfd, 0x4f, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xa5, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x53, 0xfd, 0xfd, 0xfd, 0x0c, 0x46, 0x93, 0xfd, 0x84, 0xfd, 0xfd, 0xfd, 0xfd, + 0x0a, 0x07, 0x81, 0xb3, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x49, 0xd6, 0xd6, 0x21, 0xc8, 0xfc, 0x81, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2b, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x23, 0xfd, 0xfd, 0xfd, 0x05, 0xfd, 0x0f, 0x65, 0x0f, 0xfd, 0xfd, + 0xfd, 0xfd, 0x5d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0x51, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x23, 0xfd, 0xfd, 0x07, 0x0b, 0xfd, 0xfd, 0x05, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xb3, 0xc4, 0x8b, 0xc4, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x63, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x36, 0xfd, 0xfd, 0xfd, 0x35, 0xfd, 0x2a, + 0x7a, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0x2e, 0x6b, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x33, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x29, 0xfd, 0xfd, 0xfd, 0xfd, + 0xb5, 0x00, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xba, 0xfd, 0x4b, 0x6b, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x24, + 0x1a, 0xfd, 0xfd, 0x37, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xab, 0xfd, 0xfd, + 0x37, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x0c, 0x41, 0x95, 0x33, 0x14, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x3f, + 0x38, 0xfd, 0x26, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x1b, 0xfd, 0x6e, 0x04, 0x01, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0x1f, 0xbf, 0x3c, 0x0f, 0x87, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x19, 0x62, 0xfd, 0xfd, 0x52, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x0f, 0x12, 0x76, 0xc2, 0x23, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x4d, 0x33, 0x72, 0x58, 0xdf, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x03, 0xfd, 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x09, 0x5e, 0x45, 0xfd, 0x3d, 0x4e, 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xc1, 0x04, 0x05, 0x0a, 0xfd, 0x8b, + 0x80, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x65, 0x62, 0xfd, 0x56, 0x31, 0x00, 0x13, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x6b, 0xfd, 0x05, 0x31, 0x06, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xa3, 0xd4, 0xfd, 0x1e, 0x45, 0xfd, 0x16, 0x07, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xc7, 0x80, 0x00, 0xfd, 0x3d, 0x6f, 0x38, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5c, 0xfd, 0x4d, 0xfd, 0xfd, 0xf9, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x35, 0x55, 0x23, 0x9b, 0xfd, 0x46, 0xfd, 0x11, 0xa7, 0x09, 0x85, 0x5c, + 0xfd, 0x5d, 0x9d, 0x21, 0xa5, 0xa5, 0x4b, 0xfd, 0xfd, 0xfd, 0xfd, 0x9b, 0x2a, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x52, 0xfd, 0x67, 0xfd, 0x08, 0x1e, 0xfd, + 0x20, 0xfd, 0x7f, 0x0e, 0xfd, 0x5b, 0xfd, 0x8a, 0xfd, 0x02, 0xfd, 0xfd, 0xfd, 0x6d, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x30, 0x94, 0xfd, 0xfd, 0x9b, + 0xfd, 0xfd, 0x7a, 0xfd, 0x9a, 0xfd, 0x69, 0x5c, 0xfd, 0x21, 0xfd, 0x67, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x64, 0x1b, 0x46, 0xfd, 0xab, 0x25, 0x5c, 0xfd, 0x62, 0x4c, 0x4f, 0x14, 0x4b, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x18, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, + + /* SENSOR */ + 0x06, /* larray */ + 0x00, /* status */ + 0x00, 0x44, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, /* unit */ + + 0x40, 0xfe, 0x24, 0x0c, 0x7a, 0xe1, 0x47, 0xae, /* value: sensor #0 */ + 0x40, 0xc8, 0x1c, 0xd6, 0xc8, 0xb4, 0x39, 0x58, /* value: sensor #1 */ + 0x40, 0x93, 0x4a, 0x45, 0x6d, 0x5c, 0xfa, 0xad, /* value: sensor #2 */ + 0x40, 0x5e, 0xdd, 0x3b, 0xe2, 0x2e, 0x5d, 0xe1, /* value: sensor #3 */ + 0x40, 0x28, 0xb0, 0xfc, 0xb4, 0xf1, 0xe4, 0xb4, /* value: sensor #4 */ + 0x3f, 0xf3, 0xc0, 0xca, 0x2a, 0x5b, 0x1d, 0x5d, /* value: sensor #4 */ + +}; + + +#endif /* IGTL_TEST_DATA_BIND_H */ + + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_capability.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_capability.h new file mode 100644 index 0000000..9069542 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_capability.h @@ -0,0 +1,45 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy status data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_CAPABILITY_H +#define __IGTL_TEST_DATA_CAPABILITY_H + +unsigned char test_capability_message[] = { + + 0x00, 0x01, /* Version number */ + 0x43, 0x41, 0x50, 0x41, 0x42, 0x49, 0x4c, 0x49, + 0x54, 0x59, 0x00, 0x00, /* CAPABILITY */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, /* Body size */ + + 0x69, 0x57, 0xe2, 0x9e, 0x2b, 0x35, 0xea, 0x1e, /* CRC */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* IMAGE */ + 0x47, 0x45, 0x54, 0x5f, 0x49, 0x4d, 0x41, 0x47, + 0x45, 0x00, 0x00, 0x00, /* GET_IMAGE */ + 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x4f, 0x52, + 0x4d, 0x00, 0x00, 0x00, /* TRANSFORM */ + 0x47, 0x45, 0x54, 0x5f, 0x54, 0x52, 0x41, 0x4e, + 0x53, 0x00, 0x00, 0x00, /* GET_TRANS */ + +}; + +#endif /* IGTL_TEST_DATA_SENSOR_H */ + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_colortable.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_colortable.h new file mode 100644 index 0000000..93eccf2 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_colortable.h @@ -0,0 +1,73 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy colortable data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_COLORTABLE_H +#define __IGTL_TEST_DATA_COLORTABLE_H + +unsigned char test_colortable_message[] = { + /*------- OpenIGTLink message header -------*/ + 0x00, 0x01, /* Version number */ + 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x54, 0x41, 0x42, + 0x4c, 0x45, 0x00, 0x00, /* COLORTABLE */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, /* Body size */ + 0x39, 0xfc, 0xde, 0xcb, 0xe9, 0x6b, 0x68, 0x35, /* CRC */ + + /*--------- COLORTABLE message body ---------*/ + 0x03, /* Index type */ + 0x03, /* Map type */ + /* color table */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}; + +#endif /* IGTL_TEST_DATA_COLORTABLE_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_colortable2.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_colortable2.h new file mode 100644 index 0000000..9fd379c --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_colortable2.h @@ -0,0 +1,73 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy colortable data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_COLORTABLE_H +#define __IGTL_TEST_DATA_COLORTABLE_H + +unsigned char test_colortable_message[] = { + /*------- OpenIGTLink message header -------*/ + 0x00, 0x01, /* Version number */ + 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* COLORT */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, /* Body size */ + 0x39, 0xfc, 0xde, 0xcb, 0xe9, 0x6b, 0x68, 0x35, /* CRC */ + + /*--------- COLORTABLE message body ---------*/ + 0x03, /* Index type */ + 0x03, /* Map type */ + /* color table */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}; + +#endif /* IGTL_TEST_DATA_COLORTABLE_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_command.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_command.h new file mode 100644 index 0000000..0be49d0 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_command.h @@ -0,0 +1,63 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy status data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_COMMAND_H +#define __IGTL_TEST_DATA_COMMAND_H + +unsigned char test_command_message[] = { + /*-------- OpenIGTLink message header -------*/ + 0x00, 0x01, /* Version number */ + 0x43, 0x4F, 0x4D, 0x4D, 0x41, 0x4E, 0x44, 0x00, + 0x00, 0x00, 0x00, 0x00, /* COMMAND */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, /* Body size */ + 0x2B, 0xC7, 0xCD, 0x95, 0xB7, 0xC5, 0x95, 0x45, /* CRC */ + /////// End of header + + ////// Start of command message header + 0x00, 0x00, 0x00, 0x05, /*Command ID*/ + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, + 0x6F, 0x6D, 0x6D, 0x61, 0x6E, 0x64, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Command name*/ + 0x00, 0x03, /* Encoding */ + 0x00, 0x00, 0x00, 0x1A, /* Command length*/ + ////// End of command message header + + 0x53, 0x74, 0x61, 0x72, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x72, 0x61, 0x63, 0x6B, 0x69, + 0x6E, 0x67, 0x20, 0x6D, 0x61, 0x63, 0x68, 0x69, + 0x6E, 0x65 /* Command */ + +}; + +#endif /* __IGTL_TEST_DATA_COMMAND_H */ + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_commandFormat2.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_commandFormat2.h new file mode 100644 index 0000000..c138577 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_commandFormat2.h @@ -0,0 +1,87 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy position data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#ifndef __IGTL_TEST_DATA_COMMAND_FORMAT2_H +#define __IGTL_TEST_DATA_COMMAND_FORMAT2_H + +unsigned char test_command_messageFormat2[] = { + + /*-------- OpenIGTLink message header -------*/ + 0x00, 0x02, /* Version number */ + 0x43, 0x4F, 0x4D, 0x4D, 0x41, 0x4E, 0x44, 0x00, + 0x00, 0x00, 0x00, 0x00, /* COMMAND */ + 0x4F, 0x70, 0x74, 0x69, 0x63, 0x61, 0x6C, 0x54, + 0x72, 0x61, 0x63, 0x6B, 0x65, 0x72, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, /* Body size */ + 0x85, 0xD2, 0x5E, 0xE9, 0x41, 0x90, 0x17, 0x70, /* CRC */ + + /* Extended header + 0 2 4 8 12 + +-----------------+----------------------+---------------+-------------+ + | EXT_HEADER_SIZE | METADATA_HEADER_SIZE | METADATA_SIZE | MESSAGE_ID | + +-----------------+----------------------+---------------+-------------+*/ + 0x00, 0x0c, 0x00, 0x12, 0x00, 0x00, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x01, + + ////// Start of command message header + 0x00, 0x00, 0x00, 0x05, /*Command ID*/ + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, + 0x6F, 0x6D, 0x6D, 0x61, 0x6E, 0x64, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Command name*/ + 0x00, 0x03, /* Encoding */ + 0x00, 0x00, 0x00, 0x1A, /* Command length*/ + ////// End of command message header + + + 0x53, 0x74, 0x61, 0x72, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x72, 0x61, 0x63, 0x6B, 0x69, + 0x6E, 0x67, 0x20, 0x6D, 0x61, 0x63, 0x68, 0x69, + 0x6E, 0x65, /* Command */ + + /*---------- Command Message Meta data body ------------*/ + 0x00, 0x02, /* Index Count */ + 0x00, 0x11, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, /* first element Key size(2 Bytes), value coding(2 Bytes), value size(4 Bytes)*/ + 0x00, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, /* second element Key size, value coding, value size*/ + + 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, 0x70, 0x61, /* First Patient Age 22*/ + 0x74, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x67, + 0x65, 0x32, + 0x32, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, /* Second Patient Age 25*/ + 0x70, 0x61, 0x74, 0x69, 0x65, 0x6e, 0x74, 0x20, + 0x61, 0x67, 0x65, 0x32, 0x35 + + +}; + +#endif /* __IGTL_TEST_DATA_COMMAND_FORMAT2_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_image.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_image.h new file mode 100644 index 0000000..919175f --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_image.h @@ -0,0 +1,373 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- NCIGT Logo Data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __TSET_DATA_IMAGE_H +#define __TSET_DATA_IMAGE_H + +#define TEST_IMAGE_MESSAGE_SIZE 2500 + +unsigned const char test_image[] = { + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x44, 0x14, 0xfd, 0x27, 0x13, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x77, 0x9a, 0xfd, 0xfd, 0xfd, 0xfd, 0x52, 0xfd, 0x98, 0xfd, 0x2f, + 0xfd, 0x2d, 0x46, 0x1f, 0x0d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2b, 0xfd, 0xfd, 0x86, 0xfd, 0xfd, 0xfd, 0xfd, 0x66, 0xfd, 0x00, + 0xfd, 0x22, 0x83, 0xfd, 0x34, 0x79, 0x62, 0x00, 0x23, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x08, 0x39, 0xfd, 0x5c, 0x76, 0xfd, 0x20, 0xfd, 0x45, 0xfd, 0xfd, 0x58, + 0x4f, 0xb0, 0xfd, 0x73, 0xfd, 0x13, 0xa0, 0x23, 0x44, 0x26, 0xfd, 0x03, 0x9e, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2c, 0x0d, 0x16, 0xfd, 0x1b, 0x67, 0x59, 0x51, 0x72, 0x41, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x1c, 0x27, 0x9c, 0x3d, 0x4e, 0x95, 0xfd, 0x53, 0xfd, 0x26, 0x20, + 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0c, 0xd5, 0x22, 0x09, 0x01, 0x67, 0xfd, 0x98, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0xfd, 0x6f, 0x74, 0xfd, + 0xfd, 0x34, 0x80, 0x61, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x00, 0x2f, 0x44, 0xfd, 0x7b, 0x5e, 0xb9, 0x5e, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x28, 0x06, 0x7e, 0x43, 0x09, 0x00, 0x85, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x78, 0xfd, 0xfd, 0x9a, 0x9c, 0xb6, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x0f, 0x36, 0xfd, 0x05, 0x01, 0x31, 0xa0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x25, 0x01, 0x2a, 0xfd, 0x24, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x15, 0x18, 0x6d, 0x2a, 0xa2, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xa8, 0xfd, 0xfd, 0x17, 0x14, 0x40, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x36, 0xfd, 0x18, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x01, 0xfd, 0x7c, 0x64, 0x74, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5d, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x08, 0x66, 0xfd, 0xfd, + 0x5f, 0x3b, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xc0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xb9, 0xfd, + 0xfd, 0xfd, 0x71, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x95, 0x6c, 0xca, 0x08, 0x39, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x09, + 0x39, 0x09, 0x8d, 0x20, 0xfd, 0x06, 0x34, 0x19, 0x19, 0x19, 0x19, 0x33, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0a, 0xfd, 0xb0, 0x30, 0x9e, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x06, 0xfd, 0xfd, 0x64, 0xfd, 0x1c, 0x70, 0x9f, 0xdb, 0xdd, 0x9f, 0xd8, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0c, 0xfd, 0x18, 0x2a, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x64, 0x6f, 0x92, 0x38, 0x46, 0xfd, 0xfd, 0xfd, 0xfd, 0x8b, 0xfc, 0xac, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x8f, 0x55, 0xfd, 0x22, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x14, 0x10, 0xfd, 0x96, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, + 0x21, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x34, 0xfd, 0xfd, + 0xab, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x60, 0x61, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, + 0xfc, 0xfc, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0a, 0xeb, 0xfc, 0xc5, 0xea, 0x57, 0x0a, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x32, + 0x15, 0x41, 0xfd, 0x1f, 0xfd, 0xfd, 0xfd, 0xfd, 0x6e, 0x53, 0x4a, 0xa9, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x6e, 0x8a, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x57, 0xfc, 0xfc, 0xd0, 0xfd, 0xfd, + 0xfd, 0x78, 0x57, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x3c, 0x49, 0x2f, 0x16, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0x2b, 0x16, 0x05, 0xfd, 0xfd, + 0xfd, 0x0d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe3, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xaa, + 0xfd, 0xfd, 0xfd, 0xfd, 0x13, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x3e, 0x69, 0xfd, 0x68, 0xfd, 0xfd, 0xfd, 0x43, 0x35, 0x8e, 0x39, 0x05, + 0xfd, 0xfd, 0xfd, 0x1c, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xac, 0xfd, 0xfd, 0xba, 0xfc, 0xfc, 0xfc, + 0xfc, 0x82, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x69, 0x12, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x92, 0x17, 0x58, 0x2c, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x99, 0xfd, 0xfd, 0xfd, 0xfd, 0x06, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xaa, 0xfd, 0xfd, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xcd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x39, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x01, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x57, 0xfd, 0x97, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xaf, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x70, + 0xfd, 0xda, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x1d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x06, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xe2, 0xfd, 0xc0, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xae, 0xfd, 0xa7, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0xa1, 0x70, 0xe8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xea, 0xaa, 0xe3, 0xfc, 0x96, 0xb6, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x62, 0xfd, 0xfd, 0x84, 0xfd, 0xfd, 0xfd, 0xfd, 0x1e, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xd0, 0xfd, 0x51, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xed, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x64, 0x97, 0xfd, 0x2d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x6b, 0xfd, 0xfd, 0xfd, 0xfd, + 0x2e, 0x42, 0x1f, 0x25, 0xfd, 0xfd, 0xfd, 0x49, 0x20, 0x42, 0x31, 0xfd, 0xfd, 0xfd, 0xfd, 0x1f, + 0xa1, 0x47, 0x47, 0x47, 0x47, 0xd2, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xc9, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xa8, 0xfd, 0xfd, 0x6d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x1b, 0xfd, 0xfd, + 0xfd, 0xfd, 0x29, 0x2f, 0x1e, 0x8e, 0xfd, 0xfd, 0xfd, 0x59, 0xfd, 0xfd, 0xfd, 0x01, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf7, 0xfc, 0xfc, 0xfc, 0xfc, 0x70, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0xd1, 0xfd, 0xfd, 0x4d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x14, + 0xfd, 0xfd, 0xfd, 0xfd, 0x13, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0x04, 0x8a, 0x35, 0x58, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, + 0xfc, 0x57, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd, 0x85, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0x7a, 0xfd, 0xfd, 0xfd, 0xfd, 0x42, 0x52, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5c, 0x0a, + 0x58, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, + 0xfc, 0xfc, 0xfc, 0x82, 0xfd, 0xfd, 0xfd, 0x4f, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xa5, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x53, 0xfd, 0xfd, 0xfd, 0x0c, 0x46, 0x93, 0xfd, 0x84, 0xfd, 0xfd, 0xfd, 0xfd, + 0x0a, 0x07, 0x81, 0xb3, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x49, 0xd6, 0xd6, 0x21, 0xc8, 0xfc, 0x81, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2b, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x23, 0xfd, 0xfd, 0xfd, 0x05, 0xfd, 0x0f, 0x65, 0x0f, 0xfd, 0xfd, + 0xfd, 0xfd, 0x5d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0x51, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x23, 0xfd, 0xfd, 0x07, 0x0b, 0xfd, 0xfd, 0x05, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xb3, 0xc4, 0x8b, 0xc4, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x63, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x36, 0xfd, 0xfd, 0xfd, 0x35, 0xfd, 0x2a, + 0x7a, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0x2e, 0x6b, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x33, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x29, 0xfd, 0xfd, 0xfd, 0xfd, + 0xb5, 0x00, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xba, 0xfd, 0x4b, 0x6b, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x24, + 0x1a, 0xfd, 0xfd, 0x37, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xab, 0xfd, 0xfd, + 0x37, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x0c, 0x41, 0x95, 0x33, 0x14, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x3f, + 0x38, 0xfd, 0x26, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x1b, 0xfd, 0x6e, 0x04, 0x01, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0x1f, 0xbf, 0x3c, 0x0f, 0x87, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x19, 0x62, 0xfd, 0xfd, 0x52, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x0f, 0x12, 0x76, 0xc2, 0x23, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x4d, 0x33, 0x72, 0x58, 0xdf, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x03, 0xfd, 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x09, 0x5e, 0x45, 0xfd, 0x3d, 0x4e, 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xc1, 0x04, 0x05, 0x0a, 0xfd, 0x8b, + 0x80, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x65, 0x62, 0xfd, 0x56, 0x31, 0x00, 0x13, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x6b, 0xfd, 0x05, 0x31, 0x06, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xa3, 0xd4, 0xfd, 0x1e, 0x45, 0xfd, 0x16, 0x07, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xc7, 0x80, 0x00, 0xfd, 0x3d, 0x6f, 0x38, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5c, 0xfd, 0x4d, 0xfd, 0xfd, 0xf9, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x35, 0x55, 0x23, 0x9b, 0xfd, 0x46, 0xfd, 0x11, 0xa7, 0x09, 0x85, 0x5c, + 0xfd, 0x5d, 0x9d, 0x21, 0xa5, 0xa5, 0x4b, 0xfd, 0xfd, 0xfd, 0xfd, 0x9b, 0x2a, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x52, 0xfd, 0x67, 0xfd, 0x08, 0x1e, 0xfd, + 0x20, 0xfd, 0x7f, 0x0e, 0xfd, 0x5b, 0xfd, 0x8a, 0xfd, 0x02, 0xfd, 0xfd, 0xfd, 0x6d, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x30, 0x94, 0xfd, 0xfd, 0x9b, + 0xfd, 0xfd, 0x7a, 0xfd, 0x9a, 0xfd, 0x69, 0x5c, 0xfd, 0x21, 0xfd, 0x67, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x64, 0x1b, 0x46, 0xfd, 0xab, 0x25, 0x5c, 0xfd, 0x62, 0x4c, 0x4f, 0x14, 0x4b, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x18, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, +}; + +unsigned const char test_image_message[] = { + /* OpenIGTLink header */ + 0x00, 0x01, /* Version number */ + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* IMAGE */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0c, /* Body size */ + 0x55, 0x4f, 0xc4, 0x87, 0x69, 0xfd, 0x7c, 0xff, /* CRC */ + + /* Image header */ + 0x00, 0x01, /* Version number */ + 0x01, /* Image type (scalar) */ + 0x03, /* Scalar type (8-bit unsigned int) */ + 0x02, /* Little endian */ + 0x01, /* Image coordinate */ + 0x00, 0x32, 0x00, 0x32, 0x00, 0x01, /* Number of pixels */ + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, + 0xBE, 0x63, 0xDD, 0x98, /* tx, ty, tz */ + 0xBE, 0x49, 0x59, 0xE6, 0x3E, 0x12, 0x49, 0x1B, + 0x3F, 0x78, 0x52, 0xD6, /* sx, sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, + 0xBD, 0xC8, 0x30, 0xAE, /* nx, ny, nz */ + 0x42, 0x38, 0x36, 0x60, 0x41, 0x9B, 0xC4, 0x67, + 0x42, 0x38, 0x36, 0x60, /* px, py, pz */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Starting index of subvolume */ + 0x00, 0x32, 0x00, 0x32, 0x00, 0x01, /* Number of pixels in subvolume */ + + /* Image data */ + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x44, 0x14, 0xfd, 0x27, 0x13, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x77, 0x9a, 0xfd, 0xfd, 0xfd, 0xfd, 0x52, 0xfd, 0x98, 0xfd, 0x2f, + 0xfd, 0x2d, 0x46, 0x1f, 0x0d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2b, 0xfd, 0xfd, 0x86, 0xfd, 0xfd, 0xfd, 0xfd, 0x66, 0xfd, 0x00, + 0xfd, 0x22, 0x83, 0xfd, 0x34, 0x79, 0x62, 0x00, 0x23, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x08, 0x39, 0xfd, 0x5c, 0x76, 0xfd, 0x20, 0xfd, 0x45, 0xfd, 0xfd, 0x58, + 0x4f, 0xb0, 0xfd, 0x73, 0xfd, 0x13, 0xa0, 0x23, 0x44, 0x26, 0xfd, 0x03, 0x9e, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2c, 0x0d, 0x16, 0xfd, 0x1b, 0x67, 0x59, 0x51, 0x72, 0x41, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x1c, 0x27, 0x9c, 0x3d, 0x4e, 0x95, 0xfd, 0x53, 0xfd, 0x26, 0x20, + 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0c, 0xd5, 0x22, 0x09, 0x01, 0x67, 0xfd, 0x98, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0xfd, 0x6f, 0x74, 0xfd, + 0xfd, 0x34, 0x80, 0x61, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x00, 0x2f, 0x44, 0xfd, 0x7b, 0x5e, 0xb9, 0x5e, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x28, 0x06, 0x7e, 0x43, 0x09, 0x00, 0x85, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x78, 0xfd, 0xfd, 0x9a, 0x9c, 0xb6, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x0f, 0x36, 0xfd, 0x05, 0x01, 0x31, 0xa0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x25, 0x01, 0x2a, 0xfd, 0x24, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x15, 0x18, 0x6d, 0x2a, 0xa2, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xa8, 0xfd, 0xfd, 0x17, 0x14, 0x40, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x36, 0xfd, 0x18, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x01, 0xfd, 0x7c, 0x64, 0x74, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5d, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x08, 0x66, 0xfd, 0xfd, + 0x5f, 0x3b, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xc0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xb9, 0xfd, + 0xfd, 0xfd, 0x71, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x95, 0x6c, 0xca, 0x08, 0x39, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x09, + 0x39, 0x09, 0x8d, 0x20, 0xfd, 0x06, 0x34, 0x19, 0x19, 0x19, 0x19, 0x33, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0a, 0xfd, 0xb0, 0x30, 0x9e, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x06, 0xfd, 0xfd, 0x64, 0xfd, 0x1c, 0x70, 0x9f, 0xdb, 0xdd, 0x9f, 0xd8, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0c, 0xfd, 0x18, 0x2a, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x64, 0x6f, 0x92, 0x38, 0x46, 0xfd, 0xfd, 0xfd, 0xfd, 0x8b, 0xfc, 0xac, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x8f, 0x55, 0xfd, 0x22, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x14, 0x10, 0xfd, 0x96, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, + 0x21, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x34, 0xfd, 0xfd, + 0xab, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x60, 0x61, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, + 0xfc, 0xfc, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0a, 0xeb, 0xfc, 0xc5, 0xea, 0x57, 0x0a, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x32, + 0x15, 0x41, 0xfd, 0x1f, 0xfd, 0xfd, 0xfd, 0xfd, 0x6e, 0x53, 0x4a, 0xa9, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x6e, 0x8a, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x57, 0xfc, 0xfc, 0xd0, 0xfd, 0xfd, + 0xfd, 0x78, 0x57, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x3c, 0x49, 0x2f, 0x16, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0x2b, 0x16, 0x05, 0xfd, 0xfd, + 0xfd, 0x0d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe3, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xaa, + 0xfd, 0xfd, 0xfd, 0xfd, 0x13, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x3e, 0x69, 0xfd, 0x68, 0xfd, 0xfd, 0xfd, 0x43, 0x35, 0x8e, 0x39, 0x05, + 0xfd, 0xfd, 0xfd, 0x1c, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xac, 0xfd, 0xfd, 0xba, 0xfc, 0xfc, 0xfc, + 0xfc, 0x82, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x69, 0x12, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x92, 0x17, 0x58, 0x2c, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x99, 0xfd, 0xfd, 0xfd, 0xfd, 0x06, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xaa, 0xfd, 0xfd, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xcd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x39, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x01, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x57, 0xfd, 0x97, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xaf, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x70, + 0xfd, 0xda, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x1d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x06, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xe2, 0xfd, 0xc0, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xae, 0xfd, 0xa7, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0xa1, 0x70, 0xe8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xea, 0xaa, 0xe3, 0xfc, 0x96, 0xb6, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x62, 0xfd, 0xfd, 0x84, 0xfd, 0xfd, 0xfd, 0xfd, 0x1e, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xd0, 0xfd, 0x51, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xed, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x64, 0x97, 0xfd, 0x2d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x6b, 0xfd, 0xfd, 0xfd, 0xfd, + 0x2e, 0x42, 0x1f, 0x25, 0xfd, 0xfd, 0xfd, 0x49, 0x20, 0x42, 0x31, 0xfd, 0xfd, 0xfd, 0xfd, 0x1f, + 0xa1, 0x47, 0x47, 0x47, 0x47, 0xd2, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xc9, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xa8, 0xfd, 0xfd, 0x6d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x1b, 0xfd, 0xfd, + 0xfd, 0xfd, 0x29, 0x2f, 0x1e, 0x8e, 0xfd, 0xfd, 0xfd, 0x59, 0xfd, 0xfd, 0xfd, 0x01, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf7, 0xfc, 0xfc, 0xfc, 0xfc, 0x70, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0xd1, 0xfd, 0xfd, 0x4d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x14, + 0xfd, 0xfd, 0xfd, 0xfd, 0x13, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0x04, 0x8a, 0x35, 0x58, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, + 0xfc, 0x57, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd, 0x85, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0x7a, 0xfd, 0xfd, 0xfd, 0xfd, 0x42, 0x52, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5c, 0x0a, + 0x58, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, + 0xfc, 0xfc, 0xfc, 0x82, 0xfd, 0xfd, 0xfd, 0x4f, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xa5, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x53, 0xfd, 0xfd, 0xfd, 0x0c, 0x46, 0x93, 0xfd, 0x84, 0xfd, 0xfd, 0xfd, 0xfd, + 0x0a, 0x07, 0x81, 0xb3, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x49, 0xd6, 0xd6, 0x21, 0xc8, 0xfc, 0x81, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2b, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x23, 0xfd, 0xfd, 0xfd, 0x05, 0xfd, 0x0f, 0x65, 0x0f, 0xfd, 0xfd, + 0xfd, 0xfd, 0x5d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0x51, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x23, 0xfd, 0xfd, 0x07, 0x0b, 0xfd, 0xfd, 0x05, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xb3, 0xc4, 0x8b, 0xc4, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x63, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x36, 0xfd, 0xfd, 0xfd, 0x35, 0xfd, 0x2a, + 0x7a, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0x2e, 0x6b, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x33, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x29, 0xfd, 0xfd, 0xfd, 0xfd, + 0xb5, 0x00, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xba, 0xfd, 0x4b, 0x6b, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x24, + 0x1a, 0xfd, 0xfd, 0x37, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xab, 0xfd, 0xfd, + 0x37, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x0c, 0x41, 0x95, 0x33, 0x14, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x3f, + 0x38, 0xfd, 0x26, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x1b, 0xfd, 0x6e, 0x04, 0x01, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0x1f, 0xbf, 0x3c, 0x0f, 0x87, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x19, 0x62, 0xfd, 0xfd, 0x52, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x0f, 0x12, 0x76, 0xc2, 0x23, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x4d, 0x33, 0x72, 0x58, 0xdf, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x03, 0xfd, 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x09, 0x5e, 0x45, 0xfd, 0x3d, 0x4e, 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xc1, 0x04, 0x05, 0x0a, 0xfd, 0x8b, + 0x80, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x65, 0x62, 0xfd, 0x56, 0x31, 0x00, 0x13, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x6b, 0xfd, 0x05, 0x31, 0x06, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xa3, 0xd4, 0xfd, 0x1e, 0x45, 0xfd, 0x16, 0x07, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xc7, 0x80, 0x00, 0xfd, 0x3d, 0x6f, 0x38, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5c, 0xfd, 0x4d, 0xfd, 0xfd, 0xf9, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x35, 0x55, 0x23, 0x9b, 0xfd, 0x46, 0xfd, 0x11, 0xa7, 0x09, 0x85, 0x5c, + 0xfd, 0x5d, 0x9d, 0x21, 0xa5, 0xa5, 0x4b, 0xfd, 0xfd, 0xfd, 0xfd, 0x9b, 0x2a, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x52, 0xfd, 0x67, 0xfd, 0x08, 0x1e, 0xfd, + 0x20, 0xfd, 0x7f, 0x0e, 0xfd, 0x5b, 0xfd, 0x8a, 0xfd, 0x02, 0xfd, 0xfd, 0xfd, 0x6d, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x30, 0x94, 0xfd, 0xfd, 0x9b, + 0xfd, 0xfd, 0x7a, 0xfd, 0x9a, 0xfd, 0x69, 0x5c, 0xfd, 0x21, 0xfd, 0x67, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x64, 0x1b, 0x46, 0xfd, 0xab, 0x25, 0x5c, 0xfd, 0x62, 0x4c, 0x4f, 0x14, 0x4b, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x18, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, +}; + + +#endif /* __TSET_DATA_IMAGE_H */ diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_imgmeta.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_imgmeta.h new file mode 100644 index 0000000..6d903e6 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_imgmeta.h @@ -0,0 +1,164 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy imgmeta data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_IMGMETA_H +#define __IGTL_TEST_DATA_IMGMETA_H + +unsigned char test_imgmeta_message[] = { + /*------- OpenIGTLink message header -------*/ + 0x00, 0x01, /* Version number */ + 0x49, 0x4d, 0x47, 0x4d, 0x45, 0x54, 0x41, 0x00, + 0x00, 0x00, 0x00, 0x00, /* IMGMETA */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0c, /* Body size */ + 0x38, 0x07, 0xd4, 0x2d, 0x9b, 0xde, 0xe0, 0xc9, /* CRC */ + + /*---------- IMGMETA message body -----------*/ + /* Image meta data 0 */ + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Image description */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Image name (device name) */ + + 0x43, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Modality */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Patient name */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x49, 0x44, 0x5f, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Patient ID */ + + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x02, 0x00, 0x02, 0x00, 0x00, 0x40, /* Image size */ + 0x05, /* Scalar type */ + 0x00, /* Reserved byte */ + + /* Image meta data 1 */ + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Image description */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x31, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Image name (device name) */ + + 0x4d, 0x52, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Modality */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Patient name */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x49, 0x44, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Patient ID */ + + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd8, /* Time stamp */ + 0x01, 0x00, 0x00, 0x80, 0x00, 0x20, /* Image size */ + 0x05, /* Scalar type */ + 0x00, /* Reserved byte */ + + /* Image meta data 2 */ + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Image description */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Image name (device name) */ + + 0x50, 0x45, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Modality */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Patient name */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x49, 0x44, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Patient ID */ + + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xdc, /* Time stamp */ + 0x01, 0x00, 0x01, 0x00, 0x00, 0x20, /* Image size */ + 0x05, /* Scalar type */ + 0x00, /* Reserved byte */ + +}; + +#endif /* IGTL_TEST_DATA_IMGMETA_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_lbmeta.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_lbmeta.h new file mode 100644 index 0000000..2a567db --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_lbmeta.h @@ -0,0 +1,109 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy lbmeta data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_LBMETA_H +#define __IGTL_TEST_DATA_LBMETA_H + +unsigned char test_lbmeta_message[] = { + /*------- OpenIGTLink message header --------*/ + 0x00, 0x01, /* Version number */ + 0x4c, 0x42, 0x4d, 0x45, 0x54, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* LBMETA */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x5c, /* Body size */ + 0x1a, 0x5b, 0x87, 0xbb, 0x24, 0x8d, 0x80, 0x07, /* CRC */ + + /*---------- LBMETA message body ------------*/ + /* Image meta data 0 */ + 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x5f, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Image description */ + + 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Image name (device name) */ + + 0x01, /* Label */ + 0x00, /* Reserved */ + 0xff, 0x00, 0x00, 0xff, /* RGBA */ + 0x01, 0x00, 0x00, 0x80, 0x00, 0x20, /* Size */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + + /* Image meta data 1 */ + 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x5f, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Image description */ + + 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x5f, 0x31, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Image name (device name) */ + + 0x02, /* Label */ + 0x00, /* Reserved */ + 0x00, 0xff, 0x00, 0xff, /* RGBA */ + 0x01, 0x00, 0x00, 0x80, 0x00, 0x20, /* Size */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + + /* Image meta data 2 */ + 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x5f, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Image description */ + + 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x5f, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Image name (device name) */ + + 0x03, /* Label */ + 0x00, /* Reserved */ + 0x00, 0x00, 0xff, 0xff, /* RGBA */ + 0x01, 0x00, 0x00, 0x80, 0x00, 0x20, /* Size */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + + + +}; + +#endif /* IGTL_TEST_DATA_LBMETA_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_ndarray.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_ndarray.h new file mode 100644 index 0000000..4339dfd --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_ndarray.h @@ -0,0 +1,105 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy status data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_NDARRAY_H +#define __IGTL_TEST_DATA_NDARRAY_H + +unsigned char test_ndarray_message_header[] = { + 0x00, 0x01, /* Version number */ + 0x4e, 0x44, 0x41, 0x52, 0x52, 0x41, 0x59, 0x00, + 0x00, 0x00, 0x00, 0x00, /* NDARRAY */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe8, /* Body size */ + 0x1b, 0xe0, 0xce, 0x29, 0x55, 0x4f, 0x9a, 0x92, /* CRC */ +}; + +unsigned char test_ndarray_message_body[] = { + 0x0b, /* 11: 64-bit float */ + 0x03, /* 3-dimensional array */ + 0x00, 0x05, 0x00, 0x04, 0x00, 0x03, /* size[] = {5, 4, 3} */ + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0.0 */ + 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1.0 */ + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2.0 */ + 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3.0 */ + 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ... */ + 0x40, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x41, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x42, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x44, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x45, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x47, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x48, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x49, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x4a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x4b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x4c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x4d, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + +}; + + +#endif /* IGTL_TEST_DATA_NDARRAY_H */ + + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_point.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_point.h new file mode 100644 index 0000000..e326e47 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_point.h @@ -0,0 +1,116 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy point data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_POINT_H +#define __IGTL_TEST_DATA_POINT_H + +unsigned char test_point_message[] = { + /*------- OpenIGTLink message header --------*/ + 0x00, 0x01, /* Version number */ + 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* POINT */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x98, /* Body size */ + 0xa5, 0x5c, 0xc6, 0x2d, 0x99, 0xc1, 0x82, 0x10, /* CRC */ + + /*---------- POINT message body ------------*/ + /* Image meta data 0 */ + 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x5f, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Image description */ + + 0x4c, 0x61, 0x6e, 0x64, 0x6d, 0x61, 0x72, 0x6b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Group name (Landmark etc.) */ + + 0xff, 0x00, 0x00, 0xff, /* RGBA */ + + 0x41, 0x20, 0x00, 0x00, 0x41, 0x70, 0x00, 0x00, + 0x41, 0xa0, 0x00, 0x00, /* Position */ + + 0x40, 0xa0, 0x00, 0x00, /* Radius */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + + /* Image meta data 1 */ + 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x5f, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Image description */ + + 0x4c, 0x61, 0x6e, 0x64, 0x6d, 0x61, 0x72, 0x6b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Group name (Landmark etc.) */ + + 0x00, 0xff, 0x00, 0xff, /* RGBA */ + + 0x41, 0xc8, 0x00, 0x00, 0x41, 0xf0, 0x00, 0x00, + 0x42, 0x0c, 0x00, 0x00, /* Position */ + + 0x40, 0x40, 0x00, 0x00, /* Radius */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + + /* Image meta data 2 */ + 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x5f, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Image description */ + + 0x4c, 0x61, 0x6e, 0x64, 0x6d, 0x61, 0x72, 0x6b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Group name (Landmark etc.) */ + + 0x00, 0x00, 0xff, 0xff, /* RGBA */ + + 0x42, 0x20, 0x00, 0x00, 0x42, 0x34, 0x00, 0x00, + 0x42, 0x48, 0x00, 0x00, /* Position */ + + 0x3f, 0x80, 0x00, 0x00, /* Radius */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + +}; + +#endif /* IGTL_TEST_DATA_POINT_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_polydata.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_polydata.h new file mode 100644 index 0000000..5a9cf9e --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_polydata.h @@ -0,0 +1,142 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy point data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_POLYDATA_H +#define __IGTL_TEST_DATA_POLYDATA_H + +unsigned char test_polydata_message_header[] = { + /*------- OpenIGTLink message header --------*/ + 0x00, 0x01, /* Version number */ + 0x50, 0x4f, 0x4c, 0x59, 0x44, 0x41, 0x54, 0x41, + 0x00, 0x00, 0x00, 0x00, /* POLYDATA */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2c, /* Body size */ + 0x73, 0xdd, 0xdf, 0xc8, 0x0c, 0x48, 0xc6, 0x2b, /* CRC */ +}; + +unsigned char test_polydata_message_body[] = { + /*---------- POLYDATA message header ------------*/ + 0x00, 0x00, 0x00, 0x08, /* Number of points */ + 0x00, 0x00, 0x00, 0x00, /* Number of vertices */ + 0x00, 0x00, 0x00, 0x00, /* size of vertice data */ + 0x00, 0x00, 0x00, 0x00, /* Number of lines */ + 0x00, 0x00, 0x00, 0x00, /* size of line data */ + 0x00, 0x00, 0x00, 0x06, /* Number of polygons */ + 0x00, 0x00, 0x00, 0x78, /* size of polygon data */ + 0x00, 0x00, 0x00, 0x00, /* Number of triangle strips */ + 0x00, 0x00, 0x00, 0x00, /* size of triangle strip data */ + 0x00, 0x00, 0x00, 0x01, /* number of attributes */ + + /*---------- POLYDATA message body (geometry section) ------------*/ + 0x00, 0x00, 0x00, 0x00, /* Point #0 - x*/ + 0x00, 0x00, 0x00, 0x00, /* Point #0 - y*/ + 0x00, 0x00, 0x00, 0x00, /* Point #0 - z*/ + + 0x3f, 0x80, 0x00, 0x00, /* Point #1 - x*/ + 0x00, 0x00, 0x00, 0x00, /* Point #1 - y*/ + 0x00, 0x00, 0x00, 0x00, /* Point #1 - z*/ + + 0x3f, 0x80, 0x00, 0x00, /* Point #2 - x*/ + 0x3f, 0x80, 0x00, 0x00, /* Point #2 - y*/ + 0x00, 0x00, 0x00, 0x00, /* Point #2 - z*/ + + 0x00, 0x00, 0x00, 0x00, /* Point #3 - x*/ + 0x3f, 0x80, 0x00, 0x00, /* Point #3 - y*/ + 0x00, 0x00, 0x00, 0x00, /* Point #3 - z*/ + + 0x00, 0x00, 0x00, 0x00, /* Point #4 - x*/ + 0x00, 0x00, 0x00, 0x00, /* Point #4 - y*/ + 0x3f, 0x80, 0x00, 0x00, /* Point #4 - z*/ + + 0x3f, 0x80, 0x00, 0x00, /* Point #5 - x*/ + 0x00, 0x00, 0x00, 0x00, /* Point #5 - y*/ + 0x3f, 0x80, 0x00, 0x00, /* Point #5 - z*/ + + 0x3f, 0x80, 0x00, 0x00, /* Point #6 - x*/ + 0x3f, 0x80, 0x00, 0x00, /* Point #6 - y*/ + 0x3f, 0x80, 0x00, 0x00, /* Point #6 - z*/ + + 0x00, 0x00, 0x00, 0x00, /* Point #7 - x*/ + 0x3f, 0x80, 0x00, 0x00, /* Point #7 - y*/ + 0x3f, 0x80, 0x00, 0x00, /* Point #7 - z*/ + + /* No vertices */ + + /* No lines */ + + 0x00, 0x00, 0x00, 0x04, /* Polygon #0 - number of data */ + 0x00, 0x00, 0x00, 0x00, /* Polygon #0 - point #0 */ + 0x00, 0x00, 0x00, 0x01, /* Polygon #0 - point #1 */ + 0x00, 0x00, 0x00, 0x02, /* Polygon #0 - point #2 */ + 0x00, 0x00, 0x00, 0x03, /* Polygon #0 - point #3 */ + + 0x00, 0x00, 0x00, 0x04, /* Polygon #1 - number of data */ + 0x00, 0x00, 0x00, 0x04, /* Polygon #1 - point #0 */ + 0x00, 0x00, 0x00, 0x05, /* Polygon #1 - point #1 */ + 0x00, 0x00, 0x00, 0x06, /* Polygon #1 - point #2 */ + 0x00, 0x00, 0x00, 0x07, /* Polygon #1 - point #3 */ + + 0x00, 0x00, 0x00, 0x04, /* Polygon #2 - number of data */ + 0x00, 0x00, 0x00, 0x00, /* Polygon #2 - point #0 */ + 0x00, 0x00, 0x00, 0x01, /* Polygon #2 - point #1 */ + 0x00, 0x00, 0x00, 0x05, /* Polygon #2 - point #2 */ + 0x00, 0x00, 0x00, 0x04, /* Polygon #2 - point #3 */ + + 0x00, 0x00, 0x00, 0x04, /* Polygon #3 - number of data */ + 0x00, 0x00, 0x00, 0x01, /* Polygon #3 - point #0 */ + 0x00, 0x00, 0x00, 0x02, /* Polygon #3 - point #1 */ + 0x00, 0x00, 0x00, 0x06, /* Polygon #3 - point #2 */ + 0x00, 0x00, 0x00, 0x05, /* Polygon #3 - point #3 */ + + 0x00, 0x00, 0x00, 0x04, /* Polygon #4 - number of data */ + 0x00, 0x00, 0x00, 0x02, /* Polygon #4 - point #0 */ + 0x00, 0x00, 0x00, 0x03, /* Polygon #4 - point #1 */ + 0x00, 0x00, 0x00, 0x07, /* Polygon #4 - point #2 */ + 0x00, 0x00, 0x00, 0x06, /* Polygon #4 - point #3 */ + + 0x00, 0x00, 0x00, 0x04, /* Polygon #5 - number of data */ + 0x00, 0x00, 0x00, 0x03, /* Polygon #5 - point #0 */ + 0x00, 0x00, 0x00, 0x00, /* Polygon #5 - point #1 */ + 0x00, 0x00, 0x00, 0x04, /* Polygon #5 - point #2 */ + 0x00, 0x00, 0x00, 0x07, /* Polygon #5 - point #3 */ + + /*---------- POLYDATA message body (attribute section) ------------*/ + 0x00, /* Attribute #0 Type (upper 8bit) - type */ + 0x01, /* Attribute #0 Type (lower 8bit) - number of components */ + 0x00, 0x00, 0x00, 0x08, /* Attribute #0 Size */ + + 0x61, 0x74, 0x74, 0x72, /* Attribute #0 - name */ + 0x00, /* Name string terminater */ + 0x00, /* Padding required */ + + 0x00, 0x00, 0x00, 0x00, /* Point #0 */ + 0x3f, 0x80, 0x00, 0x00, /* Point #1 */ + 0x40, 0x00, 0x00, 0x00, /* Point #2 */ + 0x40, 0x40, 0x00, 0x00, /* Point #3 */ + 0x40, 0x80, 0x00, 0x00, /* Point #4 */ + 0x40, 0xa0, 0x00, 0x00, /* Point #5 */ + 0x40, 0xc0, 0x00, 0x00, /* Point #6 */ + 0x40, 0xe0, 0x00, 0x00, /* Point #7 */ + +}; + +#endif /* IGTL_TEST_DATA_POLYDATA_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_position.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_position.h new file mode 100644 index 0000000..95f4470 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_position.h @@ -0,0 +1,45 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy position data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_POSITION_H +#define __IGTL_TEST_DATA_POSITION_H + +unsigned char test_position_message[] = { + + /*-------- OpenIGTLink message header -------*/ + 0x00, 0x01, /* Version number */ + 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, + 0x00, 0x00, 0x00, 0x00, /* POSITION */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, /* Body size */ + 0x6b, 0xc8, 0xd6, 0x28, 0x2b, 0x79, 0xa3, 0xa1, /* CRC */ + + /*-------- POSITION message body -------*/ + + 0x42, 0x38, 0x36, 0x60, 0x41, 0x9b, 0xc4, 0x67, /* px, py */ + 0x42, 0x38, 0x36, 0x60, 0x00, 0x00, 0x00, 0x00, /* pz, ox */ + 0x3f, 0x13, 0xcd, 0x3a, 0x3f, 0x13, 0xcd, 0x3a, /* oy, oz */ + 0x3e, 0xaa, 0xaa, 0xab, /* ow */ + +}; + +#endif /* IGTL_TEST_DATA_POSITION_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_positionFormat2.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_positionFormat2.h new file mode 100644 index 0000000..a959cb7 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_positionFormat2.h @@ -0,0 +1,65 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy position data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_POSITION_FORMAT2_H +#define __IGTL_TEST_DATA_POSITION_FORMAT2_H + +unsigned char test_position_messageFormat2[] = { + + /*-------- OpenIGTLink message header -------*/ + 0x00, 0x02, /* Version number */ + 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, + 0x00, 0x00, 0x00, 0x00, /* POSITION */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, /* Body size */ + 0xc7, 0x11, 0x16, 0x42, 0x76, 0x81, 0xc1, 0xe2, /* CRC */ + + /* Extended header + 0 2 4 8 12 + +-----------------+----------------------+---------------+-------------+ + | EXT_HEADER_SIZE | METADATA_HEADER_SIZE | METADATA_SIZE | MESSAGE_ID | + +-----------------+----------------------+---------------+-------------+*/ + 0x00, 0x0c, 0x00, 0x12, 0x00, 0x00, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x01, + + /*-------- POSITION message body -------*/ + + 0x42, 0x38, 0x36, 0x60, 0x41, 0x9b, 0xc4, 0x67, /* px, py */ + 0x42, 0x38, 0x36, 0x60, 0x00, 0x00, 0x00, 0x00, /* pz, ox */ + 0x3f, 0x13, 0xcd, 0x3a, 0x3f, 0x13, 0xcd, 0x3a, /* oy, oz */ + 0x3e, 0xaa, 0xaa, 0xab, /* ow */ + + /*---------- POSITION Meta data body ------------*/ + 0x00, 0x02, /* Index Count */ + 0x00, 0x11, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, /* first element Key size(2 Bytes), value coding(2 Bytes), value size(4 Bytes)*/ + 0x00, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, /* second element Key size, value coding, value size*/ + + 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, 0x70, 0x61, /* First Patient Age 22*/ + 0x74, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x67, + 0x65, 0x32, + 0x32, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, /* Second Patient Age 25*/ + 0x70, 0x61, 0x74, 0x69, 0x65, 0x6e, 0x74, 0x20, + 0x61, 0x67, 0x65, 0x32, 0x35 + +}; + +#endif /* IGTL_TEST_DATA_POSITION_FORMAT2_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_rtpwrapper.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_rtpwrapper.h new file mode 100644 index 0000000..2274e7d --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_rtpwrapper.h @@ -0,0 +1,443 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- NCIGT Logo Data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + + =========================================================================*/ + +#ifndef __TSET_DATA_RTPWRAPPER_H +#define __TSET_DATA_RTPWRAPPER_H + +#define TEST_IMAGE_MESSAGE_SIZE 2500 + +unsigned const char test_image[] = { + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x44, 0x14, 0xfd, 0x27, 0x13, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x77, 0x9a, 0xfd, 0xfd, 0xfd, 0xfd, 0x52, 0xfd, 0x98, 0xfd, 0x2f, + 0xfd, 0x2d, 0x46, 0x1f, 0x0d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2b, 0xfd, 0xfd, 0x86, 0xfd, 0xfd, 0xfd, 0xfd, 0x66, 0xfd, 0x00, + 0xfd, 0x22, 0x83, 0xfd, 0x34, 0x79, 0x62, 0x00, 0x23, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x08, 0x39, 0xfd, 0x5c, 0x76, 0xfd, 0x20, 0xfd, 0x45, 0xfd, 0xfd, 0x58, + 0x4f, 0xb0, 0xfd, 0x73, 0xfd, 0x13, 0xa0, 0x23, 0x44, 0x26, 0xfd, 0x03, 0x9e, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2c, 0x0d, 0x16, 0xfd, 0x1b, 0x67, 0x59, 0x51, 0x72, 0x41, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x1c, 0x27, 0x9c, 0x3d, 0x4e, 0x95, 0xfd, 0x53, 0xfd, 0x26, 0x20, + 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0c, 0xd5, 0x22, 0x09, 0x01, 0x67, 0xfd, 0x98, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0xfd, 0x6f, 0x74, 0xfd, + 0xfd, 0x34, 0x80, 0x61, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x00, 0x2f, 0x44, 0xfd, 0x7b, 0x5e, 0xb9, 0x5e, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x28, 0x06, 0x7e, 0x43, 0x09, 0x00, 0x85, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x78, 0xfd, 0xfd, 0x9a, 0x9c, 0xb6, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x0f, 0x36, 0xfd, 0x05, 0x01, 0x31, 0xa0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x25, 0x01, 0x2a, 0xfd, 0x24, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x15, 0x18, 0x6d, 0x2a, 0xa2, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xa8, 0xfd, 0xfd, 0x17, 0x14, 0x40, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x36, 0xfd, 0x18, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x01, 0xfd, 0x7c, 0x64, 0x74, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5d, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x08, 0x66, 0xfd, 0xfd, + 0x5f, 0x3b, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xc0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xb9, 0xfd, + 0xfd, 0xfd, 0x71, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x95, 0x6c, 0xca, 0x08, 0x39, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x09, + 0x39, 0x09, 0x8d, 0x20, 0xfd, 0x06, 0x34, 0x19, 0x19, 0x19, 0x19, 0x33, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0a, 0xfd, 0xb0, 0x30, 0x9e, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x06, 0xfd, 0xfd, 0x64, 0xfd, 0x1c, 0x70, 0x9f, 0xdb, 0xdd, 0x9f, 0xd8, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0c, 0xfd, 0x18, 0x2a, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x64, 0x6f, 0x92, 0x38, 0x46, 0xfd, 0xfd, 0xfd, 0xfd, 0x8b, 0xfc, 0xac, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x8f, 0x55, 0xfd, 0x22, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x14, 0x10, 0xfd, 0x96, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, + 0x21, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x34, 0xfd, 0xfd, + 0xab, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x60, 0x61, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, + 0xfc, 0xfc, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0a, 0xeb, 0xfc, 0xc5, 0xea, 0x57, 0x0a, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x32, + 0x15, 0x41, 0xfd, 0x1f, 0xfd, 0xfd, 0xfd, 0xfd, 0x6e, 0x53, 0x4a, 0xa9, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x6e, 0x8a, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x57, 0xfc, 0xfc, 0xd0, 0xfd, 0xfd, + 0xfd, 0x78, 0x57, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x3c, 0x49, 0x2f, 0x16, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0x2b, 0x16, 0x05, 0xfd, 0xfd, + 0xfd, 0x0d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe3, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xaa, + 0xfd, 0xfd, 0xfd, 0xfd, 0x13, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x3e, 0x69, 0xfd, 0x68, 0xfd, 0xfd, 0xfd, 0x43, 0x35, 0x8e, 0x39, 0x05, + 0xfd, 0xfd, 0xfd, 0x1c, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xac, 0xfd, 0xfd, 0xba, 0xfc, 0xfc, 0xfc, + 0xfc, 0x82, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x69, 0x12, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x92, 0x17, 0x58, 0x2c, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x99, 0xfd, 0xfd, 0xfd, 0xfd, 0x06, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xaa, 0xfd, 0xfd, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xcd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x39, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x01, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x57, 0xfd, 0x97, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xaf, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x70, + 0xfd, 0xda, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x1d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x06, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xe2, 0xfd, 0xc0, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xae, 0xfd, 0xa7, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0xa1, 0x70, 0xe8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xea, 0xaa, 0xe3, 0xfc, 0x96, 0xb6, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x62, 0xfd, 0xfd, 0x84, 0xfd, 0xfd, 0xfd, 0xfd, 0x1e, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xd0, 0xfd, 0x51, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xed, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x64, 0x97, 0xfd, 0x2d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x6b, 0xfd, 0xfd, 0xfd, 0xfd, + 0x2e, 0x42, 0x1f, 0x25, 0xfd, 0xfd, 0xfd, 0x49, 0x20, 0x42, 0x31, 0xfd, 0xfd, 0xfd, 0xfd, 0x1f, + 0xa1, 0x47, 0x47, 0x47, 0x47, 0xd2, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xc9, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xa8, 0xfd, 0xfd, 0x6d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x1b, 0xfd, 0xfd, + 0xfd, 0xfd, 0x29, 0x2f, 0x1e, 0x8e, 0xfd, 0xfd, 0xfd, 0x59, 0xfd, 0xfd, 0xfd, 0x01, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf7, 0xfc, 0xfc, 0xfc, 0xfc, 0x70, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0xd1, 0xfd, 0xfd, 0x4d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x14, + 0xfd, 0xfd, 0xfd, 0xfd, 0x13, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0x04, 0x8a, 0x35, 0x58, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, + 0xfc, 0x57, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd, 0x85, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0x7a, 0xfd, 0xfd, 0xfd, 0xfd, 0x42, 0x52, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5c, 0x0a, + 0x58, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, + 0xfc, 0xfc, 0xfc, 0x82, 0xfd, 0xfd, 0xfd, 0x4f, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xa5, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x53, 0xfd, 0xfd, 0xfd, 0x0c, 0x46, 0x93, 0xfd, 0x84, 0xfd, 0xfd, 0xfd, 0xfd, + 0x0a, 0x07, 0x81, 0xb3, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x49, 0xd6, 0xd6, 0x21, 0xc8, 0xfc, 0x81, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2b, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x23, 0xfd, 0xfd, 0xfd, 0x05, 0xfd, 0x0f, 0x65, 0x0f, 0xfd, 0xfd, + 0xfd, 0xfd, 0x5d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0x51, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x23, 0xfd, 0xfd, 0x07, 0x0b, 0xfd, 0xfd, 0x05, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xb3, 0xc4, 0x8b, 0xc4, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x63, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x36, 0xfd, 0xfd, 0xfd, 0x35, 0xfd, 0x2a, + 0x7a, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0x2e, 0x6b, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x33, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x29, 0xfd, 0xfd, 0xfd, 0xfd, + 0xb5, 0x00, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xba, 0xfd, 0x4b, 0x6b, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x24, + 0x1a, 0xfd, 0xfd, 0x37, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xab, 0xfd, 0xfd, + 0x37, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x0c, 0x41, 0x95, 0x33, 0x14, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x3f, + 0x38, 0xfd, 0x26, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x1b, 0xfd, 0x6e, 0x04, 0x01, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0x1f, 0xbf, 0x3c, 0x0f, 0x87, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x19, 0x62, 0xfd, 0xfd, 0x52, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x0f, 0x12, 0x76, 0xc2, 0x23, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x4d, 0x33, 0x72, 0x58, 0xdf, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x03, 0xfd, 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x09, 0x5e, 0x45, 0xfd, 0x3d, 0x4e, 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xc1, 0x04, 0x05, 0x0a, 0xfd, 0x8b, + 0x80, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x65, 0x62, 0xfd, 0x56, 0x31, 0x00, 0x13, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x6b, 0xfd, 0x05, 0x31, 0x06, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xa3, 0xd4, 0xfd, 0x1e, 0x45, 0xfd, 0x16, 0x07, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xc7, 0x80, 0x00, 0xfd, 0x3d, 0x6f, 0x38, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5c, 0xfd, 0x4d, 0xfd, 0xfd, 0xf9, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x35, 0x55, 0x23, 0x9b, 0xfd, 0x46, 0xfd, 0x11, 0xa7, 0x09, 0x85, 0x5c, + 0xfd, 0x5d, 0x9d, 0x21, 0xa5, 0xa5, 0x4b, 0xfd, 0xfd, 0xfd, 0xfd, 0x9b, 0x2a, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x52, 0xfd, 0x67, 0xfd, 0x08, 0x1e, 0xfd, + 0x20, 0xfd, 0x7f, 0x0e, 0xfd, 0x5b, 0xfd, 0x8a, 0xfd, 0x02, 0xfd, 0xfd, 0xfd, 0x6d, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x30, 0x94, 0xfd, 0xfd, 0x9b, + 0xfd, 0xfd, 0x7a, 0xfd, 0x9a, 0xfd, 0x69, 0x5c, 0xfd, 0x21, 0xfd, 0x67, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x64, 0x1b, 0x46, 0xfd, 0xab, 0x25, 0x5c, 0xfd, 0x62, 0x4c, 0x4f, 0x14, 0x4b, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x18, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, +}; + +unsigned const char test_RTPWrapper_PacketBuffer[] = { +//----------------------------------- +//First Packet + /* RTP Header */ + 0x80, 0x00, 0x00, 0x00, 0xBE, 0x14, 0x6D, 0x6C, + 0x00, 0x00, 0x00, 0x00, + + /* OpenIGTLink header */ + 0x00, 0x02, /* Version number */ + 0x49, 0x4D, 0x41, 0x47, 0x45, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* IMAGE */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4E, 0x61, + 0x6D, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xD4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x51, /* Body size */ + 0xC2, 0xE2, 0xD8, 0x52, 0xFC, 0x02, 0x05, 0x4B, /* CRC */ + + /* Extended Header */ + 0x00, 0x0C, 0X00, 0x12, 0x00, 0x00, 0x00, 0x27, + 0x00, 0x01, 0x80, 0x00, + + /* Image header */ + 0x00, 0x01, /* Version number */ + 0x01, /* Image type (scalar) */ + 0x03, /* Scalar type (8-bit unsigned int) */ + 0x02, /* Little endian */ + 0x01, /* Image coordinate */ + 0x00, 0x32, 0x00, 0x32, 0x00, 0x01, /* Number of pixels */ + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, + 0xBE, 0x63, 0xDD, 0x98, /* tx, ty, tz */ + 0xBE, 0x49, 0x59, 0xE6, 0x3E, 0x12, 0x49, 0x1B, + 0x3F, 0x78, 0x52, 0xD6, /* sx, sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, + 0xBD, 0xC8, 0x30, 0xAE, /* nx, ny, nz */ + 0x42, 0x38, 0x36, 0x60, 0x41, 0x9B, 0xC4, 0x67, + 0x42, 0x38, 0x36, 0x60, /* px, py, pz */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Starting index of subvolume */ + 0x00, 0x32, 0x00, 0x32, 0x00, 0x01, /* Number of pixels in subvolume */ + + /* Image data */ + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x44, 0x14, 0xfd, 0x27, 0x13, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x77, 0x9a, 0xfd, 0xfd, 0xfd, 0xfd, 0x52, 0xfd, 0x98, 0xfd, 0x2f, + 0xfd, 0x2d, 0x46, 0x1f, 0x0d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2b, 0xfd, 0xfd, 0x86, 0xfd, 0xfd, 0xfd, 0xfd, 0x66, 0xfd, 0x00, + 0xfd, 0x22, 0x83, 0xfd, 0x34, 0x79, 0x62, 0x00, 0x23, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x08, 0x39, 0xfd, 0x5c, 0x76, 0xfd, 0x20, 0xfd, 0x45, 0xfd, 0xfd, 0x58, + 0x4f, 0xb0, 0xfd, 0x73, 0xfd, 0x13, 0xa0, 0x23, 0x44, 0x26, 0xfd, 0x03, 0x9e, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2c, 0x0d, 0x16, 0xfd, 0x1b, 0x67, 0x59, 0x51, 0x72, 0x41, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x1c, 0x27, 0x9c, 0x3d, 0x4e, 0x95, 0xfd, 0x53, 0xfd, 0x26, 0x20, + 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0c, 0xd5, 0x22, 0x09, 0x01, 0x67, 0xfd, 0x98, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0xfd, 0x6f, 0x74, 0xfd, + 0xfd, 0x34, 0x80, 0x61, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x00, 0x2f, 0x44, 0xfd, 0x7b, 0x5e, 0xb9, 0x5e, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x28, 0x06, 0x7e, 0x43, 0x09, 0x00, 0x85, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x78, 0xfd, 0xfd, 0x9a, 0x9c, 0xb6, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x0f, 0x36, 0xfd, 0x05, 0x01, 0x31, 0xa0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x25, 0x01, 0x2a, 0xfd, 0x24, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x15, 0x18, 0x6d, 0x2a, 0xa2, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xa8, 0xfd, 0xfd, 0x17, 0x14, 0x40, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x36, 0xfd, 0x18, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x01, 0xfd, 0x7c, 0x64, 0x74, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5d, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x08, 0x66, 0xfd, 0xfd, + 0x5f, 0x3b, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xc0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xb9, 0xfd, + 0xfd, 0xfd, 0x71, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x95, 0x6c, 0xca, 0x08, 0x39, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x09, + 0x39, 0x09, 0x8d, 0x20, 0xfd, 0x06, 0x34, 0x19, 0x19, 0x19, 0x19, 0x33, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0a, 0xfd, 0xb0, 0x30, 0x9e, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x06, 0xfd, 0xfd, 0x64, 0xfd, 0x1c, 0x70, 0x9f, 0xdb, 0xdd, 0x9f, 0xd8, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0c, 0xfd, 0x18, 0x2a, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x64, 0x6f, 0x92, 0x38, 0x46, 0xfd, 0xfd, 0xfd, 0xfd, 0x8b, 0xfc, 0xac, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x8f, 0x55, 0xfd, 0x22, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x14, 0x10, 0xfd, 0x96, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, + 0x21, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x34, 0xfd, 0xfd, + 0xab, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x60, 0x61, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, + 0xfc, 0xfc, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x0a, 0xeb, 0xfc, 0xc5, 0xea, 0x57, 0x0a, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x32, + 0x15, 0x41, 0xfd, 0x1f, 0xfd, 0xfd, 0xfd, 0xfd, 0x6e, 0x53, 0x4a, 0xa9, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x6e, 0x8a, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x57, 0xfc, 0xfc, 0xd0, 0xfd, 0xfd, + 0xfd, 0x78, 0x57, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x3c, 0x49, 0x2f, 0x16, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0x2b, 0x16, 0x05, 0xfd, 0xfd, + 0xfd, 0x0d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xe3, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xaa, + 0xfd, 0xfd, 0xfd, 0xfd, 0x13, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x3e, 0x69, 0xfd, 0x68, 0xfd, 0xfd, 0xfd, 0x43, 0x35, 0x8e, 0x39, 0x05, + 0xfd, 0xfd, 0xfd, 0x1c, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xac, 0xfd, 0xfd, 0xba, 0xfc, 0xfc, 0xfc, + 0xfc, 0x82, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x69, 0x12, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x92, 0x17, 0x58, 0x2c, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x99, 0xfd, 0xfd, 0xfd, 0xfd, 0x06, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xaa, 0xfd, 0xfd, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xcd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x39, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + +//First Packet +//----------------------------------- + + + +//----------------------------------- +//Second Packet + + /* RTP Header */ + 0x80, 0x00, 0x00, 0x01, 0xBE, 0x14, 0x6D, 0x6C, + 0x00, 0x00, 0x00, 0x00, + + /* OpenIGTLink header */ + 0x00, 0x02, /* Version number */ + 0x49, 0x4D, 0x41, 0x47, 0x45, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* IMAGE */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4E, 0x61, + 0x6D, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xD4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x51, /* Body size */ + 0xC2, 0xE2, 0xD8, 0x52, 0xFC, 0x02, 0x05, 0x4B, /* CRC */ + + /* Extended Header */ + 0x00, 0x0C, 0X00, 0x12, 0x00, 0x00, 0x00, 0x27, + 0x00, 0x01, 0x80, 0x01, + + 0xfd, 0x01, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x57, 0xfd, 0x97, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xaf, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x70, + 0xfd, 0xda, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x1d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x06, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xe2, 0xfd, 0xc0, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xae, 0xfd, 0xa7, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0xa1, 0x70, 0xe8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xea, 0xaa, 0xe3, 0xfc, 0x96, 0xb6, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x62, 0xfd, 0xfd, 0x84, 0xfd, 0xfd, 0xfd, 0xfd, 0x1e, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xd0, 0xfd, 0x51, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xed, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x64, 0x97, 0xfd, 0x2d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x6b, 0xfd, 0xfd, 0xfd, 0xfd, + 0x2e, 0x42, 0x1f, 0x25, 0xfd, 0xfd, 0xfd, 0x49, 0x20, 0x42, 0x31, 0xfd, 0xfd, 0xfd, 0xfd, 0x1f, + 0xa1, 0x47, 0x47, 0x47, 0x47, 0xd2, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xc9, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xa8, 0xfd, 0xfd, 0x6d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x1b, 0xfd, 0xfd, + 0xfd, 0xfd, 0x29, 0x2f, 0x1e, 0x8e, 0xfd, 0xfd, 0xfd, 0x59, 0xfd, 0xfd, 0xfd, 0x01, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xf7, 0xfc, 0xfc, 0xfc, 0xfc, 0x70, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0xd1, 0xfd, 0xfd, 0x4d, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x14, + 0xfd, 0xfd, 0xfd, 0xfd, 0x13, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, 0x04, 0x8a, 0x35, 0x58, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, + 0xfc, 0x57, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd, 0x85, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0x7a, 0xfd, 0xfd, 0xfd, 0xfd, 0x42, 0x52, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5c, 0x0a, + 0x58, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x04, + 0xfc, 0xfc, 0xfc, 0x82, 0xfd, 0xfd, 0xfd, 0x4f, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xa5, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0x53, 0xfd, 0xfd, 0xfd, 0x0c, 0x46, 0x93, 0xfd, 0x84, 0xfd, 0xfd, 0xfd, 0xfd, + 0x0a, 0x07, 0x81, 0xb3, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x49, 0xd6, 0xd6, 0x21, 0xc8, 0xfc, 0x81, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x2b, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x23, 0xfd, 0xfd, 0xfd, 0x05, 0xfd, 0x0f, 0x65, 0x0f, 0xfd, 0xfd, + 0xfd, 0xfd, 0x5d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0x51, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x23, 0xfd, 0xfd, 0x07, 0x0b, 0xfd, 0xfd, 0x05, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xb3, 0xc4, 0x8b, 0xc4, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x63, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x36, 0xfd, 0xfd, 0xfd, 0x35, 0xfd, 0x2a, + 0x7a, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x05, 0x2e, 0x6b, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x33, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0x29, 0xfd, 0xfd, 0xfd, 0xfd, + 0xb5, 0x00, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xba, 0xfd, 0x4b, 0x6b, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x24, + 0x1a, 0xfd, 0xfd, 0x37, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xab, 0xfd, 0xfd, + 0x37, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x0c, 0x41, 0x95, 0x33, 0x14, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x3f, + 0x38, 0xfd, 0x26, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0x1b, 0xfd, 0x6e, 0x04, 0x01, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0x1f, 0xbf, 0x3c, 0x0f, 0x87, 0x4d, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0x19, 0x62, 0xfd, 0xfd, 0x52, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x0f, 0x12, 0x76, 0xc2, 0x23, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x4d, 0x33, 0x72, 0x58, 0xdf, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x03, 0xfd, 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x09, 0x5e, 0x45, 0xfd, 0x3d, 0x4e, 0x08, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xc1, 0x04, 0x05, 0x0a, 0xfd, 0x8b, + 0x80, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x65, 0x62, 0xfd, 0x56, 0x31, 0x00, 0x13, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x6b, 0xfd, 0x05, 0x31, 0x06, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xa3, 0xd4, 0xfd, 0x1e, 0x45, 0xfd, 0x16, 0x07, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xc7, 0x80, 0x00, 0xfd, 0x3d, 0x6f, 0x38, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x5c, 0xfd, 0x4d, 0xfd, 0xfd, 0xf9, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0x35, 0x55, 0x23, 0x9b, 0xfd, 0x46, 0xfd, 0x11, 0xa7, 0x09, 0x85, 0x5c, + 0xfd, 0x5d, 0x9d, 0x21, 0xa5, 0xa5, 0x4b, 0xfd, 0xfd, 0xfd, 0xfd, 0x9b, 0x2a, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x52, 0xfd, 0x67, 0xfd, 0x08, 0x1e, 0xfd, + 0x20, 0xfd, 0x7f, 0x0e, 0xfd, 0x5b, 0xfd, 0x8a, 0xfd, 0x02, 0xfd, 0xfd, 0xfd, 0x6d, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x30, 0x94, 0xfd, 0xfd, 0x9b, + 0xfd, 0xfd, 0x7a, 0xfd, 0x9a, 0xfd, 0x69, 0x5c, 0xfd, 0x21, 0xfd, 0x67, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x64, 0x1b, 0x46, 0xfd, 0xab, 0x25, 0x5c, 0xfd, 0x62, 0x4c, 0x4f, 0x14, 0x4b, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, + //Second Packet + //----------------------------------- + + + + //----------------------------------- + //Third Packet + + /* RTP Header */ + 0x80, 0x00, 0x00, 0x02, 0xBE, 0x14, 0x6D, 0x6C, + 0x00, 0x00, 0x00, 0x00, + + /* OpenIGTLink header */ + 0x00, 0x02, /* Version number */ + 0x49, 0x4D, 0x41, 0x47, 0x45, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* IMAGE */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4E, 0x61, + 0x6D, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xD4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x51, /* Body size */ + 0xC2, 0xE2, 0xD8, 0x52, 0xFC, 0x02, 0x05, 0x4B, /* CRC */ + + /* Extended Header */ + 0x00, 0x0C, 0X00, 0x12, 0x00, 0x00, 0x00, 0x27, + 0x00, 0x01, 0xE0, 0x02, + + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0x18, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0x00, 0x02, 0x00, 0x11, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x12, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x02, 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, 0x70, 0x61, 0x74, 0x69, 0x65, 0x6E, 0x74, 0x20, + 0x61, 0x67, 0x65, 0x32, 0x32, 0x53, 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x20, 0x70, 0x61, 0x74, 0x69, + 0x65, 0x6E, 0x74, 0x20, 0x61, 0x67, 0x65, 0x32, 0x35, +}; + + +#endif /* __TSET_DATA_IMAGE_H */ diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_sensor.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_sensor.h new file mode 100644 index 0000000..dd9fe99 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_sensor.h @@ -0,0 +1,47 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy status data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_SENSOR_H +#define __IGTL_TEST_DATA_SENSOR_H + +unsigned char test_sensor_message[] = { + 0x00, 0x01, /* Version number */ + 0x53, 0x45, 0x4e, 0x53, 0x4f, 0x52, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* SENSOR */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, /* Body size */ + 0x63, 0x7b, 0x80, 0x08, 0x66, 0x20, 0x20, 0xe7, /* CRC */ + + 0x06, /* larray */ + 0x00, /* status */ + 0x00, 0x44, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, /* unit */ + + 0x40, 0xfe, 0x24, 0x0c, 0x7a, 0xe1, 0x47, 0xae, /* value: sensor #0 */ + 0x40, 0xc8, 0x1c, 0xd6, 0xc8, 0xb4, 0x39, 0x58, /* value: sensor #1 */ + 0x40, 0x93, 0x4a, 0x45, 0x6d, 0x5c, 0xfa, 0xad, /* value: sensor #2 */ + 0x40, 0x5e, 0xdd, 0x3b, 0xe2, 0x2e, 0x5d, 0xe1, /* value: sensor #3 */ + 0x40, 0x28, 0xb0, 0xfc, 0xb4, 0xf1, 0xe4, 0xb4, /* value: sensor #4 */ + 0x3f, 0xf3, 0xc0, 0xca, 0x2a, 0x5b, 0x1d, 0x5d, /* value: sensor #4 */ +}; + +#endif /* IGTL_TEST_DATA_SENSOR_H */ + + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_status.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_status.h new file mode 100644 index 0000000..b3b7ec6 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_status.h @@ -0,0 +1,44 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy status data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_STATUS_H +#define __IGTL_TEST_DATA_STATUS_H + +unsigned char test_status_message[] = { + 0x00, 0x01, /* Version number */ + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* STATUS */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, /* Body size */ + 0x98, 0xee, 0x43, 0xee, 0xd8, 0xe4, 0x31, 0xcf, /* CRC */ + + 0x00, 0x0f, /* Status code */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, /* Sub code */ + 0x41, 0x43, 0x54, 0x55, 0x41, 0x54, 0x4f, 0x52, + 0x5f, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4c, 0x45, + 0x44, 0x00, 0x00, 0x00, /* Status name */ + 0x41, 0x63, 0x74, 0x75, 0x61, 0x74, 0x6f, 0x72, + 0x20, 0x41, 0x20, 0x69, 0x73, 0x20, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x2e, 0x00, +}; + +#endif /* IGTL_TEST_DATA_STATUS_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_string.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_string.h new file mode 100644 index 0000000..d71c235 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_string.h @@ -0,0 +1,41 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy status data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_STRING_H +#define __IGTL_TEST_DATA_STRING_H + +unsigned char test_string_message[] = { + 0x00, 0x01, /* Version number */ + 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* STRING */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, /* Body size */ + + 0xce, 0xf1, 0xb4, 0x2a, 0x70, 0x11, 0x04, 0xd4, /* CRC */ + + 0x00, 0x03, /* encoding */ + 0x00, 0x16, /* length */ + 0x57, 0x65, 0x6c, 0x63, 0x6f, 0x6d, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x4f, 0x70, 0x65, 0x6e, 0x49, + 0x47, 0x54, 0x4c, 0x69, 0x6e ,0x6b, /* string content */ + +}; + +#endif /* IGTL_TEST_DATA_SENSOR_H */ + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_tdata.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_tdata.h new file mode 100644 index 0000000..5f7d910 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_tdata.h @@ -0,0 +1,77 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy tdata data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_TDATA_H +#define __IGTL_TEST_DATA_TDATA_H + +unsigned char test_tdata_message[] = { + /*------- OpenIGTLink message header --------*/ + 0x00, 0x01, /* Version number */ + 0x54, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* TDATA */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, /* Body size */ + 0x5c, 0x7c, 0xeb, 0xfd, 0x27, 0x67, 0x68, 0x77, /* CRC */ + + /*---------- TDATA message body ------------*/ + /* Tracker data 0 */ + 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Name */ + 0x02, /* Instrument type */ + 0x00, + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, /* tx, ty */ + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, /* tz, sx */ + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, /* sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, /* nx, ny */ + 0xBD, 0xC8, 0x30, 0xAE, 0x42, 0x38, 0x36, 0x60, /* nz, px */ + 0x41, 0x9B, 0xC4, 0x67, 0x42, 0x38, 0x36, 0x60, /* py, pz */ + + /* Tracker data 1 */ + 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Name */ + 0x02, /* Instrument type */ + 0x00, + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, /* tx, ty */ + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, /* tz, sx */ + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, /* sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, /* nx, ny */ + 0xBD, 0xC8, 0x30, 0xAE, 0x42, 0x38, 0x36, 0x60, /* nz, px */ + 0x41, 0x9B, 0xC4, 0x67, 0x42, 0x38, 0x36, 0x60, /* py, pz */ + + /* Tracker data 1 */ + 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Name */ + 0x02, /* Instrument type */ + 0x00, + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, /* tx, ty */ + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, /* tz, sx */ + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, /* sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, /* nx, ny */ + 0xBD, 0xC8, 0x30, 0xAE, 0x42, 0x38, 0x36, 0x60, /* nz, px */ + 0x41, 0x9B, 0xC4, 0x67, 0x42, 0x38, 0x36, 0x60, /* py, pz */ + +}; + +#endif /* IGTL_TEST_DATA_TDATA_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_tdataFormat2.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_tdataFormat2.h new file mode 100644 index 0000000..640c523 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_tdataFormat2.h @@ -0,0 +1,97 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy tdata data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_TDATA_FORMAT2_H +#define __IGTL_TEST_DATA_TDATA_FORMAT2_H + +unsigned char test_tdata_messageFormat2[] = { + /*------- OpenIGTLink message header --------*/ + 0x00, 0x02, /* Version number */ + 0x54, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* TDATA */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, /* Body size */ + 0xbd, 0x30, 0x9e, 0x0e, 0x33, 0x10, 0x1c, 0x37, /* CRC */ + + /* Extended header + 0 2 4 8 12 + +-----------------+----------------------+---------------+-------------+ + | EXT_HEADER_SIZE | METADATA_HEADER_SIZE | METADATA_SIZE | MESSAGE_ID | + +-----------------+----------------------+---------------+-------------+*/ + 0x00, 0x0c, 0x00, 0x12, 0x00, 0x00, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x01, + + /*---------- TDATA message body ------------*/ + /* Tracker data 0 */ + 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Name */ + 0x02, /* Instrument type */ + 0x00, + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, /* tx, ty */ + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, /* tz, sx */ + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, /* sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, /* nx, ny */ + 0xBD, 0xC8, 0x30, 0xAE, 0x42, 0x38, 0x36, 0x60, /* nz, px */ + 0x41, 0x9B, 0xC4, 0x67, 0x42, 0x38, 0x36, 0x60, /* py, pz */ + + /* Tracker data 1 */ + 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Name */ + 0x02, /* Instrument type */ + 0x00, + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, /* tx, ty */ + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, /* tz, sx */ + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, /* sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, /* nx, ny */ + 0xBD, 0xC8, 0x30, 0xAE, 0x42, 0x38, 0x36, 0x60, /* nz, px */ + 0x41, 0x9B, 0xC4, 0x67, 0x42, 0x38, 0x36, 0x60, /* py, pz */ + + /* Tracker data 1 */ + 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Name */ + 0x02, /* Instrument type */ + 0x00, + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, /* tx, ty */ + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, /* tz, sx */ + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, /* sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, /* nx, ny */ + 0xBD, 0xC8, 0x30, 0xAE, 0x42, 0x38, 0x36, 0x60, /* nz, px */ + 0x41, 0x9B, 0xC4, 0x67, 0x42, 0x38, 0x36, 0x60, /* py, pz */ + + /*---------- TDATA Meta data body ------------*/ + 0x00, 0x02, /* Index Count */ + 0x00, 0x11, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, /* first element Key size(2 Bytes), value coding(2 Bytes), value size(4 Bytes)*/ + 0x00, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, /* second element Key size, value coding, value size*/ + + 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, 0x70, 0x61, /* First Patient Age 22*/ + 0x74, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x67, + 0x65, 0x32, + 0x32, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, /* Second Patient Age 25*/ + 0x70, 0x61, 0x74, 0x69, 0x65, 0x6e, 0x74, 0x20, + 0x61, 0x67, 0x65, 0x32, 0x35 + +}; + +#endif /* IGTL_TEST_DATA_TDATA_FORMAT2_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_trajectory.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_trajectory.h new file mode 100644 index 0000000..3678875 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_trajectory.h @@ -0,0 +1,125 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy trajectory data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_TRAJECTORY_H +#define __IGTL_TEST_DATA_TRAJECTORY_H + +unsigned char test_trajectory_message[] = { + /*------- OpenIGTLink message header --------*/ + 0x00, 0x01, /* Version number */ + 0x54, 0x52, 0x41, 0x4a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* TRAJECTORY */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc2, /* Body size */ + 0x62, 0x05, 0xa3, 0x66, 0x18, 0x57, 0x76, 0x30, /* CRC */ + + /*---------- TRAJECTORY message body ------------*/ + /* Trajectory data 0 */ + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x5f, 0x44, 0x45, 0x53, 0x43, 0x52, + 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Trajectory description */ + + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Group name (Trajectory etc.) */ + + 0x03, /* Type */ + 0x00, /* Reserved */ + 0xff, 0x00, 0x00, 0xff, /* RGBA */ + + 0x41, 0x20, 0x00, 0x00, 0x41, 0x70, 0x00, 0x00, + 0x41, 0xa0, 0x00, 0x00, /* Entry position */ + 0x41, 0xc8, 0x00, 0x00, 0x41, 0xf0, 0x00, 0x00, + 0x42, 0x0c, 0x00, 0x00, /* Target position */ + 0x40, 0xa0, 0x00, 0x00, /* Radius */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + + /* Trajectory data 1 */ + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x5f, 0x44, 0x45, 0x53, 0x43, 0x52, + 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Trajectory description */ + + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Group name (Trajectory etc.) */ + + 0x03, /* Type */ + 0x00, /* Reserved */ + 0x00, 0xff, 0x00, 0xff, /* RGBA */ + + 0x42, 0x20, 0x00, 0x00, 0x42, 0x34, 0x00, 0x00, + 0x42, 0x48, 0x00, 0x00, /* Entry position */ + 0x42, 0x5c, 0x00, 0x00, 0x42, 0x70, 0x00, 0x00, + 0x42, 0x82, 0x00, 0x00, /* Target position */ + 0x40, 0x20, 0x00, 0x00, /* Radius */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + + /* Trajectory data 2 */ + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x5f, 0x44, 0x45, 0x53, 0x43, 0x52, + 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Trajectory description */ + + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Group name (Trajectory etc.) */ + + 0x03, /* Type */ + 0x00, /* Reserved */ + 0x00, 0x00, 0xff, 0xff, /* RGBA */ + + 0x42, 0x8c, 0x00, 0x00, 0x42, 0x96, 0x00, 0x00, + 0x42, 0xa0, 0x00, 0x00, /* Entry position */ + 0x42, 0xaa, 0x00, 0x00, 0x42, 0xb4, 0x00, 0x00, + 0x42, 0xbe, 0x00, 0x00, /* Target position */ + 0x00, 0x00, 0x00, 0x00, /* Radius */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + +}; + +#endif /* IGTL_TEST_DATA_TRAJECTORY_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_trajectoryFormat2.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_trajectoryFormat2.h new file mode 100644 index 0000000..88c42b5 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_trajectoryFormat2.h @@ -0,0 +1,143 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy trajectory data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_TRAJECTORY_FORMAT2_H +#define __IGTL_TEST_DATA_TRAJECTORY_FORMAT2_H + +unsigned char test_trajectory_message_Format2[] = { + /*------- OpenIGTLink message header --------*/ + 0x00, 0x02, /* Version number */ + 0x54, 0x52, 0x41, 0x4a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* TRAJECTORY */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x07, /* Body size */ + 0x29, 0x44, 0x65, 0x7a, 0xc8, 0xa3, 0x96, 0xe9, /* CRC */ + + + /* Extended header + 0 2 4 8 12 + +-----------------+----------------------+---------------+-------------+ + | EXT_HEADER_SIZE | METADATA_HEADER_SIZE | METADATA_SIZE | MESSAGE_ID | + +-----------------+----------------------+---------------+-------------+*/ + 0x00, 0x0c, 0x00, 0x12, 0x00, 0x00, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x01, + + /*---------- TRAJECTORY message body ------------*/ + /* Trajectory data 0 */ + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x5f, 0x44, 0x45, 0x53, 0x43, 0x52, + 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Trajectory description */ + + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Group name (Trajectory etc.) */ + + 0x03, /* Type */ + 0x00, /* Reserved */ + 0xff, 0x00, 0x00, 0xff, /* RGBA */ + + 0x41, 0x20, 0x00, 0x00, 0x41, 0x70, 0x00, 0x00, + 0x41, 0xa0, 0x00, 0x00, /* Entry position */ + 0x41, 0xc8, 0x00, 0x00, 0x41, 0xf0, 0x00, 0x00, + 0x42, 0x0c, 0x00, 0x00, /* Target position */ + 0x40, 0xa0, 0x00, 0x00, /* Radius */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + + /* Trajectory data 1 */ + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x5f, 0x44, 0x45, 0x53, 0x43, 0x52, + 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Trajectory description */ + + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Group name (Trajectory etc.) */ + + 0x03, /* Type */ + 0x00, /* Reserved */ + 0x00, 0xff, 0x00, 0xff, /* RGBA */ + + 0x42, 0x20, 0x00, 0x00, 0x42, 0x34, 0x00, 0x00, + 0x42, 0x48, 0x00, 0x00, /* Entry position */ + 0x42, 0x5c, 0x00, 0x00, 0x42, 0x70, 0x00, 0x00, + 0x42, 0x82, 0x00, 0x00, /* Target position */ + 0x40, 0x20, 0x00, 0x00, /* Radius */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + + /* Trajectory data 2 */ + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x5f, 0x44, 0x45, 0x53, 0x43, 0x52, + 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Trajectory description */ + + 0x54, 0x52, 0x41, 0x4a, 0x45, 0x43, 0x54, 0x4f, + 0x52, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Group name (Trajectory etc.) */ + + 0x03, /* Type */ + 0x00, /* Reserved */ + 0x00, 0x00, 0xff, 0xff, /* RGBA */ + + 0x42, 0x8c, 0x00, 0x00, 0x42, 0x96, 0x00, 0x00, + 0x42, 0xa0, 0x00, 0x00, /* Entry position */ + 0x42, 0xaa, 0x00, 0x00, 0x42, 0xb4, 0x00, 0x00, + 0x42, 0xbe, 0x00, 0x00, /* Target position */ + 0x00, 0x00, 0x00, 0x00, /* Radius */ + + 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Owner image */ + + /*---------- TRAJECTORY Meta data body ------------*/ + 0x00, 0x02, /* Index Count */ + 0x00, 0x11, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, /* first element Key size(2 Bytes), value coding(2 Bytes), value size(4 Bytes)*/ + 0x00, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, /* second element Key size, value coding, value size*/ + + 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, 0x70, 0x61, /* First Patient Age 22*/ + 0x74, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x67, + 0x65, 0x32, + 0x32, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, /* Second Patient Age 25*/ + 0x70, 0x61, 0x74, 0x69, 0x65, 0x6e, 0x74, 0x20, + 0x61, 0x67, 0x65, 0x32, 0x35 +}; + +#endif /* IGTL_TEST_DATA_TRAJECTORY_FORMAT2_H */ + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_transform.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_transform.h new file mode 100644 index 0000000..c5890d0 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_transform.h @@ -0,0 +1,42 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy transform data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_TRANSFORM_H +#define __IGTL_TEST_DATA_TRANSFORM_H + +unsigned char test_transform_message[] = { + 0x00, 0x01, /* Version number */ + 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x4f, 0x52, + 0x4d, 0x00, 0x00, 0x00, /* TRANSFORM */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, /* Body size */ + 0xf6, 0xdd, 0x2b, 0x8e, 0xb4, 0xdf, 0x6d, 0xd2, /* CRC */ + + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, /* tx, ty */ + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, /* tz, sx */ + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, /* sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, /* nx, ny */ + 0xBD, 0xC8, 0x30, 0xAE, 0x42, 0x38, 0x36, 0x60, /* nz, px */ + 0x41, 0x9B, 0xC4, 0x67, 0x42, 0x38, 0x36, 0x60, /* py, pz */ +}; + +#endif /* IGTL_TEST_DATA_TRANSFORM_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_transformFormat2.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_transformFormat2.h new file mode 100644 index 0000000..9ca692e --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_transformFormat2.h @@ -0,0 +1,58 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy transform data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_TRANSFORM_FORMAT2_H +#define __IGTL_TEST_DATA_TRANSFORM_FORMAT2_H + +unsigned char test_transform_message_Format2[] = { + 0x00, 0x02, /* Version number */ + 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x4f, 0x52, + 0x4d, 0x00, 0x00, 0x00, /* TRANSFORM */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xd4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, /* Body size */ + 0xf6, 0x98, 0xf6, 0x4f, 0xda, 0xe2, 0x66, 0xdd, /* CRC */ + + /* Extended header + 0 2 4 8 12 + +-----------------+----------------------+---------------+-------------+ + | EXT_HEADER_SIZE | METADATA_HEADER_SIZE | METADATA_SIZE | MESSAGE_ID | + +-----------------+----------------------+---------------+-------------+*/ + 0x00, 0x0c, 0x00, 0x12, 0x00, 0x00, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x01, + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, /* tx, ty */ + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, /* tz, sx */ + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, /* sy, sz */ + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, /* nx, ny */ + 0xBD, 0xC8, 0x30, 0xAE, 0x42, 0x38, 0x36, 0x60, /* nz, px */ + 0x41, 0x9B, 0xC4, 0x67, 0x42, 0x38, 0x36, 0x60, /* py, pz */ + + /*---------- Transformation Meta data body ------------*/ + 0x00, 0x02, /* Index Count */ + 0x00, 0x11, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, /* first element Key size(2 Bytes), value coding(2 Bytes), value size(4 Bytes)*/ + 0x00, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, /* second element Key size, value coding, value size*/ + + 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, 0x70, 0x61, /* First Patient Age 22*/ + 0x74, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x67, + 0x65, 0x32, + 0x32, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, /* Second Patient Age 25*/ + 0x70, 0x61, 0x74, 0x69, 0x65, 0x6e, 0x74, 0x20, + 0x61, 0x67, 0x65, 0x32, 0x35 +}; + +#endif /* IGTL_TEST_DATA_TRANSFORM_FORMAT2_H */ diff --git a/openigtlink/repo/Testing/igtlutil/igtl_test_data_videometa.h b/openigtlink/repo/Testing/igtlutil/igtl_test_data_videometa.h new file mode 100644 index 0000000..cfff8c5 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_test_data_videometa.h @@ -0,0 +1,208 @@ +/*========================================================================= + + Program: OpenIGTLLink Library -- Dummy imgmeta data + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TEST_DATA_VIDEOMETA_H +#define __IGTL_TEST_DATA_VIDEOMETA_H + +unsigned char test_videometa_message[] = { + /*------- OpenIGTLink message header -------*/ + 0x00, 0x02, /* Version number */ + 0x56, 0x49, 0x44, 0x45, 0x4F, 0x4D, 0x45, 0x54, + 0x41, 0x00, 0x00, 0x00, /* VIDEOMETA */ + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4E, 0x61, + 0x6D, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* Device name */ + 0x00, 0x00, 0x00, 0x00, 0x49, 0x96, 0x02, 0xD4, /* Time stamp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xD4, /* Body size */ + 0x7D, 0xB9, 0x37, 0x17, 0xAB, 0x19, 0x8D, 0x48, /* CRC */ + + /* Extended header + 0 2 4 8 12 + +-----------------+----------------------+---------------+-------------+ + | EXT_HEADER_SIZE | METADATA_HEADER_SIZE | METADATA_SIZE | MESSAGE_ID | + +-----------------+----------------------+---------------+-------------+*/ + 0x00, 0x0C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + + /*---------- VIDEOMETA message body -----------*/ + /* Video meta data 0 */ + 0x56, 0x49, 0x44, 0x45, 0x4F, 0x5F, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4F, + 0x4E, 0x5F, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* video description */ + + 0x56, 0x49, 0x44, 0x45, 0x4F, 0x5F, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* device name */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4E, 0x54, 0x5F, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* patient name */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4E, 0x54, 0x5F, + 0x49, 0x44, 0x5F, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* patient ID */ + + 0x00, 0x04, /* Zoom factor */ + 0x40, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Focal length */ + 0x02, 0x00, 0x02, 0x00, 0x00, 0x40, /* size */ + + + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, + 0xBD, 0xC8, 0x30, 0xAE, 0x42, 0x38, 0x36, 0x60, + 0x41, 0x9B, 0xC4, 0x67, 0x42, 0x38, 0x36, 0x60, /* matrix */ + + 0x05, /* data type */ + 0x00, /* reserved */ + + // ---------------------------- + /* Video meta data 1 */ + 0x56, 0x49, 0x44, 0x45, 0x4F, 0x5F, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4F, + 0x4E, 0x5F, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* video description */ + + 0x56, 0x49, 0x44, 0x45, 0x4F, 0x5F, 0x31, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* device name */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4E, 0x54, 0x5F, + 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* patient name */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4E, 0x54, 0x5F, + 0x49, 0x44, 0x5F, 0x31, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* patient ID */ + + 0xFF, 0xFE, /* Zoom factor */ + 0x40, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Focal length */ + 0x01, 0x00, 0x00, 0x80, 0x00, 0x20, /* size */ + + + 0xBF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0x80, 0x00, 0x00, 0x42, 0x48, 0x00, 0x00, + 0x42, 0xC8, 0x00, 0x00, 0x41, 0x80, 0x00, 0x00, /* matrix */ + + 0x05, /* data type */ + 0x00, /* reserved */ + + // ---------------------- + /* Video meta data 2 */ + 0x56, 0x49, 0x44, 0x45, 0x4F, 0x5F, 0x44, 0x45, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4F, + 0x4E, 0x5F, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* video description */ + + 0x56, 0x49, 0x44, 0x45, 0x4F, 0x5F, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* device name */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4E, 0x54, 0x5F, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* patient name */ + + 0x50, 0x41, 0x54, 0x49, 0x45, 0x4E, 0x54, 0x5F, + 0x49, 0x44, 0x5F, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* patient ID */ + + 0x00, 0x00, /* Zoom factor */ + 0x40, 0x34, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, /* Focal length */ + 0x01, 0x00, 0x01, 0x00, 0x00, 0x20, /* size */ + + + 0xBF, 0x74, 0x73, 0xCD, 0x3E, 0x49, 0x59, 0xE6, + 0xBE, 0x63, 0xDD, 0x98, 0xBE, 0x49, 0x59, 0xE6, + 0x3E, 0x12, 0x49, 0x1B, 0x3F, 0x78, 0x52, 0xD6, + 0x3E, 0x63, 0xDD, 0x98, 0x3F, 0x78, 0x52, 0xD6, + 0xBD, 0xC8, 0x30, 0xAE, 0x43, 0x16, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x43, 0x48, 0x00, 0x00, /* matrix */ + + 0x05, /* data type */ + 0x00, /* reserved */ + + /*---------- Video Meta data body ------------*/ + 0x00, 0x00 /* Index Count */ + +}; + +#endif /* IGTL_TEST_DATA_VIDEOMETA_H */ + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_trajectory_test.c b/openigtlink/repo/Testing/igtlutil/igtl_trajectory_test.c new file mode 100644 index 0000000..eb2b6f8 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_trajectory_test.c @@ -0,0 +1,150 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include +#include +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_trajectory.h" +#include "igtl_util.h" + +/* include test trajectory data and serialized trajectory message */ +#include "igtl_test_data_trajectory.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#define TEST_TRAJECTORY_NUM 3 + +#pragma pack(1) +struct trajectory_message { + igtl_header header; + igtl_trajectory_element tlist[TEST_TRAJECTORY_NUM]; +}; +#pragma pack() + + +int main( int argc, char * argv [] ) +{ + + struct trajectory_message message; + int r; + int s; + + // Test structure size + if (sizeof(message) != IGTL_HEADER_SIZE+IGTL_TRAJECTORY_ELEMENT_SIZE*TEST_TRAJECTORY_NUM) + { + fprintf(stdout, "Invalid size of trajectory message structure.\n"); + return EXIT_FAILURE; + } + + /* Trajectory data 0 */ + strncpy((char*)&(message.tlist[0].name), "TRAJECTORY_DESCRIPTION_0", 64); + strncpy((char*)&(message.tlist[0].group_name), "TRAJECTORY", 32); + message.tlist[0].type = IGTL_TRAJECTORY_TYPE_ENTRY_TARGET; + message.tlist[0].reserved = 0; + message.tlist[0].rgba[0] = 255; + message.tlist[0].rgba[1] = 0; + message.tlist[0].rgba[2] = 0; + message.tlist[0].rgba[3] = 255; + message.tlist[0].entry_pos[0] = 10.0; + message.tlist[0].entry_pos[1] = 15.0; + message.tlist[0].entry_pos[2] = 20.0; + message.tlist[0].target_pos[0] = 25.0; + message.tlist[0].target_pos[1] = 30.0; + message.tlist[0].target_pos[2] = 35.0; + message.tlist[0].radius = 5.0; + strncpy((char*)&(message.tlist[0].owner_name), "IMAGE_0", 20); + + /* Trajectory data 1 */ + strncpy((char*)&(message.tlist[1].name), "TRAJECTORY_DESCRIPTION_1", 64); + strncpy((char*)&(message.tlist[1].group_name), "TRAJECTORY", 32); + message.tlist[1].type = IGTL_TRAJECTORY_TYPE_ENTRY_TARGET; + message.tlist[1].reserved = 0; + message.tlist[1].rgba[0] = 0; + message.tlist[1].rgba[1] = 255; + message.tlist[1].rgba[2] = 0; + message.tlist[1].rgba[3] = 255; + message.tlist[1].entry_pos[0] = 40.0; + message.tlist[1].entry_pos[1] = 45.0; + message.tlist[1].entry_pos[2] = 50.0; + message.tlist[1].target_pos[0] = 55.0; + message.tlist[1].target_pos[1] = 60.0; + message.tlist[1].target_pos[2] = 65.0; + message.tlist[1].radius = 2.5; + strncpy((char*)&(message.tlist[1].owner_name), "IMAGE_0", 20); + + /* Trajectory data 1 */ + strncpy((char*)&(message.tlist[2].name), "TRAJECTORY_DESCRIPTION_2", 64); + strncpy((char*)&(message.tlist[2].group_name), "TRAJECTORY", 32); + message.tlist[2].type = IGTL_TRAJECTORY_TYPE_ENTRY_TARGET; + message.tlist[2].reserved = 0; + message.tlist[2].rgba[0] = 0; + message.tlist[2].rgba[1] = 0; + message.tlist[2].rgba[2] = 255; + message.tlist[2].rgba[3] = 255; + message.tlist[2].entry_pos[0] = 70.0; + message.tlist[2].entry_pos[1] = 75.0; + message.tlist[2].entry_pos[2] = 80.0; + message.tlist[2].target_pos[0] = 85.0; + message.tlist[2].target_pos[1] = 90.0; + message.tlist[2].target_pos[2] = 95.0; + message.tlist[2].radius = 0.0; + strncpy((char*)&(message.tlist[2].owner_name), "IMAGE_0", 20); + + /* Swap byte order if necessary */ + igtl_trajectory_convert_byte_order(message.tlist, TEST_TRAJECTORY_NUM); + + /* Create OpenIGTLink header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "TRAJ", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_TRAJECTORY_ELEMENT_SIZE*TEST_TRAJECTORY_NUM; + message.header.crc = igtl_trajectory_get_crc(message.tlist, TEST_TRAJECTORY_NUM); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for debugging */ + /* + FILE *fp; + fp = fopen("trajectory.bin", "w"); + fwrite(&(message), IGTL_HEADER_SIZE+IGTL_TRAJECTORY_ELEMENT_SIZE*TEST_TRAJECTORY_NUM, 1, fp); + fclose(fp); + */ + + /* Compare the serialized byte array with the gold standard */ + r = memcmp((const void*)&message, (const void*)test_trajectory_message, + (size_t)(IGTL_HEADER_SIZE+IGTL_TRAJECTORY_ELEMENT_SIZE*TEST_TRAJECTORY_NUM)); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print first 256 bytes as HEX values in STDERR for debug */ + s = IGTL_HEADER_SIZE+IGTL_TRAJECTORY_ELEMENT_SIZE*TEST_TRAJECTORY_NUM; + if (s > 256) + { + s = 256; + } + + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", s); + //igtl_message_dump_hex(stdout, (const void*)&message, s); + + return EXIT_FAILURE; + } +} diff --git a/openigtlink/repo/Testing/igtlutil/igtl_transform_test.c b/openigtlink/repo/Testing/igtlutil/igtl_transform_test.c new file mode 100644 index 0000000..8d69247 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_transform_test.c @@ -0,0 +1,99 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtl_types.h" +#include "igtl_header.h" +#include "igtl_transform.h" +#include "igtl_util.h" +#include +#include + + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* The decimal is rounded when it is converted to IEEE 754 floating point */ + +/* Include serialized test data (gold standard) */ +#include "igtl_test_data_transform.h" + +#pragma pack(1) +struct transform_message { + igtl_header header; + igtl_float32 transform[12]; +}; +#pragma pack() + +int main( int argc, char * argv [] ) +{ + + struct transform_message message; + int r; + + /* Set dummy transform */ + message.transform[0] = -0.954892f; + message.transform[1] = 0.196632f; + message.transform[2] = -0.222525f; + message.transform[3] = -0.196632f; + message.transform[4] = 0.142857f; + message.transform[5] = 0.970014f; + message.transform[6] = 0.222525f; + message.transform[7] = 0.970014f; + message.transform[8] = -0.0977491f; + message.transform[9] = 46.0531f; + message.transform[10] = 19.4709f; + message.transform[11] = 46.0531f; + + igtl_transform_convert_byte_order(message.transform); + + /* Set header */ + message.header.header_version = 1; + strncpy( (char*)&(message.header.name), "TRANSFORM", 12 ); + strncpy( (char*)&(message.header.device_name), "DeviceName", 20 ); + message.header.timestamp = 1234567892; + message.header.body_size = IGTL_TRANSFORM_SIZE; + message.header.crc = igtl_transform_get_crc(message.transform); + igtl_header_convert_byte_order( &(message.header) ); + + /* Dumping data -- for testing */ + /* + FILE *fp; + fp = fopen("transform.bin", "w"); + fwrite(&(message.header), IGTL_HEADER_SIZE+IGTL_TRANSFORM_SIZE, 1, fp); + fclose(fp); + */ + + /* Compare the serialized byte array with the gold standard */ + r = memcmp((const void*)&message, (const void*)test_transform_message, + IGTL_HEADER_SIZE+IGTL_TRANSFORM_SIZE); + + if (r == 0) + { + return EXIT_SUCCESS; + } + else + { + /* Print message as HEX values in STDERR for debug */ + fprintf(stdout, "\n===== First %d bytes of the test message =====\n", IGTL_HEADER_SIZE+IGTL_TRANSFORM_SIZE); + igtl_message_dump_hex(stdout, (const void*)&message, IGTL_HEADER_SIZE+IGTL_TRANSFORM_SIZE); + + return EXIT_FAILURE; + } + +} + + + diff --git a/openigtlink/repo/Testing/igtlutil/igtl_util_test.c b/openigtlink/repo/Testing/igtlutil/igtl_util_test.c new file mode 100644 index 0000000..848f043 --- /dev/null +++ b/openigtlink/repo/Testing/igtlutil/igtl_util_test.c @@ -0,0 +1,26 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $RCSfile: $ + Language: C + Date: $Date: $ + Version: $Revision: $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "igtl_util.h" + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +int main( int argc, char * argv [] ) +{ + + return EXIT_SUCCESS; +} diff --git a/openigtlink/repo/Testing/img/igtlTestImage1.raw b/openigtlink/repo/Testing/img/igtlTestImage1.raw new file mode 100644 index 0000000..c761445 Binary files /dev/null and b/openigtlink/repo/Testing/img/igtlTestImage1.raw differ diff --git a/openigtlink/repo/Testing/img/igtlTestImage2.raw b/openigtlink/repo/Testing/img/igtlTestImage2.raw new file mode 100644 index 0000000..3d97aa8 Binary files /dev/null and b/openigtlink/repo/Testing/img/igtlTestImage2.raw differ diff --git a/openigtlink/repo/Testing/img/igtlTestImage3.raw b/openigtlink/repo/Testing/img/igtlTestImage3.raw new file mode 100644 index 0000000..0f1df7b Binary files /dev/null and b/openigtlink/repo/Testing/img/igtlTestImage3.raw differ diff --git a/openigtlink/repo/Testing/img/igtlTestImage4.raw b/openigtlink/repo/Testing/img/igtlTestImage4.raw new file mode 100644 index 0000000..c6c0892 Binary files /dev/null and b/openigtlink/repo/Testing/img/igtlTestImage4.raw differ diff --git a/openigtlink/repo/Testing/img/igtlTestImage5.raw b/openigtlink/repo/Testing/img/igtlTestImage5.raw new file mode 100644 index 0000000..50e67dc Binary files /dev/null and b/openigtlink/repo/Testing/img/igtlTestImage5.raw differ diff --git a/openigtlink/repo/Testing/img/igtlTestImage6.raw b/openigtlink/repo/Testing/img/igtlTestImage6.raw new file mode 100644 index 0000000..72a23f4 Binary files /dev/null and b/openigtlink/repo/Testing/img/igtlTestImage6.raw differ diff --git a/openigtlink/repo/Tools/CMakeLists.txt b/openigtlink/repo/Tools/CMakeLists.txt new file mode 100755 index 0000000..e6df58a --- /dev/null +++ b/openigtlink/repo/Tools/CMakeLists.txt @@ -0,0 +1,3 @@ +# +# Add here Tools that provide OpenIGTLink functionalities. +# diff --git a/openigtlink/repo/UseOpenIGTLink.cmake.in b/openigtlink/repo/UseOpenIGTLink.cmake.in new file mode 100644 index 0000000..349f264 --- /dev/null +++ b/openigtlink/repo/UseOpenIGTLink.cmake.in @@ -0,0 +1,30 @@ +# +# This file sets up include directories, link directories, and +# compiler settings for a project to use OpenIGTLink. It should not be +# included directly, but rather through the OpenIGTLink_USE_FILE setting +# obtained from OpenIGTLinkConfig.cmake. +# + +IF(OpenIGTLink_BUILD_SETTINGS_FILE AND NOT SKIP_OpenIGTLink_BUILD_SETTINGS_FILE) + INCLUDE(${CMAKE_ROOT}/Modules/CMakeImportBuildSettings.cmake) + CMAKE_IMPORT_BUILD_SETTINGS(${OpenIGTLink_BUILD_SETTINGS_FILE}) +ENDIF() + +# Add compiler flags needed to use OpenIGTLink. +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenIGTLink_REQUIRED_C_FLAGS}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenIGTLink_REQUIRED_CXX_FLAGS}") +SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenIGTLink_REQUIRED_LINK_FLAGS}") +SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${OpenIGTLink_REQUIRED_LINK_FLAGS}") +SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${OpenIGTLink_REQUIRED_LINK_FLAGS}") + +# Add include directories needed to use OpenIGTLink. +INCLUDE_DIRECTORIES(BEFORE ${OpenIGTLink_INCLUDE_DIRS}) + +# Load the OpenIGTLink targets +include(${OpenIGTLink_LIBRARY_TARGETS_FILE}) + +IF(OpenIGTLink_USE_WEBSOCKET) + SET(CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}/websocketpp") + find_package(websocketpp REQUIRED) + INCLUDE(${OpenIGTLink_DIR}/UseWebSocket.cmake) +ENDIF() \ No newline at end of file diff --git a/openigtlink/repo/Utilities/Doxygen/doxygen.config.in b/openigtlink/repo/Utilities/Doxygen/doxygen.config.in new file mode 100644 index 0000000..b03da77 --- /dev/null +++ b/openigtlink/repo/Utilities/Doxygen/doxygen.config.in @@ -0,0 +1,1350 @@ +# Doxyfile 1.4.3-20050530 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = OpenIGTLink + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @OpenIGTLink_VERSION_MAJOR@.@OpenIGTLink_VERSION_MINOR@.@OpenIGTLink_VERSION_PATCH@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @OpenIGTLink_BINARY_DIR@/Documents/Doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. +# OpenIGTLinkcommments: Links specific to OpenIGTLink will then require relative paths or absolute +# paths and will create issues. +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = NO + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = @OpenIGTLink_BINARY_DIR@/Documents/ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. + +SHOW_DIRECTORIES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the progam writes to standard output +# is used as the file version. See the manual for examples. +# +# FILE_VERSION_FILTER = "@OpenIGTLink_SOURCE_DIR@/Utilities/Doxygen/cvsVersionFilter.sh" +# + +FILE_VERSION_FILTER = + + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = "@OpenIGTLink_SOURCE_DIR@/Source" "@OpenIGTLink_SOURCE_DIR@/Documents/Doxygen" + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS = *.h *.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = "@OpenIGTLink_SOURCE_DIR@/Code/Common/itkPixelTraits.h" \ + "@OpenIGTLink_SOURCE_DIR@/Code/Common/itkNumericTraits.h" \ + "@OpenIGTLink_SOURCE_DIR@/Code/Common/itkNumericTraitsRGB.h" \ + "@OpenIGTLink_SOURCE_DIR@/Code/Common/itkNumericTraitsVectorPixel.h" \ + "@OpenIGTLink_SOURCE_DIR@/Code/Common/itkNumericTraitsTensorPixel.h" \ + "@OpenIGTLink_SOURCE_DIR@/Code/Common/itkNumericTraitsCovariantVectorPixel.h" \ + "@OpenIGTLink_SOURCE_DIR@/Code/Common/itkNumericTraitsVariableLengthVectorPixel.h" \ + "@OpenIGTLink_SOURCE_DIR@/Code/IO/itkPixelData.h" \ + "@OpenIGTLink_SOURCE_DIR@/Code/IO/itkAnalyzeDbh.h" + + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = "*/vxl_copyright.h" "*/vcl/*" "*/dll.h" \ + "*/test*" "*/example*" "*config*" "*/contrib/*" \ + "*/Templates/*" "*_mocced.cxx" # "*impl*" + + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = "@OpenIGTLink_SOURCE_DIR@/Testing/Code" "@OpenIGTLink_SOURCE_DIR@/Examples" "@OpenIGTLink_SOURCE_DIR@/Examples" + + + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = *.cxx + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = "@OpenIGTLink_SOURCE_DIR@/Documents/Art" + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = "perl @OpenIGTLink_BINARY_DIR@/Utilities/Doxygen/igtldoxygen.pl" + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 3 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = "@OpenIGTLink_SOURCE_DIR@/Documents/Doxygen/DoxygenHeader.html" + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = "@OpenIGTLink_SOURCE_DIR@/Documents/Doxygen/DoxygenFooter.html" + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = "@OpenIGTLink_SOURCE_DIR@/Documents/Doxygen/DoxygenStyle.css" + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = YES + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 1 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = YES + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = NO + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = "itkNotUsed(x)="\ + "itkSetMacro(name,type)= \ + virtual void Set##name (type _arg);" \ + "itkGetMacro(name,type)= \ + virtual type Get##name ();" \ + "itkGetConstMacro(name,type)= \ + virtual type Get##name () const;" \ + "itkSetStringMacro(name)= \ + virtual void Set##name (const char* _arg);" \ + "itkGetStringMacro(name)= \ + virtual const char* Get##name () const;" \ + "itkSetClampMacro(name,type,min,max)= \ + virtual void Set##name (type _arg);" \ + "itkSetObjectMacro(name,type)= \ + virtual void Set##name (type* _arg);" \ + "itkGetObjectMacro(name,type)= \ + virtual type* Get##name ();" \ + "itkSetConstObjectMacro(name,type)= \ + virtual void Set##name ( const type* _arg);" \ + "itkGetConstObjectMacro(name,type)= \ + virtual const type* Get##name ();" \ + "itkGetConstReferenceMacro(name,type)= \ + virtual const type& Get##name ();" \ + "itkGetConstReferenceObjectMacro(name,type)= \ + virtual const type::Pointer& Get##name () const;" \ + "itkBooleanMacro(name)= \ + virtual void name##On (); \ + virtual void name##Off ();" \ + "itkSetVector2Macro(name,type)= \ + virtual void Set##name (type _arg1, type _arg2) \ + virtual void Set##name (type _arg[2]);" \ + "itkGetVector2Macro(name,type)= \ + virtual type* Get##name () const; \ + virtual void Get##name (type& _arg1, type& _arg2) const; \ + virtual void Get##name (type _arg[2]) const;" \ + "itkSetVector3Macro(name,type)= \ + virtual void Set##name (type _arg1, type _arg2, type _arg3) \ + virtual void Set##name (type _arg[3]);" \ + "itkGetVector3Macro(name,type)= \ + virtual type* Get##name () const; \ + virtual void Get##name (type& _arg1, type& _arg2, type& _arg3) const; \ + virtual void Get##name (type _arg[3]) const;" \ + "itkSetVector4Macro(name,type)= \ + virtual void Set##name (type _arg1, type _arg2, type _arg3, type _arg4) \ + virtual void Set##name (type _arg[4]);" \ + "itkGetVector4Macro(name,type)= \ + virtual type* Get##name () const; \ + virtual void Get##name (type& _arg1, type& _arg2, type& _arg3, type& _arg4) const; \ + virtual void Get##name (type _arg[4]) const;" \ + "itkSetVector6Macro(name,type)= \ + virtual void Set##name (type _arg1, type _arg2, type _arg3, type _arg4, type _arg5, type _arg6) \ + virtual void Set##name (type _arg[6]);" \ + "itkGetVector6Macro(name,type)= \ + virtual type* Get##name () const; \ + virtual void Get##name (type& _arg1, type& _arg2, type& _arg3, type& _arg4, type& _arg5, type& _arg6) const; \ + virtual void Get##name (type _arg[6]) const;" \ + "itkSetVectorMacro(name,type,count)= \ + virtual void Set##name(type data[]);" \ + "itkGetVectorMacro(name,type,count)= \ + virtual type* Get##name () const;" \ + "itkNewMacro(type)= \ + static Pointer New();" \ + "itkTypeMacro(thisClass,superclass)= \ + virtual const char *GetNameOfClass() const;" \ + "itkEventMacro(thisClass,superclass)= \ + class thisClass : public superclass {};" \ + "itkConceptMacro(thisName,thisConcept)= \ + /** This class requires thisName \ + in the form of thisConcept */ \ + typedef thisConcept thisName;" \ + "vcl_numeric_limits= \ + std::numeric_limits" \ + "OpenIGTLink_TYPENAME= \ + typename" \ + "FEM_ABSTRACT_CLASS(thisClass,parentClass)= \ + public: \ + /** Standard "Self" typedef.*/ \ + typedef thisClass Self; \ + /** Standard "Superclass" typedef. */ \ + typedef parentClass Superclass; \ + /** Pointer or SmartPointer to an object. */ \ + typedef Self* Pointer; \ + /** Const pointer or SmartPointer to an object. */ \ + typedef const Self* ConstPointer; \ + private:" \ + "FEM_CLASS(thisClass,parentClass)= \ + FEM_ABSTRACT_CLASS(thisClass,parentClass) \ + public: \ + /** Create a new object from the existing one */ \ + virtual Baseclass::Pointer Clone() const; \ + /** Class ID for FEM object factory */ \ + static const int CLID; \ + /** Virtual function to access the class ID */ \ + virtual int ClassID() const \ + { return CLID; } \ + /** Object creation in an itk compatible way */ \ + static Self::Pointer New() \ + { return new Self(); } \ + private:" \ + "FREEVERSION" "ERROR_CHECKING" \ + "HAS_TIFF" "HAS_JPEG" "HAS_NETLIB" "HAS_PNG" "HAS_ZLIB" \ + "HAS_GLUT" "HAS_QT" \ + "VCL_USE_NATIVE_STL=1" "VCL_USE_NATIVE_COMPLEX=1" \ + "VCL_HAS_BOOL=1" "VXL_BIG_ENDIAN=1" "VXL_LITTLE_ENDIAN=0"\ + "VNL_DLL_DATA=" "size_t=vcl_size_t" + + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = @OpenIGTLink_BINARY_DIR@/Documents/Doxygen/InsightDoxygen.tag + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/openigtlink/repo/Utilities/Doxygen/igtldoxygen.pl.in b/openigtlink/repo/Utilities/Doxygen/igtldoxygen.pl.in new file mode 100755 index 0000000..fc1a7a1 --- /dev/null +++ b/openigtlink/repo/Utilities/Doxygen/igtldoxygen.pl.in @@ -0,0 +1,3 @@ + +system ("perl @OpenIGTLink_SOURCE_DIR@/Utilities/Doxygen/igtlgroup.pl $ARGV[0]"); + diff --git a/openigtlink/repo/Utilities/Doxygen/igtlgroup.pl b/openigtlink/repo/Utilities/Doxygen/igtlgroup.pl new file mode 100755 index 0000000..7cfe41a --- /dev/null +++ b/openigtlink/repo/Utilities/Doxygen/igtlgroup.pl @@ -0,0 +1,85 @@ +# if regular doxycomment add a @{ +# at next empty line add a //@} + +$ingroup = 0; +$semicount =0; +$endbracecount = 0; +$endparencount = 0; +while(<>) +{ + chomp; + $line = $_; +# if the line is not an empty line + if( $line =~ /\S+/ ) + { + if ( /\/\*\*(.*)/ ) + { + # I guess it was not a group, dump savebuffer + if($ingroup) + { + print "/**" . $savebuffer . "\n"; + } + # if it is a class or brief then output the line but + # do not start a group + if ( /(\\class|\\brief)/ ) + { + print $line . "\n"; + } + # must be a group so start saving + else + { + $savebuffer = "$1" . "\n"; + $ingroup = 1; + $semicount = 0; + $endbracecount = 0; + $endparencount = 0; + } + } + else + { + # add to save buffer if in group + if($ingroup) + { + $savebuffer = $savebuffer . $_ . "\n"; + } + else + { + # non empty line that is not the start of a doxy comment + print $_ . "\n"; + } + } + if($line =~ /;/ ) + { + $semicount = $semicount + 1; + } + if($line =~ /\}/ ) + { + $endbracecount = $endbracecount + 1; + } + if($line =~ /\)/ ) + { + $endparencount = $endparencount + 1; + } + } + else + { + if($ingroup) + { + if($endparencount > 1 && ($semicount > 1 || $endbracecount > 1)) + { + print "/**@\{" . $savebuffer . "//@}\n\n"; + } + else + { + print "/**" . $savebuffer . "\n"; + } + $savebuffer = ""; + $ingroup = 0; + } + else + { + print $line . "\n"; + } + } +} + diff --git a/openigtlink/repo/Utilities/GitSetup/.gitattributes b/openigtlink/repo/Utilities/GitSetup/.gitattributes new file mode 100644 index 0000000..3323f94 --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/.gitattributes @@ -0,0 +1,9 @@ +.git* export-ignore + +# Exclude from source archives files specific to Git work tree. +* export-ignore + +config* eol=lf whitespace=indent-with-non-tab +git-* eol=lf whitespace=indent-with-non-tab +tips eol=lf whitespace=indent-with-non-tab +setup-* eol=lf whitespace=indent-with-non-tab diff --git a/openigtlink/repo/Utilities/GitSetup/LICENSE b/openigtlink/repo/Utilities/GitSetup/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/openigtlink/repo/Utilities/GitSetup/NOTICE b/openigtlink/repo/Utilities/GitSetup/NOTICE new file mode 100644 index 0000000..09aab19 --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/NOTICE @@ -0,0 +1,10 @@ +The contents of this folder are based on Kitware Local Git Setup Script derived from VTK. + +https://github.com/Kitware/VTK + + +Kitware Local Git Setup Scripts +Copyright 2010-2012 Kitware, Inc. + +This product includes software developed at Kitware, Inc. +(http://www.kitware.com/). diff --git a/openigtlink/repo/Utilities/GitSetup/README b/openigtlink/repo/Utilities/GitSetup/README new file mode 100644 index 0000000..cf468fb --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/README @@ -0,0 +1,80 @@ +Kitware Local Git Setup Scripts + + +Introduction +------------ + +This is a collection of local Git development setup scripts meant for +inclusion in project source trees to aid their development workflow. +Project-specific information needed by the scripts may be configured +in a "config" file added next to them in the project. + + +Import +------ + +A project may import these scripts into their source tree by +initializing a subtree merge. Bring up a Git prompt and set the +current working directory inside a clone of the target project. +Fetch the "setup" branch from the GitSetup repository: + + $ git fetch ../GitSetup setup:setup + +Prepare to merge the branch but place the content in a subdirectory. +Any prefix (with trailing '/') may be chosen so long as it is used +consistently within a project through the rest of these instructions: + + $ git merge -s ours --no-commit setup + $ git read-tree -u --prefix=Utilities/GitSetup/ setup + +Commit the merge with an informative message: + + $ git commit + ------------------------------------------------------------------------ + Merge branch 'setup' + + Add Utilities/GitSetup/ directory using subtree merge from + the general GitSetup repository "setup" branch. + ------------------------------------------------------------------------ + + +Configuration +------------- + +Read the "Project configuration instructions" comment in each script. +Add a "config" file next to the scripts with desired configuration +(optionally copy and modify "config.sample"). For example, to +configure the "setup-hooks" script: + + $ git config -f Utilities/GitSetup/config hooks.url "$url" + +where "$url" is the project repository publishing the "hooks" branch. +When finished, add and commit the configuration file: + + $ git add Utilities/GitSetup/config + $ git commit + + +Update +------ + +A project may update these scripts from the GitSetup repository. +Bring up a Git prompt and set the current working directory inside a +clone of the target project. Fetch the "setup" branch from the +GitSetup repository: + + $ git fetch ../GitSetup setup:setup + +Merge the "setup" branch into the subtree: + + $ git merge -X subtree=Utilities/GitSetup setup + +where "Utilities/GitSetup" is the same prefix used during the import +setup, but without a trailing '/'. + + +License +------- + +Distributed under the Apache License 2.0. +See LICENSE and NOTICE for details. diff --git a/openigtlink/repo/Utilities/GitSetup/config b/openigtlink/repo/Utilities/GitSetup/config new file mode 100644 index 0000000..380ea06 --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/config @@ -0,0 +1,12 @@ +[hooks] + url = https://github.com/openigtlink/OpenIGTLink.git +[upstream] + url = https://github.com/openigtlink/OpenIGTLink.git +[github] + host = github.com + group-path = openigtlink + group-name = openigtlink + project-path = OpenIGTLink + project-name = OpenIGTLink + url = https://github.com/$username/OpenIGTLink.git + pushurl = https://github.com/$username/OpenIGTLink.git diff --git a/openigtlink/repo/Utilities/GitSetup/config.sample b/openigtlink/repo/Utilities/GitSetup/config.sample new file mode 100644 index 0000000..eeb468b --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/config.sample @@ -0,0 +1,32 @@ +# Kitware Local Git Setup Scripts - Sample Project Configuration +# +# Copy to "config" and edit as necessary. + +[hooks] + url = http://public.kitware.com/GitSetup.git + #branch = hooks + +[ssh] + host = public.kitware.com + key = id_git_public + request-url = https://www.kitware.com/Admin/SendPassword.cgi + +[stage] + #url = git://public.kitware.com/stage/Project.git + #pushurl = git@public.kitware.com:stage/Project.git + +[gerrit] + #project = Project + site = http://review.source.kitware.com + # pushurl placeholder "$username" is literal + pushurl = $username@review.source.kitware.com:Project + +[upstream] + url = git://public.kitware.com/Project.git + +[gitlab] + host = gitlab.kitware.com + group-path = group + group-name = Group + project-path = project + project-name = Project diff --git a/openigtlink/repo/Utilities/GitSetup/git-github-push b/openigtlink/repo/Utilities/GitSetup/git-github-push new file mode 100755 index 0000000..7354713 --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/git-github-push @@ -0,0 +1,223 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2015 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +USAGE='[] [...] [--] + +OPTIONS + +--dry-run + Show what would be pushed without actually updating the destination + +-f,--force + Force-push the topic HEAD to rewrite the destination branch + +--keep-data + Do not erase local data refs after pushing + +--no-data + Do not push any data refs that may normally go with the topic + +--no-default + Do not push the default branch (e.g. master) + +--no-topic + Do not push the topic HEAD. +' +OPTIONS_SPEC= +SUBDIRECTORY_OK=Yes +. "$(git --exec-path)/git-sh-setup" + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +# Load the project configuration. +github_upstream='' && +github_configured='' && +config="${BASH_SOURCE%/*}/config" && +protocol=$(git config -f "$config" --get github.protocol || + echo "https") && +host=$(git config -f "$config" --get github.host) && +site=$(git config -f "$config" --get github.site || + echo "$protocol://$host") && +group_path=$(git config -f "$config" --get github.group-path) && +project_path=$(git config -f "$config" --get github.project-path) && +github_upstream="$site/$group_path/$project_path.git" && +github_pushurl=$(git config --get remote.github.pushurl || + git config --get remote.github.url) && +github_configured=1 + +data_report_and_remove() { + data="$1" && + if test -n "$keep_data"; then + action="kept" + else + action="removed" + if test -z "$dry_run"; then + git update-ref -d "$1" 2>/dev/null || true + fi + fi && + echo "Pushed $data and $action local ref." +} + +data_refs() { + git rev-list "$@" | + git diff-tree --no-commit-id --root -c -r --diff-filter=AM --stdin | + egrep '\.(md5)$' | + # read :srcmode dstmode srcobj dstobj status file + while read _ _ _ obj _ file; do + # Identify the hash algorithm used. + case "$file" in + *.md5) algo=MD5 ; validate="^[0-9a-fA-F]{32}$" ;; + *) continue ;; + esac + + # Load and validate the hash. + if hash=$(git cat-file blob $obj 2>/dev/null) && + echo "$hash" | egrep-q "$validate"; then + # Use this data ref if it exists. + git for-each-ref --format='%(refname)' "refs/data/$algo/$hash" + fi + done | + sort | + uniq +} + +#----------------------------------------------------------------------------- + +remote='' +refspecs='' +force='' +keep_data='' +no_topic='' +no_default='' +no_data='' +dry_run='' + +# Parse the command line options. +while test $# != 0; do + case "$1" in + -f|--force) force='+' ;; + --keep-data) keep_data=1 ;; + --no-topic) no_topic=1 ;; + --no-data) no_data=1 ;; + --dry-run) dry_run=--dry-run ;; + --no-default) no_default=1 ;; + --) shift; break ;; + -*) usage ;; + *) test -z "$remote" || usage ; remote="$1" ;; + esac + shift +done +test $# = 0 || usage + +# Default remote. +test -n "$remote" || remote="github" + +if test -z "$no_topic"; then + # Identify and validate the topic branch name. + head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic='' + if test -z "$topic" -o "$topic" = "master"; then + die 'Please name your topic: + git checkout -b descriptive-name' + fi + # The topic branch will be pushed by name. + refspecs="${force}HEAD:refs/heads/$topic $refspecs" +fi + +# Fetch the current remote master branch head. +# This helps computation of a minimal pack to push. +echo "Fetching $remote master" +fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out" +github_head=$(git rev-parse FETCH_HEAD) || exit + +# Fetch the current upstream master branch head. +if origin_fetchurl=$(git config --get remote.origin.url) && + test "$origin_fetchurl" = "$github_upstream"; then + upstream_remote='origin' +else + upstream_remote="$github_upstream" +fi +echo "Fetching $upstream_remote master" +fetch_out=$(git fetch "$upstream_remote" master 2>&1) || die "$fetch_out" +upstream_head=$(git rev-parse FETCH_HEAD) || exit + +# Collect refspecs for each data object referenced by the topic. +if test -z "$no_data"; then + data_refs=$(data_refs $upstream_head..) && + for data in $data_refs; do + refspecs="+$data:$data $refspecs" + done +else + data_refs='' +fi + +# Add a refspec to keep the remote master up to date if possible. +if test -z "$no_default" && + base=$(git merge-base "$github_head" "$upstream_head") && + test "$base" = "$github_head"; then + refspecs="$upstream_head:refs/heads/master $refspecs" +fi + +# Exit early if we have nothing to push. +if test -z "$refspecs"; then + echo 'Nothing to push!' + exit 0 +fi + +# Push. Save output and exit code. +echo "Pushing to $remote" +push_config='-c advice.pushUpdateRejected=false' +push_stdout=$(git $push_config push --porcelain $dry_run "$remote" $refspecs); push_exit=$? +echo "$push_stdout" + +# Advise the user to force-push if needed. +if test "$push_exit" -ne 0 && test -z "$force" && + echo "$push_stdout" | egrep-q 'non-fast-forward'; then + echo ' +Add "-f" or "--force" to push a rewritten topic.' +fi + +# Check if data were pushed successfully. +for data in $data_refs; do + if echo "$push_stdout" | egrep-q "^[*=+] $data"; then + data_report_and_remove "$data" + fi +done + +# Tell the user what to do next with the topic in Github. +if test -z "$no_topic" && + test "$push_exit" -eq 0 && + test "$remote" = "github" && + test -n "$github_configured" && + echo "$github_pushurl" | egrep-q "$host[^/:]*[/:][^/]*/$project_path\\.git$"; then + userpath="${github_pushurl%/*.git}" && + username="${userpath##*[/:]}" && + echo ' +The topic has been pushed to your fork in GitHub. Visit + + '"$site/$username/$project_path/tree/$topic"' + +to see the files. Visit + + '"$site/$username/$project_path/merge_requests/new?merge_request[source_branch]=$topic"' + +to create a Merge Request if there is not one already.' +fi + +# Reproduce the push exit code. +exit $push_exit diff --git a/openigtlink/repo/Utilities/GitSetup/setup-github b/openigtlink/repo/Utilities/GitSetup/setup-github new file mode 100755 index 0000000..1f59a9a --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/setup-github @@ -0,0 +1,140 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2015 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up the local Git repository to push to +# a personal fork for this project in GitHub. + +# Project configuration instructions: +# +# - Run a GitHub server +# +# - Populate adjacent "config" file with: +# github.protocol = Top GitHub protocol, if not 'https' +# github.host = Top GitHub fully qualified host name +# github.site = Top GitHub URL, if not "://" +# github.group-name = Name of group containing project in GitHub +# github.group-path = Path of group containing project in GitHub +# github.project-name = Name of project within GitHub group +# github.project-path = Path of project within GitHub group +# github.url = GitHub push URL with "$username" placeholder, +# if not "/$username/.git" +# github.pushurl = GitHub push URL with "$username" placeholder, +# if not "git@:$username/.git" +# github.remote = GitHub remote name, if not "github" + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Load the project configuration. +protocol=$(git config -f config --get github.protocol || + echo "https") && +host=$(git config -f config --get github.host) && +site=$(git config -f config --get github.site || + echo "$protocol://$host") && +group_path=$(git config -f config --get github.group-path) && +group_name=$(git config -f config --get github.group-name) && +project_name=$(git config -f config --get github.project-name) && +project_path=$(git config -f config --get github.project-path) && +pushurl_=$(git config -f config --get github.pushurl || + echo "git@$host:\$username/$project_path.git") && +remote=$(git config -f config --get github.remote || + echo "github") && +fetchurl_=$(git config -f config --get github.url || + echo "$site/\$username/$project_path.git") || +die 'This project is not configured to use GitHub.' + +# Get current github push URL. +pushurl=$(git config --get remote."$remote".pushurl || + git config --get remote."$remote".url || echo '') && + +# Tell user about current configuration. +if test -n "$pushurl"; then + echo 'Remote "'"$remote"'" is currently configured to push to + + '"$pushurl"' +' && + read -ep 'Reconfigure GitHub? [y/N]: ' ans && + if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then + setup=1 + else + setup='' + fi +else + echo 'Remote "'"$remote"'" is not yet configured. +' && + read -ep 'Configure GitHub to contribute to '"$project_name"'? [Y/n]: ' ans && + if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then + exit 0 + else + setup=1 + fi +fi && + +setup_instructions='Add your SSH public keys at + + '"$site"'/profile/keys + +Then visit the main repository at: + + '"$site/$group_path/$project_path"' + +and use the Fork button in the upper right. +' + +# Perform setup if necessary. +if test -n "$setup"; then + echo 'Sign-in to GitHub to get/set your username at + + '"$site/profile/account"' + +'"$setup_instructions" && + read -ep "GitHub username? [$USER]: " gu && + if test -z "$gu"; then + gu="$USER" + fi && + fetchurl="${fetchurl_/\$username/$gu}" && + if test -z "$pushurl"; then + git remote add "$remote" "$fetchurl" + else + git config remote."$remote".url "$fetchurl" + fi && + pushurl="${pushurl_/\$username/$gu}" && + git config remote."$remote".pushurl "$pushurl" && + echo 'Remote "'"$remote"'" is now configured to push to + + '"$pushurl"' +' +fi && + +# Optionally test GitHub access. +if test -n "$pushurl"; then + read -ep 'Test access to GitHub (SSH)? [y/N]: ' ans && + if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then + echo -n 'Testing GitHub access by SSH...' + if git ls-remote --heads "$pushurl" >/dev/null; then + echo 'passed.' + else + echo 'failed.' && + die 'Could not access your GitHub fork of this project. +'"$setup_instructions" + fi + fi +fi diff --git a/openigtlink/repo/Utilities/GitSetup/setup-hooks b/openigtlink/repo/Utilities/GitSetup/setup-hooks new file mode 100755 index 0000000..ca07712 --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/setup-hooks @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up local Git hooks for this project. + +# Project configuration instructions: +# +# - Publish a "hooks" branch in the project repository such that +# clones will have "refs/remotes/origin/hooks". +# +# - Populate adjacent "config" file with: +# hooks.url = Repository URL publishing "hooks" branch +# hooks.branch = Repository branch instead of "hooks" + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Select a hooks branch. +if url=$(git config --get hooks.url); then + # Fetch hooks from locally configured repository. + branch=$(git config hooks.branch || echo hooks) +elif git for-each-ref refs/remotes/origin/hooks 2>/dev/null | + egrep-q 'refs/remotes/origin/hooks$'; then + # Use hooks cloned from origin. + url=.. && branch=remotes/origin/hooks +elif url=$(git config -f config --get hooks.url); then + # Fetch hooks from project-configured repository. + branch=$(git config -f config hooks.branch || echo hooks) +else + die 'This project is not configured to install local hooks.' +fi && + +# Populate ".git/hooks". +echo 'Setting up git hooks...' && +git_dir=$(git rev-parse --git-dir) && +mkdir -p "$git_dir/hooks" && +cd "$git_dir/hooks" && +if ! test -e .git; then + git init -q || die 'Could not run git init for hooks.' +fi && +git fetch -q "$url" "$branch" && +git reset -q --hard FETCH_HEAD || die 'Failed to install hooks' diff --git a/openigtlink/repo/Utilities/GitSetup/setup-ssh b/openigtlink/repo/Utilities/GitSetup/setup-ssh new file mode 100755 index 0000000..8920a5b --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/setup-ssh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up ssh push access to the repository host. + +# Project configuration instructions: +# +# - Populate adjacent "config" file with: +# ssh.host = Repository host name +# ssh.user = Username on host, if not "git" +# ssh.key = Local ssh key name +# ssh.request-url = Web page URL to request ssh access + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Load the project configuration. +host=$(git config -f config --get ssh.host) && +user=$(git config -f config --get ssh.user || echo git) && +key=$(git config -f config --get ssh.key) && +request_url=$(git config -f config --get ssh.request-url) || +die 'This project is not configured for ssh push access.' + +# Check for existing configuration. +if test -r ~/.ssh/config && + egrep-q 'Host[= ]'"${host//\./\\.}" ~/.ssh/config; then + echo 'Host "'"$host"'" is already in ~/.ssh/config' && + setup= && + question='Test' +else + echo 'Host "'"$host"'" not found in ~/.ssh/config' && + setup=1 && + question='Setup and test' +fi && + +# Ask the user whether to make changes. +echo '' && +read -ep "${question} push access by ssh to $user@$host? [y/N]: " access && +if test "$access" != "y" -a "$access" != "Y"; then + exit 0 +fi && + +# Setup host configuration if necessary. +if test -n "$setup"; then + if ! test -d ~/.ssh; then + mkdir -p ~/.ssh && + chmod 700 ~/.ssh + fi && + if ! test -f ~/.ssh/config; then + touch ~/.ssh/config && + chmod 600 ~/.ssh/config + fi && + ssh_config='Host='"$host"' + IdentityFile ~/.ssh/'"$key" && + echo "Adding to ~/.ssh/config: + +$ssh_config +" && + echo "$ssh_config" >> ~/.ssh/config && + if ! test -e ~/.ssh/"$key"; then + if test -f ~/.ssh/id_rsa; then + # Take care of the common case. + ln -s id_rsa ~/.ssh/"$key" + echo ' +Assuming ~/.ssh/id_rsa is the private key corresponding to the public key for + + '"$user@$host"' + +If this is incorrect place private key at "~/.ssh/'"$key"'".' + else + echo ' +Place the private key corresponding to the public key registered for + + '"$user@$host"' + +at "~/.ssh/'"$key"'".' + fi + read -e -n 1 -p 'Press any key to continue...' + fi +fi || exit 1 + +# Test access configuration. +echo 'Testing ssh push access to "'"$user@$host"'"...' && +if ! ssh "$user@$host" info; then + die 'No ssh push access to "'"$user@$host"'". You may need to request access at + + '"$request_url"' +' +fi diff --git a/openigtlink/repo/Utilities/GitSetup/setup-stage b/openigtlink/repo/Utilities/GitSetup/setup-stage new file mode 100755 index 0000000..ce6ec45 --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/setup-stage @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up the topic stage for pushing changes. + +# Project configuration instructions: +# +# - Run a Topic Stage repository next to the main project repository. +# +# - Populate adjacent "config" file with: +# stage.url = Topic Stage repository URL +# stage.pushurl = Topic Stage push URL if not "$url" + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Load the project configuration. +fetchurl_=$(git config -f config --get stage.url) && +pushurl_=$(git config -f config --get stage.pushurl || echo "$fetchurl_") && +remote=$(git config -f config --get stage.remote || echo 'stage') || +die 'This project is not configured to use a topic stage.' + +# Get current stage push URL. +pushurl=$(git config --get remote."$remote".pushurl || + git config --get remote."$remote".url || echo '') && + +# Tell user about current configuration. +if test -n "$pushurl"; then + echo 'Remote "'"$remote"'" is currently configured to push to + + '"$pushurl"' +' && + read -ep 'Reconfigure Topic Stage? [y/N]: ' ans && + if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then + setup=1 + else + setup='' + fi +else + setup=1 +fi + +# Perform setup if necessary. +if test -n "$setup"; then + echo 'Setting up the topic stage...' && + fetchurl="${fetchurl_}" && + if test -z "$pushurl"; then + git remote add "$remote" "$fetchurl" + else + git config remote."$remote".url "$fetchurl" + fi && + pushurl="${pushurl_}" && + if test "$pushurl" != "$fetchurl"; then + git config remote."$remote".pushurl "$pushurl" + fi && + echo 'Remote "'"$remote"'" is now configured to push to + + '"$pushurl"' +' +fi || die 'Could not configure the topic stage remote.' diff --git a/openigtlink/repo/Utilities/GitSetup/setup-upstream b/openigtlink/repo/Utilities/GitSetup/setup-upstream new file mode 100755 index 0000000..92ce1da --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/setup-upstream @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2015 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up the local Git repository to use the +# preferred upstream repository URLs. + +# Project configuration instructions: +# +# - Populate adjacent "config" file with: +# upstream.url = Preferred fetch url for upstream remote +# upstream.remote = Preferred name for upstream remote, if not "origin" + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Load the project configuration. +url=$(git config -f config --get upstream.url) && +remote=$(git config -f config --get upstream.remote || + echo 'origin') || +die 'This project is not configured to use a preferred upstream repository.' + +# Get current upstream URLs. +fetchurl=$(git config --get remote."$remote".url || echo '') && +pushurl=$(git config --get remote."$remote".pushurl || echo '') && + +if test "$fetchurl" = "$url"; then + echo 'Remote "'"$remote"'" already uses recommended upstream repository.' + exit 0 +fi + +upstream_recommend=' +We recommended configuring the "'"$remote"'" remote to fetch from upstream at + + '"$url"' +' + +# Tell user about current configuration. +if test -n "$fetchurl"; then + echo 'Remote "'"$remote"'" is currently configured to fetch from + + '"$fetchurl"' +' && + if test -n "$pushurl"; then + echo 'and push to + + '"$pushurl" + fi && + echo "$upstream_recommend" && + if test -n "$pushurl"; then + echo 'and to never push to it directly. +' + fi && + + read -ep 'Reconfigure "'"$remote"'" remote as recommended? [y/N]: ' ans && + if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then + setup=1 + else + setup='' + fi +else + echo 'Remote "'"$remote"'" is not yet configured.' && + echo "$upstream_recommend" && + read -ep 'Configure "'"$remote"'" remote as recommended? [Y/n]: ' ans && + if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then + exit 0 + else + setup=1 + fi +fi && + +# Perform setup if necessary. +if test -n "$setup"; then + if test -z "$fetchurl"; then + git remote add "$remote" "$url" + else + git config remote."$remote".url "$url" && + if old=$(git config --get remote."$remote".pushurl); then + git config --unset remote."$remote".pushurl || + echo 'Warning: failed to unset remote.'"$remote"'.pushurl' + fi + fi && + echo 'Remote "'"$remote"'" is now configured to fetch from + + '"$url"' +' +fi diff --git a/openigtlink/repo/Utilities/GitSetup/setup-user b/openigtlink/repo/Utilities/GitSetup/setup-user new file mode 100755 index 0000000..1af439c --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/setup-user @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to configure Git user info in this repository. + +# Project configuration instructions: NONE + +for (( ; ; )); do + user_name=$(git config user.name || echo '') && + user_email=$(git config user.email || echo '') && + if test -n "$user_name" -a -n "$user_email"; then + echo 'Your commits will record as Author: + + '"$user_name <$user_email>"' +' && + read -ep 'Is the author name and email address above correct? [Y/n] ' correct && + if test "$correct" != "n" -a "$correct" != "N"; then + break + fi + fi && + read -ep 'Enter your full name e.g. "John Doe": ' name && + read -ep 'Enter your email address e.g. "john@gmail.com": ' email && + git config user.name "$name" && + git config user.email "$email" +done diff --git a/openigtlink/repo/Utilities/GitSetup/tips b/openigtlink/repo/Utilities/GitSetup/tips new file mode 100755 index 0000000..784e1ed --- /dev/null +++ b/openigtlink/repo/Utilities/GitSetup/tips @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# This script makes optional suggestions for working with Git. + +# Project configuration instructions: NONE + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +# Suggest color configuration. +if test -z "$(git config --get color.ui)"; then + echo ' +One may enable color output from Git commands with + + git config --global color.ui auto +' +fi + +# Suggest bash completion. +if ! bash -i -c 'echo $PS1' | egrep-q '__git_ps1'; then + echo ' +A dynamic, informative Git shell prompt can be obtained by sourcing +the git bash-completion script in your "~/.bashrc". Set the PS1 +environmental variable as suggested in the comments at the top of the +bash-completion script. You may need to install the bash-completion +package from your distribution to obtain it. +' +fi + +# Suggest merge tool. +if test -z "$(git config --get merge.tool)"; then + echo ' +One may configure Git to load a merge tool with + + git config merge.tool + +See "git help mergetool" for more information. +' +fi diff --git a/openigtlink/repo/Utilities/OpenIGTLinkReleaseScript.sh b/openigtlink/repo/Utilities/OpenIGTLinkReleaseScript.sh new file mode 100755 index 0000000..b7e26ef --- /dev/null +++ b/openigtlink/repo/Utilities/OpenIGTLinkReleaseScript.sh @@ -0,0 +1,177 @@ +#! /usr/bin/env bash + +# Bash script to release a new revision of OpenIGTLink library. +# Run the command without arugment for the usage. + +GITHUB_ORG="tokjun" +GITHUB_REPO="OpenIGTLink.git" +GITHUB_PAGES_REPO="openigtlink.github.com" + +GIT_URL="https://github.com/$GITHUB_ORG/$GITHUB_REPO" +GIT_WEB_URL="https://github.com/$GITHUB_ORG/$GITHUB_PAGES_REPO" + +# +# Major, minor, and patch version numbers +# +MAJ=0 +MIN=0 +PAT=0 + +printUsage() { + echo '' + echo 'Usage: Utilities/OpenIGTLinkReleaseScript.sh ' + echo '' + echo ' RELEASE_TYPE: Type of release' + echo ' major : Major version release' + echo ' minor : Minor version release' + echo ' patch : Patch release' +} + +# +# Extract OpenIGTLink protocol version numbers from the specified CMake file +# +getVersionNumbers() { + + local FILE=$1 + + echo "Examining the existing version numbers in $FILE..." + MAJ=`sed -rn 's/(\s*SET\(OpenIGTLink_VERSION_MAJOR\s+\")([0-9]+)(.*)/\2/p' $FILE` + MIN=`sed -rn 's/(\s*SET\(OpenIGTLink_VERSION_MINOR\s+\")([0-9]+)(.*)/\2/p' $FILE` + PAT=`sed -rn 's/(\s*SET\(OpenIGTLink_VERSION_PATCH\s+\")([0-9]+)(.*)/\2/p' $FILE` + + echo "Old version: $MAJ.$MIN.$PAT" + +} + +# +# Update OpenIGTLink protocol version numbers in the specified CMake file +# +updateVersionNumbers() { + + local FILE=$1 + + echo "New version: $MAJ.$MIN.$PAT" + + cat $FILE \ + | sed -r 's/(\s*SET\(OpenIGTLink_VERSION_MAJOR\s+\")([0-9]+)(.*)/\1'"$MAJ"'\3/g' \ + | sed -r 's/(\s*SET\(OpenIGTLink_VERSION_MINOR\s+\")([0-9]+)(.*)/\1'"$MIN"'\3/g' \ + | sed -r 's/(\s*SET\(OpenIGTLink_VERSION_PATCH\s+\")([0-9]+)(.*)/\1'"$PAT"'\3/g' > $FILE.back + mv $FILE.back $FILE + +} + + +replacePageLine() { + local FILE=$1 + local STRING1=$2 + local STRING2=$3 + cat $FILE \ + | sed -r 's/'"$STRING1"'.*)/'"$STRING2"'/g' > $FILE.back + mv $FILE.back $FILE +} + +updatePage() { + local FILE=$1 + local VERSION=$2 + local STRING=$3 + cat $FILE \ + | sed -r 's/(\[AUTO_VER'"$VERSION"'\]\:\s+\<\>\s+\(.*\).*)/'"$STRING"'/g' > $FILE.back + mv $FILE.back $FILE +} + +# Validate the number of arguments +if [ "$#" -ne 1 ]; then + printUsage + exit 1 +fi + +RELEASE_TYPE=$1 + +getVersionNumbers CMakeLists.txt + +if [ $RELEASE_TYPE == "major" ]; then + MAJ=$(($MAJ+1)) + MIN=0 + PAT=0 +elif [ $RELEASE_TYPE == "minor" ]; then + MIN=$(($MIN+1)) + PAT=0 +elif [ $RELEASE_TYPE == "patch" ]; then + PAT=$(($PAT+1)) +else + echo "ERROR: Invaid release type: $TYPE" + exit 1 +fi + +BRANCH_NAME="release-$MAJ.$MIN" +TAG_NAME="v$MAJ.$MIN.$PAT" +CURRENT_BRANCH=`git rev-parse --abbrev-ref HEAD` + +# Major release must be performed under the master branch +if [ $RELEASE_TYPE == "major" ]]; then + if [ $CURRENT_BRANCH != "master" ]]; then + echo "ERROR: Cannot perform major release from non-master branch." + exit 1 + fi +fi + +updateVersionNumbers CMakeLists.txt + +# If the current branch is not master, switch to the appropriate release branch +if [ $CURRENT_BRANCH != "master" ]]; then + git checkout -B $BRANCH_NAME + CURRENT_BRANCH=$BRANCH_NAME +fi + +# Commit the updated CMakeFileLists.txt to the current branch +git commit -a -m "Update version number in CMakeLists.txt to $MAJ.$MIN.$PAT." +git push $GIT_URL $CURRENT_BRANCH + +# Change to the release branch, if the current branch is master +git checkout -B $BRANCH_NAME + +# Add release tag +git tag -a $TAG_NAME -m "Relase $MAJ.$MIN.$PAT" +git push --tags $GIT_URL $CURRENT_BRANCH + +# Generate Doxygen in a temporary directory +TEMP_DIR=`mktemp -d` +SOURCE_DIR=`pwd` + +cd $TEMP_DIR +mkdir OpenIGTLink-build +cd OpenIGTLink-build +cmake -DBUILD_DOCUMENTATION:BOOL=ON $SOURCE_DIR +make Documentation + +# Download the repository of OpenIGTLink website +cd $TEMP_DIR +git clone $GIT_WEB_URL +cd $GITHUB_PAGES_REPO + +# Copy Doxygen-generated API document +mkdir api/v$MAJ.$MIN +cp -rp $TEMP_DIR/OpenIGTLink-build/Documents/Doxygen/html/* api/v$MAJ.$MIN +git add api/v$MAJ.$MIN/* +git commit -a -m "Add API document for release $MAJ.$MIN.$PAT." + +DATE=`date +"%b %d, %G"` +updatePage releaselog.md 0 " - $DATE : Version $MAJ.$MIN.$PAT is released." + +if [ $RELEASE_TYPE == "patch" ]]; then + replacePageLine spec.md "- [Relase $MAJ.$MIN]" "- [Release $MAJ.$MIN]](https://github.com/openigtlink/OpenIGTLink/blob/release-v$MAJ.$MIN.$PAT/Documents/Protocol/index.md)" + replacePageLine api/index.md "- [Relase $MAJ.$MIN]" "- [Release $MAJ.$MIN]](https://github.com/openigtlink/OpenIGTLink/blob/release-v$MAJ.$MIN.$PAT/Documents/Protocol/index.md)" +fi + +if [ $RELEASE_TYPE == "minor" ]]; then + updatePage spec.md $MAJ " - [Release $MAJ.$MIN](https://github.com/openigtlink/OpenIGTLink/blob/release-v$MAJ.$MIN.$PAT/Documents/Protocol/index.md)" +fi + + +rm -rf $TEMP_DIR + + + + + + diff --git a/openigtlink/repo/Utilities/Scripts/SetupGitAliases.sh b/openigtlink/repo/Utilities/Scripts/SetupGitAliases.sh new file mode 100755 index 0000000..089a60c --- /dev/null +++ b/openigtlink/repo/Utilities/Scripts/SetupGitAliases.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +echo "Setting up useful Git aliases..." && + +# General aliases that could be global +git config alias.pullall '!bash -c "git pull && git submodule update --init"' && +git config alias.prepush 'log --graph --stat origin/master..' && + +# Staging aliases +stage_disabled="VTK no longer uses the topic stage. Please use GitHub." && +git config alias.stage-cmd '!sh -c "echo '"${stage_disabled}"'"' && +git config alias.stage-push '!sh -c "echo '"${stage_disabled}"'"' && +git config alias.stage-branch '!sh -c "echo '"${stage_disabled}"'"' && +git config alias.stage-merge '!sh -c "echo '"${stage_disabled}"'"' && + +# Alias to push the current topic branch to GitHub +git config alias.github-push '!bash Utilities/GitSetup/git-github-push' && + +true diff --git a/openigtlink/repo/Utilities/Scripts/pre-commit b/openigtlink/repo/Utilities/Scripts/pre-commit new file mode 100755 index 0000000..d719058 --- /dev/null +++ b/openigtlink/repo/Utilities/Scripts/pre-commit @@ -0,0 +1,97 @@ +#!/usr/bin/env bash + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +die() { + echo 'pre-commit hook failure' 1>&2 + echo '-----------------------' 1>&2 + echo '' 1>&2 + echo "$@" 1>&2 + exit 1 +} + +ExternalData_stage_linked_content() { + # Identify the hash algorithm used. + case "$file" in + *.md5) algo=MD5 ; base="${file/.md5}" ; validate="^[0-9a-fA-F]{32}$" ;; + *) die "$file: invalid content link (unrecognized extension)" ;; + esac + + # Load and validate the hash stored in the staged blob. + hash=$(git cat-file blob $dst_obj) || hash="" + echo "$hash" | egrep-q "$validate" || + die "$file: invalid content link (does not match '$validate')" + + # Reject simultaneous raw file and content link. + files=$(git ls-files -- "$base") + if test -n "$files"; then + die "$file: content link may not coexist with $files" + fi + + # Find the content referenced by the link. + staged="$(dirname "$file")/.ExternalData_${algo}_${hash}" + stored="${ExternalData_STORE}/$algo/$hash" + ref="refs/data/$algo/$hash" + obj=$(git rev-parse --verify -q "$ref") || obj="" + if test -z "$obj" -a -f "$staged"; then + # Content is staged by the ExternalData module. Store it in Git. + obj=$(git hash-object -w -- "$staged") || + die "$file: git hash-object failed to load $staged" + git update-ref "$ref" "$obj" "" || + die "$file: git update-ref failed to create $ref = $obj" + echo "$file: Added content to Git at $ref" + fi + + # Move staged object to local store if it is in Git. + if test -f "$staged" && test -n "$obj"; then + mkdir -p "${stored%/*}" && + mv "$staged" "$stored" && + rm -f "$staged" && + echo "$file: Added content to local store at $stored" + fi + + # Report destination of content link. + if test -f "$stored"; then + echo "Content link $file -> $stored" + else + echo "Content link $file -> (object not in local store)" + fi +} + +ExternalData_non_content_link() { + # Reject simultaneous raw file and content link. + files=$(git ls-files -- "$file.md5") + if test -n "$files"; then + die "$file: file may not coexist with $files" + fi +} + +#----------------------------------------------------------------------------- + +# Check that developmer setup is up-to-date. +lastSetupForDevelopment=$(git config --get hooks.SetupForDevelopment || echo 0) +eval $(grep '^SetupForDevelopment_VERSION=' "${BASH_SOURCE%/*}/../SetupForDevelopment.sh") +test -n "$SetupForDevelopment_VERSION" || SetupForDevelopment_VERSION=0 +if test $lastSetupForDevelopment -lt $SetupForDevelopment_VERSION; then + die 'Developer setup in this work tree is out of date. Please re-run + + Utilities/SetupForDevelopment.sh +' +fi + +#----------------------------------------------------------------------------- + +# Local ExternalData object repository. +ExternalData_STORE=".ExternalData" + +# Process content links created by/for the CMake ExternalData module. +git diff-index --cached HEAD --diff-filter=AM | +while read src_mode dst_mode src_obj dst_obj status file; do + if echo "$dst_mode $file" | egrep-q '^100644 .*\.(md5)$'; then + ExternalData_stage_linked_content + else + ExternalData_non_content_link + fi +done || exit 1 diff --git a/openigtlink/repo/Utilities/Scripts/prepare-commit-msg b/openigtlink/repo/Utilities/Scripts/prepare-commit-msg new file mode 100755 index 0000000..b0e384d --- /dev/null +++ b/openigtlink/repo/Utilities/Scripts/prepare-commit-msg @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +# First argument is file containing commit message. +commit_msg="$1" + +# Check for our extra instructions. +egrep-q "^# Start the commit message" -- "$commit_msg" && return 0 + +# Insert our extra instructions. +commit_msg_tmp="$commit_msg.$$" +sed 's/^# \(On\|Not currently on any\) branch.*/'\ +'# Start the commit message in "WIP: " to indicate Work In Progress\ +# that is not yet ready to merge.\ +#\ +&/' "$commit_msg" > "$commit_msg_tmp" && +mv "$commit_msg_tmp" "$commit_msg" diff --git a/openigtlink/repo/Utilities/SetupForDevelopment.sh b/openigtlink/repo/Utilities/SetupForDevelopment.sh new file mode 100755 index 0000000..4cb0237 --- /dev/null +++ b/openigtlink/repo/Utilities/SetupForDevelopment.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +cd "${BASH_SOURCE%/*}/.." && +Utilities/GitSetup/setup-user && echo && +Utilities/GitSetup/setup-hooks && echo && +Utilities/Scripts/SetupGitAliases.sh && echo && +(Utilities/GitSetup/setup-upstream || + echo 'Failed to setup origin. Run this again to retry.') && echo && +(Utilities/GitSetup/setup-github|| + echo 'Failed to setup GitHub. Run this again to retry.') && echo && +Utilities/GitSetup/tips + +# Rebase master by default +git config rebase.stat true +git config branch.master.rebase true + +# Record the version of this setup so Scripts/pre-commit can check it. +SetupForDevelopment_VERSION=2 +git config hooks.SetupForDevelopment ${SetupForDevelopment_VERSION} diff --git a/openigtlink/repo/appveyor.yml b/openigtlink/repo/appveyor.yml new file mode 100644 index 0000000..3e4bbd3 --- /dev/null +++ b/openigtlink/repo/appveyor.yml @@ -0,0 +1,76 @@ +version: 1.0.{build} + +os: Visual Studio 2015 + +#Google Test is not build correctly for v120 and v110, but the TestConfigure.h file is a workaround solution for the testing +environment: + matrix: + - Toolset: v140-64 + - Toolset: v140 + - Toolset: v120-64 + - Toolset: v120 + - Toolset: v110 + + +platform: + - x86 + - x64 + - ARM + +configuration: + - Release + + +build: + verbosity: minimal + +branches: + #whitelist + only: + - master + +clone_depth: 1 +skip_tags: true +clone_folder: c:\projects\openigtlink + +before_build: +- ps: | + Write-Output "Configuration: $env:CONFIGURATION" + Write-Output "Platform: $env:PLATFORM" + $generator = switch ($env:TOOLSET) + { + "v110" {"Visual Studio 11 2012"} + "v120" {"Visual Studio 12 2013"} + "v120-64" {"Visual Studio 12 2013 Win64"} + "v140" {"Visual Studio 14 2015"} + "v140-64" {"Visual Studio 14 2015 Win64"} + } + +build_script: +- ps: | + mkdir build -Force | Out-Null + cd build + & cmake -G "$generator" -DOpenIGTLink_PROTOCOL_VERSION_3=ON -DOpenIGTLink_USE_VP9=ON -DOpenIGTLink_SUPERBUILD=OFF .. + if ($LastExitCode -ne 0) { + throw "Exec: $ErrorMessage" + } + & cmake --build . --config $env:CONFIGURATION + if ($LastExitCode -ne 0) { + throw "Exec: $ErrorMessage" + } + & ctest -C $env:CONFIGURATION --output-on-failure + if ($LastExitCode -ne 0) { + throw "Exec: $ErrorMessage" + } + cmake -G "$generator" -DOpenIGTLink_PROTOCOL_VERSION_3=OFF .. + if ($LastExitCode -ne 0) { + throw "Exec: $ErrorMessage" + } + & cmake --build . --config $env:CONFIGURATION + if ($LastExitCode -ne 0) { + throw "Exec: $ErrorMessage" + } + & ctest -C $env:CONFIGURATION --output-on-failure + if ($LastExitCode -ne 0) { + throw "Exec: $ErrorMessage" + } diff --git a/openigtlink/repo/igtlConfigure.h.in b/openigtlink/repo/igtlConfigure.h.in new file mode 100644 index 0000000..180eed6 --- /dev/null +++ b/openigtlink/repo/igtlConfigure.h.in @@ -0,0 +1,56 @@ +/*========================================================================= + + Program: OpenIGTLink Library + Module: $HeadURL: http://svn.na-mic.org/NAMICSandBox/trunk/OpenIGTLink/igtlConfigure.h.in $ + Language: C + Date: $Date: 2010-06-09 16:16:36 -0400 (Wed, 09 Jun 2010) $ + Version: $Revision: 6525 $ + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_CONFIGURE_H +#define __IGTL_CONFIGURE_H + +#cmakedefine OpenIGTLink_PLATFORM_MACOSX +#cmakedefine OpenIGTLink_PLATFORM_LINUX +#cmakedefine OpenIGTLink_PLATFORM_SUNOS +#cmakedefine OpenIGTLink_PLATFORM_WIN32 +#ifdef OpenIGTLink_PLATFORM_WIN32 + #ifndef _WIN32 + #define _WIN32 + #endif + #ifndef WIN32 + #define WIN32 + #endif + #define IGTLCommon_EXPORTS +#endif + +#cmakedefine OpenIGTLink_USE_PTHREADS +#cmakedefine OpenIGTLink_USE_WIN32_THREADS +#cmakedefine OpenIGTLink_USE_SPROC +#cmakedefine OpenIGTLink_HAVE_GETSOCKNAME_WITH_SOCKLEN_T +#cmakedefine OpenIGTLink_HAVE_STRNLEN +#cmakedefine OpenIGTLink_USE_H264 +#cmakedefine OpenIGTLink_USE_VP9 +#cmakedefine OpenIGTLink_USE_X265 +#cmakedefine OpenIGTLink_USE_OpenHEVC +#cmakedefine OpenIGTLink_USE_AV1 +#cmakedefine OpenIGTLink_USE_WEBSOCKET +#cmakedefine OpenIGTLink_ENABLE_VIDEOSTREAMING + +#define OpenIGTLink_PROTOCOL_VERSION_1 1 +#define OpenIGTLink_PROTOCOL_VERSION_2 2 +#define OpenIGTLink_PROTOCOL_VERSION_3 3 +#define OpenIGTLink_PROTOCOL_VERSION @OpenIGTLink_PROTOCOL_VERSION@ +#define OpenIGTLink_HEADER_VERSION @OpenIGTLink_HEADER_VERSION@ +#define OpenIGTLink_SOURCE_ROOTDIR "@OpenIGTLink_SOURCE_DIR@" +#endif /*__IGTL_CONFIGURE_H*/ + + + diff --git a/openigtlink/repo/igtlTypeConfig.h.in b/openigtlink/repo/igtlTypeConfig.h.in new file mode 100644 index 0000000..768dc2f --- /dev/null +++ b/openigtlink/repo/igtlTypeConfig.h.in @@ -0,0 +1,77 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TYPECONFIG_H +#define __IGTL_TYPECONFIG_H + +#cmakedefine CMAKE_SIZEOF_CHAR +#ifdef CMAKE_SIZEOF_CHAR + #define IGTL_SIZEOF_CHAR @CMAKE_SIZEOF_CHAR@ +#endif + +#cmakedefine CMAKE_SIZEOF_INT +#ifdef CMAKE_SIZEOF_INT + #define IGTL_SIZEOF_INT @CMAKE_SIZEOF_INT@ +#endif + +#cmakedefine CMAKE_SIZEOF_SHORT +#ifdef CMAKE_SIZEOF_SHORT + #define IGTL_SIZEOF_SHORT @CMAKE_SIZEOF_SHORT@ +#endif + +#cmakedefine CMAKE_SIZEOF_LONG +#ifdef CMAKE_SIZEOF_LONG + #define IGTL_SIZEOF_LONG @CMAKE_SIZEOF_LONG@ +#endif + +#cmakedefine CMAKE_SIZEOF_FLOAT +#ifdef CMAKE_SIZEOF_FLOAT + #define IGTL_SIZEOF_FLOAT @CMAKE_SIZEOF_FLOAT@ +#endif + +#cmakedefine CMAKE_SIZEOF_DOUBLE +#ifdef CMAKE_SIZEOF_DOUBLE + #define IGTL_SIZEOF_DOUBLE @CMAKE_SIZEOF_DOUBLE@ +#endif + +#cmakedefine CMAKE_SIZEOF_LONG_LONG +#cmakedefine CMAKE_SIZEOF___INT64 +#cmakedefine CMAKE_SIZEOF_INT64_T +#ifdef CMAKE_SIZEOF_LONG_LONG + #define IGTL_TYPE_USE_LONG_LONG 1 + #define IGTL_SIZEOF_LONG_LONG @CMAKE_SIZEOF_LONG_LONG@ +#elif defined(CMAKE_SIZEOF___INT64) + #define IGTL_TYPE_USE___INT64 1 + #define IGTL_SIZEOF___INT64 @CMAKE_SIZEOF___INT64@ +#elif defined(CMAKE_SIZEOF_INT64_T) + #define IGTL_TYPE_USE_INT64_T 1 + #define IGTL_SIZEOF_INT64_T @CMAKE_SIZEOF_INT64_T@ +#endif + +#cmakedefine CMAKE_SIZEOF_VOID_P + +#cmakedefine OpenIGTLink_PLATFORM_WIN32 +#ifdef OpenIGTLink_PLATFORM_WIN32 + #ifndef _WIN32 + #define _WIN32 + #endif + #ifndef WIN32 + #define WIN32 + #endif + #define IGTLCommon_EXPORTS +#endif + +#endif /*__IGTL_TYPECONFIG_H*/ + + + diff --git a/openigtlink/repo/igtl_typeconfig.h.in b/openigtlink/repo/igtl_typeconfig.h.in new file mode 100644 index 0000000..fb8de5f --- /dev/null +++ b/openigtlink/repo/igtl_typeconfig.h.in @@ -0,0 +1,74 @@ +/*========================================================================= + + Program: The OpenIGTLink Library + Language: C + + Copyright (c) Insight Software Consortium. All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#ifndef __IGTL_TYPECONFIG_H +#define __IGTL_TYPECONFIG_H + +#cmakedefine CMAKE_SIZEOF_CHAR +#ifdef CMAKE_SIZEOF_CHAR + #define IGTL_SIZEOF_CHAR @CMAKE_SIZEOF_CHAR@ +#endif + +#cmakedefine CMAKE_SIZEOF_INT +#ifdef CMAKE_SIZEOF_INT + #define IGTL_SIZEOF_INT @CMAKE_SIZEOF_INT@ +#endif + +#cmakedefine CMAKE_SIZEOF_SHORT +#ifdef CMAKE_SIZEOF_SHORT + #define IGTL_SIZEOF_SHORT @CMAKE_SIZEOF_SHORT@ +#endif + +#cmakedefine CMAKE_SIZEOF_LONG +#ifdef CMAKE_SIZEOF_LONG + #define IGTL_SIZEOF_LONG @CMAKE_SIZEOF_LONG@ +#endif + +#cmakedefine CMAKE_SIZEOF_FLOAT +#ifdef CMAKE_SIZEOF_FLOAT + #define IGTL_SIZEOF_FLOAT @CMAKE_SIZEOF_FLOAT@ +#endif + +#cmakedefine CMAKE_SIZEOF_DOUBLE +#ifdef CMAKE_SIZEOF_DOUBLE + #define IGTL_SIZEOF_DOUBLE @CMAKE_SIZEOF_DOUBLE@ +#endif + +#cmakedefine CMAKE_SIZEOF_LONG_LONG +#cmakedefine CMAKE_SIZEOF___INT64 +#cmakedefine CMAKE_SIZEOF_INT64_T +#ifdef CMAKE_SIZEOF_LONG_LONG + #define IGTL_TYPE_USE_LONG_LONG 1 + #define IGTL_SIZEOF_LONG_LONG @CMAKE_SIZEOF_LONG_LONG@ +#elif defined(CMAKE_SIZEOF___INT64) + #define IGTL_TYPE_USE___INT64 1 + #define IGTL_SIZEOF___INT64 @CMAKE_SIZEOF___INT64@ +#elif defined(CMAKE_SIZEOF_INT64_T) + #define IGTL_TYPE_USE_INT64_T 1 + #define IGTL_SIZEOF_INT64_T @CMAKE_SIZEOF_INT64_T@ +#endif + +#cmakedefine CMAKE_SIZEOF_VOID_P + +#cmakedefine OpenIGTLink_PLATFORM_WIN32 +#ifdef OpenIGTLink_PLATFORM_WIN32 + #ifndef _WIN32 + #define _WIN32 + #endif + #ifndef WIN32 + #define WIN32 + #endif + #define IGTLCommon_EXPORTS +#endif + +#endif /*__IGTL_TYPECONFIG_H*/ \ No newline at end of file