New integration with 3Dconnexion devices (#12929)

* New integration with 3Dconnexion devices

* CMake build option hidden for Mac

* Minor fixes, to be squashed to previous commit

* cmake: fix indent and case; to be squashed

* Corrected name case

---------

Co-authored-by: Patryk Skowroński <pskowronski@3dconnexion.com>
Co-authored-by: Chris Hennes <chennes@pioneerlibrarysystem.org>
Co-authored-by: Ladislav Michl <ladis@linux-mips.org>
This commit is contained in:
Patryk Skowroński
2024-04-15 17:43:45 +02:00
committed by GitHub
parent 87839c9f8b
commit 233a61e54e
46 changed files with 9868 additions and 1 deletions

View File

@@ -138,6 +138,11 @@ macro(InitializeFreeCADBuildOptions)
option(BUILD_CLOUD "Build the FreeCAD cloud module" OFF)
option(ENABLE_DEVELOPER_TESTS "Build the FreeCAD unit tests suit" ON)
if(MSVC)
set(FREECAD_3CONNEXION_SUPPORT "NavLib" CACHE STRING "Select version of the 3Dconnexion device integration")
set_property(CACHE FREECAD_3CONNEXION_SUPPORT PROPERTY STRINGS "NavLib" "SpNav")
endif(MSVC)
if(MSVC)
option(BUILD_FEM_NETGEN "Build the FreeCAD FEM module with the NETGEN mesher" ON)
option(FREECAD_USE_PCL "Build the features that use PCL libs" OFF) # 3/5/2021 current LibPack uses non-C++17 FLANN
@@ -157,6 +162,11 @@ macro(InitializeFreeCADBuildOptions)
option(FREECAD_USE_PCL "Build the features that use PCL libs" OFF)
endif(NOT MSVC)
if(FREECAD_3CONNEXION_SUPPORT STREQUAL "NavLib" AND FREECAD_USE_3DCONNEXION)
set(FREECAD_USE_3DCONNEXION_NAVLIB ON)
set(FREECAD_USE_3DCONNEXION OFF)
endif()
# if this is set override some options
if (FREECAD_BUILD_DEBIAN)
set(FREECAD_USE_EXTERNAL_ZIPIOS ON )

View File

@@ -166,7 +166,13 @@ macro(PrintFinalReport)
simple(Coin3D "${COIN3D_VERSION} [${COIN3D_LIBRARIES}] [${COIN3D_INCLUDE_DIRS}]")
simple(pivy ${PIVY_VERSION})
if (WIN32)
#simple(SPNAV "not available yet for your OS") # FREECAD_USE_3DCONNEXION instead...
if (FREECAD_USE_3DCONNEXION)
simple(3Dconnexion "Building 3Dconnexion support with original code")
elseif(FREECAD_USE_3DCONNEXION_NAVLIB)
simple(3Dconnexion "Building 3Dconnexion support with NavLib")
else()
simple(3Dconnexion "Not building 3Dconnexion device support")
endif()
else()
conditional(SPNAV SPNAV_FOUND "not found" "[${SPNAV_LIBRARY}] [${SPNAV_INCLUDE_DIR}]")
endif()

3
src/3rdParty/3Dconnexion/README.txt vendored Normal file
View File

@@ -0,0 +1,3 @@
This directory contains part of the the 3Dconnexion 3DxWare_SDK v4
The full sdk can be obtained from https://3dconnexion.com/software-developer-program/

View File

@@ -0,0 +1,336 @@
#ifndef CInputAction_HPP_INCLUDED
#define CInputAction_HPP_INCLUDED
// <copyright file="CInputAction.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CNavigation3D.hpp 16056 2019-04-10 13:42:31Z mbonk $
//
// </history>
// SpaceMouse
#include <SpaceMouse/CActionInputImpl.hpp>
#include <SpaceMouse/CCategory.hpp>
#include <SpaceMouse/CCommand.hpp>
#include <SpaceMouse/CCommandSet.hpp>
#include <SpaceMouse/CImage.hpp>
#include <SpaceMouse/INavlib.hpp>
// stdlib
#include <memory>
#include <string>
#include <vector>
// navlib
#include <navlib/navlib.h>
#include <navlib/navlib_error.h>
namespace TDx {
namespace SpaceMouse {
/// <summary>
/// Contains types that support 3Dconnexion SpaceMouse input action interface.
/// </summary>
namespace ActionInput {
/// <summary>
/// The base class for 3D navigation implements defaults for the <see cref="IAccessors"/> interface.
/// </summary>
/// <remarks>This class can be used as the base class for the application specific implementation of
/// the accessors.</remarks>
class CActionInput : public Navigation3D::INavlibProperty, protected IActionAccessors {
public:
/// <summary>
/// Initializes a new instance of the <see cref="CActionInput"/> class.
/// </summary>
/// <param name="multiThreaded">Allow multithreading.</param>
/// <remarks>Set multithreaded to true for a windows console application. If the application
/// requires that the callbacks are executed on the main thread, either leave as false, or marshall
/// the callbacks back to the main thread.</remarks>
CActionInput(bool multiThreaded = false)
: m_enabled(false), m_pImpl(CActionInputImpl::CreateInstance(this, multiThreaded)) {
}
#if defined(_MSC_EXTENSIONS)
/// <summary>
/// Gets or sets a value indicating whether the connection to the input device is enabled.
/// </summary>
__declspec(property(get = IsEnabled, put = PutEnable)) bool Enable;
/// <summary>
/// Gets or sets the text to pass to the 3Dconnexion driver to use in Properties Utility.
/// </summary>
/// <remarks>If the connection to the navlib is already open, the connection is closed and
/// reopened.</remarks>
__declspec(property(get = GetProfileHint, put = PutProfileHint)) std::string Profile;
/// <summary>
/// Gets or sets a value representing the active command set.
/// </summary>
/// <exception cref="std::system_error"></exception>
__declspec(property(get = GetActiveCommands, put = PutActiveCommands)) std::string ActiveCommands;
#endif
/// <summary>
/// Gets a value indicating whether action interface is enabled.
/// </summary>
/// <returns>true if enabled, otherwise false.</returns>
bool IsEnabled() const {
return m_enabled;
}
/// <summary>
/// Sets a value indicating whether the action interface is enabled.
/// </summary>
/// <param name="value">true to enable, false to disable.</param>
/// <exception cref="std::invalid_argument">The text for the '3Dconnexion Properties' is
/// empty.</exception>
/// <exception cref="std::system_error">Cannot create a connection to the library.</exception>
void PutEnable(bool value) {
if (m_enabled == value) {
return;
}
if (value) {
m_pImpl->Open(m_profileHint);
m_enabled = true;
} else {
m_pImpl->Close();
m_enabled = false;
}
}
/// <summary>
/// Sets a value indicating whether the action interface is enabled.
/// </summary>
/// <param name="value">true to enable, false to disable.</param>
/// <param name="ec">The <see cref="std::error_code"/> contains the error if something goes
/// wrong.</param>
/// <exception cref="std::invalid_argument">The text for the '3Dconnexion Properties' is
/// empty.</exception>
/// <exception cref="std::system_error">Cannot create a connection to the library.</exception>
void PutEnable(bool value, std::error_code &ec) NOEXCEPT {
try {
PutEnable(value);
}
#if defined(_DEBUG) && defined(TRACE_NAVLIB)
catch (const std::system_error &e) {
ec = e.code();
std::cerr << "system_error exception thrown in EnableNavigation(" << value << ") 0x"
<< std::hex << ec.value() << std::dec << ", " << ec.message() << ", " << e.what()
<< "\n";
} catch (const std::invalid_argument &e) {
ec = std::make_error_code(std::errc::invalid_argument);
std::cerr << "invalid_argument exception thrown in EnableNavigation(" << value << ") 0x"
<< std::hex << ec.value() << std::dec << ", " << ec.message() << ", " << e.what()
<< "\n";
} catch (const std::exception &e) {
ec = std::make_error_code(std::errc::io_error);
std::cerr << "exception thrown in EnableNavigation(" << value << ") 0x" << std::hex
<< ec.value() << std::dec << ", " << ec.message() << ", " << e.what() << "\n";
}
#else
catch (const std::system_error &e) {
ec = e.code();
} catch (const std::invalid_argument &) {
ec = std::make_error_code(std::errc::invalid_argument);
} catch (const std::exception &) {
ec = std::make_error_code(std::errc::io_error);
}
#endif
}
/// <summary>
/// Gets or sets the text to pass to the 3Dconnexion driver to use in Properties Utility.
/// </summary>
/// <remarks>If the connection to the navlib is already open, the connection is closed and
/// reopened.</remarks>
std::string GetProfileHint() const {
return m_profileHint;
}
void PutProfileHint(std::string const &value) {
if (m_profileHint != value) {
m_profileHint = value;
if (IsEnabled()) {
PutEnable(false);
PutEnable(true);
}
}
}
/// <summary>
/// Gets or sets a value representing the active command set.
/// </summary>
/// <exception cref="std::system_error"></exception>
std::string GetActiveCommands() const {
std::string result;
long error = m_pImpl->Read(navlib::commands_activeSet_k, result);
if (error != 0) {
throw std::system_error(make_error_code(error));
}
return result;
}
void PutActiveCommands(const std::string &id) {
long error = m_pImpl->Write(navlib::commands_activeSet_k, id);
if (error != 0) {
throw std::system_error(make_error_code(error));
}
}
/// <summary>
/// Add commands to the sets of commands.
/// </summary>
/// <param name="commands">The <see cref="CCommandTree"/> to add.</param>
/// <exception cref="std::system_error"></exception>
void AddCommands(const CCommandTree &commands) {
const SiActionNodeEx_t *pnode = &commands.GetSiActionNode();
long error = m_pImpl->Write(navlib::commands_tree_k, pnode);
if (error != 0) {
throw std::system_error(make_error_code(error));
}
}
/// <summary>
/// Add a set of commands to the sets of commands.
/// </summary>
/// <param name="commands">The <see cref="CCommandSet"/> to add.</param>
/// <exception cref="std::system_error"></exception>
void AddCommandSet(const CCommandSet &commands) {
AddCommands(commands);
}
/// <summary>
/// Add to the images available to the 3Dconnexion properties utility.
/// </summary>
/// <param name="images">The <see cref="std::vector"/> container containing the images to
/// add.</param>
/// <exception cref="std::system_error"></exception>
template <class T>
void AddImages(const std::vector<T> &images,
typename std::enable_if<std::is_base_of<SiImage_t, T>::value &&
sizeof(T) == sizeof(SiImage_t)>::type * = nullptr) {
long error;
navlib::imagearray_t imagearray = {images.data(), images.size()};
error = m_pImpl->Write(navlib::images_k, imagearray);
if (error != 0) {
throw std::system_error(make_error_code(error));
}
}
/// <summary>
/// Add to the images available to the 3Dconnexion properties utility.
/// </summary>
/// <param name="images">The <see cref="std::vector{T}"/> container containing the images to
/// add.</param>
/// <exception cref="std::system_error"></exception>
template <class T>
void
AddImages(const std::vector<T> &images,
typename std::enable_if<std::is_base_of<TDx::CImage, T>::value>::type * = nullptr) {
std::vector<SiImage_t> siImages;
for (auto const &image : images) {
siImages.push_back(static_cast<SiImage_t>(image));
}
const navlib::imagearray_t imagearray = {siImages.data(), siImages.size()};
long error = m_pImpl->Write(navlib::images_k, imagearray);
if (error != 0) {
throw std::system_error(make_error_code(error));
}
}
/// <summary>
/// Writes the value of a property to the navlib.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// write.</param>
/// <param name="value">The <see cref="navlib::value"/> to write.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
long Write(const std::string &propertyName, const navlib::value &value) override {
return m_pImpl->Write(propertyName, value);
}
/// <summary>
/// Reads the value of a navlib property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="value">The <see cref="navlib::value"/> to read.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
long Read(const std::string &propertyName, navlib::value &value) const override {
return m_pImpl->Read(propertyName, value);
}
/// <summary>
/// Reads the value of a navlib string property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="string">The <see cref="std::string"/> value of the property.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib.</exception>
long Read(const std::string &propertyName, std::string &string) const override {
return m_pImpl->Read(propertyName, string);
}
protected:
// IEvents overrides
/// <summary>
/// Default for SetSettingsChanged.
/// </summary>
/// <param name="count">The change count.</param>
/// <returns>navlib::navlib_errc::function_not_supported error.</returns>
long SetSettingsChanged(long count) override {
(void)count;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
/// <summary>
/// Default for SetKeyPress.
/// </summary>
/// <param name="vkey">The virtual key code of the key pressed.</param>
/// <returns>navlib::navlib_errc::function_not_supported error.</returns>
long SetKeyPress(long vkey) override {
(void)vkey;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
/// <summary>
/// Default for SetKeyRelease.
/// </summary>
/// <param name="vkey">The virtual key code of the key pressed.</param>
/// <returns>navlib::navlib_errc::function_not_supported error.</returns>
long SetKeyRelease(long vkey) override {
(void)vkey;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
protected:
std::error_code make_error_code(long result_code) const {
int errc = result_code & 0xffff;
int facility = result_code >> 16 & 0x7fff;
if (facility == FACILITY_NAVLIB) {
return std::error_code(errc, navlib_category);
}
return std::error_code(errc, std::generic_category());
}
protected:
bool m_enabled;
std::string m_profileHint;
std::shared_ptr<CActionInputImpl> m_pImpl;
};
} // namespace ActionInput
} // namespace SpaceMouse
} // namespace TDx
#endif // CInputAction_HPP_INCLUDED

View File

@@ -0,0 +1,187 @@
#ifndef CActionInputImpl_HPP_INCLUDED
#define CActionInputImpl_HPP_INCLUDED
// <copyright file="CActionInputImpl.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id$
//
// </history>
#include <SpaceMouse/CNavlibInterface.hpp>
#include <SpaceMouse/IActionAccessors.hpp>
#include <SpaceMouse/INavlib.hpp>
// stdlib
#include <map>
#include <memory>
#include <string>
#include <vector>
// navlib
#include <navlib/navlib.h>
#include <navlib/navlib_error.h>
namespace TDx {
namespace SpaceMouse {
namespace ActionInput {
/// <summary>
/// Implementation for creating a shared pointer.
/// </summary>
class CActionInputImpl : public Navigation3D::INavlib,
#if defined(_MSC_VER) && _MSC_VER < 1800
public IActionAccessors,
#else
private IActionAccessors,
#endif
public std::enable_shared_from_this<CActionInputImpl> {
typedef CActionInputImpl this_type;
friend std::shared_ptr<IActionAccessors>
std::static_pointer_cast<IActionAccessors, CActionInputImpl>(
const std::shared_ptr<CActionInputImpl> &) NOEXCEPT;
/// <summary>
/// Make the constructors private to force creation of a shared pointer.
/// </summary>
CActionInputImpl() = default;
CActionInputImpl(IActionAccessors *iclient) : m_iclient(iclient) {
}
public:
/// <summary>
/// Creates a new instance of the CNavlibImpl class.
/// </summary>
/// <param name="iclient">pointer to the instance implementing the IAccessors interface.</param>
/// <param name="multiThreaded">true to use multi-threading, false for single-threaded.</param>
/// <param name="rowMajor">true for row-major ordered matrices, false for column-major.</param>
/// <returns>
/// A <see cref="std::shared_ptr{CNavlibImpl}"/> to the new CNavlibImpl instance.
/// </returns>
static std::shared_ptr<CActionInputImpl> CreateInstance(IActionAccessors *iclient,
bool multiThreaded = false) {
return CreateInstance(iclient, multiThreaded, navlib::none);
}
/// <summary>
/// Creates a new instance of the CNavlibImpl class.
/// </summary>
/// <param name="iclient">pointer to the instance implementing the IAccessors interface.</param>
/// <param name="multiThreaded">true to use multi-threading, false for single-threaded.</param>
/// <param name="options">A combination of the <see cref="navlib::nlOptions_t"/> values.</param>
/// <returns>
/// A <see cref="std::shared_ptr{CNavlibImpl}"/> to the new CNavlibImpl instance.
/// </returns>
static std::shared_ptr<CActionInputImpl>
CreateInstance(IActionAccessors *iclient, bool multiThreaded, navlib::nlOptions_t options) {
if (iclient == nullptr) {
throw std::logic_error("The accessor interface is null");
}
// So that std::make_shared<> can be used with the private constructor.
struct make_shared_enabler : public this_type {
make_shared_enabler(IActionAccessors *iclient) : this_type(iclient) {
}
};
std::shared_ptr<CActionInputImpl> result = std::make_shared<make_shared_enabler>(iclient);
result->m_pNavlib =
std::unique_ptr<Navigation3D::CNavlibInterface>(new Navigation3D::CNavlibInterface(
std::static_pointer_cast<IActionAccessors>(result), multiThreaded, options));
return result;
}
// INavlib implementation
/// <summary>
/// Close the connection to the 3D navigation library.
/// </summary>
void Close() override {
m_pNavlib->Close();
}
/// <summary>
/// Opens a connection to the 3D navigation library.
/// </summary>
void Open() override {
m_pNavlib->Open();
}
/// <summary>
/// Opens a connection to the 3D navigation library
/// </summary>
/// <param name="profileName">The name of the 3Dconnexion profile to use.</param>
/// <exception cref="std::system_error">The connection to the library is already open.</exception>
/// <exception cref="std::system_error">Cannot create a connection to the library.</exception>
/// <exception cref="std::invalid_argument">The name of the profile is empty.</exception>
void Open(std::string profileName) override {
m_pNavlib->Open(std::move(profileName));
}
/// <summary>
/// Writes the value of a property to the navlib.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// write.</param>
/// <param name="value">The <see cref="navlib::value"/> to write.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
long Write(const std::string &propertyName, const navlib::value &value) override {
return m_pNavlib->Write(propertyName, value);
}
/// <summary>
/// Reads the value of a navlib property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="value">The <see cref="navlib::value"/> to read.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
long Read(const std::string &propertyName, navlib::value &value) const override {
return m_pNavlib->Read(propertyName, value);
}
/// <summary>
/// Reads the value of a navlib string property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="string">The <see cref="std::string"/> value of the property.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib.</exception>
long Read(const std::string &propertyName, std::string &string) const override {
return m_pNavlib->Read(propertyName, string);
}
private:
// IEvents overrides
long SetActiveCommand(std::string commandId) override {
return m_iclient->SetActiveCommand(commandId);
}
long SetSettingsChanged(long change) override {
return m_iclient->SetSettingsChanged(change);
}
long SetKeyPress(long vkey) override {
return m_iclient->SetKeyPress(vkey);
}
long SetKeyRelease(long vkey) override {
return m_iclient->SetKeyRelease(vkey);
}
private:
IActionAccessors *m_iclient = nullptr;
std::unique_ptr<Navigation3D::CNavlibInterface> m_pNavlib;
};
} // namespace ActionInput
} // namespace SpaceMouse
} // namespace TDx
#endif // CNavlibImpl_HPP_INCLUDED

View File

@@ -0,0 +1,353 @@
#ifndef CActionNode_HPP_INCLUDED
#define CActionNode_HPP_INCLUDED
// <copyright file="CActionNode.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CActionNode.hpp 16051 2019-04-09 11:29:53Z mbonk $
//
// </history>
// navlib
#include <navlib/navlib_defines.h>
// 3dxware
#include <siappcmd_types.h>
// stdlib
#include <memory>
#include <string>
#include <vector>
#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
/// <summary>
/// The TDx namespace provides support for the types used in the 3DxWare interface.
/// </summary>
namespace TDx {
/// <summary>
/// Wrapper class for the <see cref="SiActionNodeEx_t"/> structure.
/// </summary>
class CActionNode : private SiActionNodeEx_t {
typedef SiActionNodeEx_t base_type;
public:
/// <summary>
/// Initializes a new instance of the <see cref="CActionNode"/> class.
/// </summary>
#if defined(_MSC_VER) && _MSC_VER < 1800
CActionNode() : base_type() {
base_type::size = sizeof(base_type);
}
#else
CActionNode()
: base_type({sizeof(base_type), SI_ACTIONSET_NODE, nullptr, nullptr,
nullptr, nullptr, nullptr}) {
}
#endif
/// <summary>
/// Constructor a <see cref="CActionNode"/> with a label.
/// </summary>
/// <param name="nodeId">The unique node identifier.</param>
/// <param name="text">Text to display to the user in the user interface.</param>
/// <param name="nodeType">The <see cref="SiActionNodeType_t"/> of the node.</param>
explicit CActionNode(std::string nodeId, std::string text, SiActionNodeType_t nodeType)
#if defined(_MSC_VER) && _MSC_VER < 1800
: base_type(), m_id(std::move(nodeId)), m_label(std::move(text)) {
base_type::size = sizeof(base_type);
base_type::type = nodeType;
#else
: base_type({sizeof(base_type), nodeType, nullptr, nullptr, nullptr, nullptr, nullptr}),
m_id(std::move(nodeId)), m_label(std::move(text)) {
#endif
if (!m_id.empty()) {
base_type::id = m_id.c_str();
}
if (!m_label.empty()) {
base_type::label = m_label.c_str();
}
}
/// <summary>
/// Constructor a <see cref="CActionNode"/> with a label and a description for a tooltip.
/// </summary>
/// <param name="nodeId">The unique node identifier</param>
/// <param name="text">Text to display to the user in the user interface.</param>
/// <param name="tooltip">Text to display in a tooltip.</param>
/// <param name="nodeType">The <see cref="SiActionNodeType_t"/> of the node.</param>
explicit CActionNode(std::string nodeId, std::string text, std::string tooltip,
SiActionNodeType_t nodeType)
#if defined(_MSC_VER) && _MSC_VER < 1800
: base_type(), m_id(std::move(nodeId)), m_label(std::move(text)),
m_description(std::move(tooltip)) {
base_type::size = sizeof(base_type);
base_type::type = nodeType;
#else
: base_type({sizeof(base_type), nodeType, nullptr, nullptr, nullptr, nullptr, nullptr}),
m_id(std::move(nodeId)), m_label(std::move(text)),
m_description(std::move(tooltip)) {
#endif
if (!m_id.empty()) {
base_type::id = m_id.c_str();
}
if (!m_label.empty()) {
base_type::label = m_label.c_str();
}
if (!m_description.empty()) {
base_type::description = m_description.c_str();
}
}
virtual ~CActionNode() {
Tidy();
}
/// <summary>
/// Move constructor
/// </summary>
/// <param name="other">The <see cref="CActionNode"/> to use for construction.</param>
CActionNode(CActionNode &&other) NOEXCEPT
: base_type(other), m_id(std::move(other.m_id)), m_label(std::move(other.m_label)),
m_description(std::move(other.m_description)) {
base_type zero = {sizeof(base_type), SI_ACTIONSET_NODE, nullptr, nullptr, nullptr,
nullptr, nullptr};
static_cast<base_type &>(other) = zero;
base_type::id = !m_id.empty() ? m_id.c_str() : nullptr;
base_type::label = !m_label.empty() ? m_label.c_str() : nullptr;
base_type::description = !m_description.empty() ? m_description.c_str() : nullptr;
}
/// <summary>
/// Move assignment
/// </summary>
/// <param name="other">The <see cref="CActionNode"/> to use for construction.</param>
CActionNode &operator=(CActionNode &&other) NOEXCEPT {
static_cast<base_type &>(*this) = static_cast<base_type>(other);
m_id = std::move(other.m_id);
m_label = std::move(other.m_label);
m_description = std::move(other.m_description);
base_type zero = {sizeof(base_type), SI_ACTIONSET_NODE, nullptr, nullptr,
nullptr, nullptr, nullptr};
static_cast<base_type &>(other) = zero;
base_type::id = !m_id.empty() ? m_id.c_str() : nullptr;
base_type::label = !m_label.empty() ? m_label.c_str() : nullptr;
base_type::description = !m_description.empty() ? m_description.c_str() : nullptr;
return *this;
}
#if !defined(_MSC_VER) || _MSC_VER > 1700
CActionNode(const CActionNode &) = delete;
CActionNode &operator=(const CActionNode &) = delete;
#else
private:
CActionNode(const CActionNode &);
CActionNode &operator=(const CActionNode &);
#endif
public:
/// <summary>
/// Set the <see cref="SiActionNodeEx_t"/> child node.
/// </summary>
/// <param name="child">The child node.</param>
template <typename Ty_> void PutChild(Ty_ &&child) {
if (base_type::children) {
delete static_cast<CActionNode *>(base_type::children);
}
base_type::children = child.release();
}
/// <summary>
/// Set the next <see cref="SiActionNodeEx_t"/> node.
/// </summary>
/// <param name="next_">The next node.</param>
template <typename Ty_> void PutNext(Ty_ &&next_) {
if (base_type::next) {
delete static_cast<CActionNode *>(base_type::next);
}
base_type::next = next_.release();
}
#if defined(_MSC_EXTENSIONS)
/// <summary>
/// The <see cref="SiActionNodeEx_t"/> properties.
/// </summary>
__declspec(property(get = GetId, put = PutId)) std::string Id;
__declspec(property(get = GetDescription, put = PutDescription)) std::string Description;
__declspec(property(get = GetLabel, put = PutLabel)) std::string Label;
__declspec(property(get = GetType, put = PutType)) SiActionNodeType_t Type;
#endif
void PutType(const SiActionNodeType_t value) {
base_type::type = value;
}
void PutId(std::string value) {
m_id = std::move(value);
base_type::id = m_id.c_str();
}
void PutLabel(std::string value) {
m_label = std::move(value);
base_type::label = m_label.c_str();
}
void PutDescription(std::string value) {
m_description = std::move(value);
base_type::description = m_description.c_str();
}
CActionNode *DetachChild() {
CActionNode *p = static_cast<CActionNode *>(base_type::children);
base_type::children = nullptr;
return p;
}
CActionNode *DetachNext() {
CActionNode *p = static_cast<CActionNode *>(base_type::next);
base_type::next = nullptr;
return p;
}
CActionNode *GetChild() {
return static_cast<CActionNode *>(base_type::children);
}
const CActionNode *GetChild() const {
return static_cast<const CActionNode *>(base_type::children);
}
CActionNode *GetNext() {
return static_cast<CActionNode *>(base_type::next);
}
const CActionNode *GetNext() const {
return static_cast<const CActionNode *>(base_type::next);
}
std::string GetId() const {
return m_id;
}
std::string GetLabel() const {
return m_label;
}
std::string GetDescription() const {
return m_description;
}
SiActionNodeType_t GetType() const {
return base_type::type;
}
const SiActionNodeEx_t &GetSiActionNode() const {
return *this;
}
/// <summary>
/// Clears this and the linked nodes.
/// </summary>
void clear() {
base_type::id = base_type::label = base_type::description = nullptr;
m_id.clear();
m_label.clear();
m_description.clear();
Tidy();
}
/// <summary>
/// Returns true if the node is empty and has no linked nodes
/// </summary>
/// <returns></returns>
bool empty() const {
return m_id.empty() && base_type::next == nullptr && base_type::children == nullptr &&
m_label.empty() && m_description.empty();
}
private:
void AssignBaseDataValues() {
base_type::id = !m_id.empty() ? m_id.c_str() : nullptr;
base_type::label = !m_label.empty() ? m_label.c_str() : nullptr;
base_type::description = !m_description.empty() ? m_description.c_str() : nullptr;
}
void Tidy() {
if (base_type::next == nullptr && base_type::children == nullptr) {
return;
}
CActionNode *nextNode = static_cast<CActionNode *>(base_type::next);
CActionNode *childrenNodes = static_cast<CActionNode *>(base_type::children);
base_type::next = nullptr;
base_type::children = nullptr;
// Fix to avoid a stack overflow when destructing large lists
// This traverses to the end of the list and deletes from there
std::vector<CActionNode *> vnodes;
if (nextNode) {
vnodes.push_back(nextNode);
}
if (childrenNodes) {
vnodes.push_back(childrenNodes);
}
size_t i;
for (i = 0; i < vnodes.size(); ++i) {
nextNode = static_cast<CActionNode *>(vnodes[i]->next);
childrenNodes = static_cast<CActionNode *>(vnodes[i]->children);
if (nextNode) {
vnodes[i]->next = nullptr;
vnodes.push_back(nextNode);
}
if (childrenNodes) {
vnodes[i]->children = nullptr;
vnodes.push_back(childrenNodes);
}
}
std::vector<CActionNode *>::reverse_iterator riter;
for (riter = vnodes.rbegin(); riter != vnodes.rend(); ++riter) {
delete (*riter);
}
}
private:
std::string m_id;
std::string m_label;
std::string m_description;
};
} // namespace TDx
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
#endif // CActionNode_HPP_INCLUDED

View File

@@ -0,0 +1,64 @@
#ifndef CCategory_HPP_INCLUDED
#define CCategory_HPP_INCLUDED
// <copyright file="CCategory.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CCategory.hpp 16056 2019-04-10 13:42:31Z mbonk $
//
// </history>
#include <SpaceMouse/CCommandTreeNode.hpp>
#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#endif
namespace TDx {
/// <summary>
/// Contains types used for programming the SpaceMouse.
/// </summary>
namespace SpaceMouse {
/// <summary>
/// The helper class implements the <see cref="SiActionNodeType_t::SI_CATEGORY_NODE"/> node type.
/// </summary>
class CCategory : public CCommandTreeNode {
typedef CCommandTreeNode base_type;
public:
CCategory() {
}
explicit CCategory(std::string id, std::string name)
: base_type(std::move(id), std::move(name), SiActionNodeType_t::SI_CATEGORY_NODE) {
}
#if defined(_MSC_VER) && _MSC_VER < 1900
CCategory(CCategory &&other) : base_type(std::forward<base_type>(other)) {
}
CCategory &operator=(CCategory &&other) {
base_type::operator=(std::forward<base_type>(other));
return *this;
}
#else
CCategory(CCategory &&) = default;
CCategory &operator=(CCategory &&) = default;
#endif
};
} // namespace SpaceMouse
} // namespace TDx
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
#endif // CCategory_HPP_INCLUDED

View File

@@ -0,0 +1,64 @@
#ifndef CCommand_HPP_INCLUDED
#define CCommand_HPP_INCLUDED
// <copyright file="CCommand.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CCommand.hpp 16056 2019-04-10 13:42:31Z mbonk $
//
// </history>
#include <SpaceMouse/CCommandTreeNode.hpp>
#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#endif
namespace TDx {
namespace SpaceMouse {
/// <summary>
/// The <see cref="CCommand"/> class implements the application command node.
/// </summary>
class CCommand : public CCommandTreeNode {
typedef CCommandTreeNode base_type;
public:
CCommand() {
}
explicit CCommand(std::string id, std::string name, std::string description)
: base_type(std::move(id), std::move(name), std::move(description),
SiActionNodeType_t::SI_ACTION_NODE) {
}
explicit CCommand(std::string id, std::string name)
: base_type(std::move(id), std::move(name), SiActionNodeType_t::SI_ACTION_NODE) {
}
#if defined(_MSC_VER) && _MSC_VER < 1900
CCommand(CCommand &&other) : base_type(std::forward<base_type>(other)) {
}
CCommand &operator=(CCommand &&other) {
base_type::operator=(std::forward<base_type>(other));
return *this;
}
#else
CCommand(CCommand &&) = default;
CCommand &operator=(CCommand &&) = default;
#endif
};
} // namespace SpaceMouse
} // namespace TDx
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
#endif // CCommand_HPP_INCLUDED

View File

@@ -0,0 +1,60 @@
#ifndef CCommandSet_HPP_INCLUDED
#define CCommandSet_HPP_INCLUDED
// <copyright file="CCommandSet.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CCommandSet.hpp 16056 2019-04-10 13:42:31Z mbonk $
//
// </history>
#include <SpaceMouse/CCommandTreeNode.hpp>
#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#endif
namespace TDx {
namespace SpaceMouse {
/// <summary>
/// The helper class implements the <see cref="SiActionNodeType_t::SI_ACTIONSET_NODE"/> node type.
/// </summary>
class CCommandSet : public CCommandTreeNode {
typedef CCommandTreeNode base_type;
public:
CCommandSet() {
}
explicit CCommandSet(std::string id, std::string name)
: base_type(std::move(id), std::move(name), SiActionNodeType_t::SI_ACTIONSET_NODE) {
}
#if defined(_MSC_VER) && _MSC_VER < 1900
CCommandSet(CCommandSet &&other) : base_type(std::forward<base_type>(other)) {
}
CCommandSet &operator=(CCommandSet &&other) {
base_type::operator=(std::forward<base_type>(other));
return *this;
}
#else
CCommandSet(CCommandSet &&) = default;
CCommandSet &operator=(CCommandSet &&) = default;
#endif
};
} // namespace SpaceMouse
} // namespace TDx
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
#endif // CCommandSet_HPP_INCLUDED

View File

@@ -0,0 +1,288 @@
#ifndef CCommandTreeNode_HPP_INCLUDED
#define CCommandTreeNode_HPP_INCLUDED
// <copyright file="CCommandTreeNode.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CCommandTreeNode.hpp 16056 2019-04-10 13:42:31Z mbonk $
//
// </history>
#include <SpaceMouse/CActionNode.hpp>
// stdlib
#include <exception>
#include <iterator>
#include <memory>
#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#endif
namespace TDx {
template <typename Ty_, bool doubled_linked = false> class raw_linkedlist_iterator {
public:
typedef std::input_iterator_tag iterator_category;
typedef Ty_ value_type;
typedef ptrdiff_t difference_type;
typedef Ty_ *pointer;
typedef Ty_ &reference;
public:
raw_linkedlist_iterator(Ty_ *ptr_ = nullptr) : MyPtr_(ptr_) {
}
raw_linkedlist_iterator(const raw_linkedlist_iterator<Ty_> &_other) : MyPtr_(_other.MyPtr_) {
}
raw_linkedlist_iterator<Ty_> &operator=(const raw_linkedlist_iterator<Ty_> &_other) {
MyPtr_ = _other.MyPtr_;
return *this;
}
raw_linkedlist_iterator<Ty_> &operator=(Ty_ *ptr_) {
MyPtr_ = ptr_;
return *this;
}
// accessors
Ty_ &operator*() {
return *MyPtr_;
}
Ty_ const &operator*() const {
return *MyPtr_;
}
Ty_ *operator->() {
return MyPtr_;
}
Ty_ const *operator->() const {
return MyPtr_;
}
raw_linkedlist_iterator<Ty_> &operator++() {
if (MyPtr_)
MyPtr_ = MyPtr_->GetNext();
return *this;
}
raw_linkedlist_iterator<Ty_> &operator--() {
if (doubled_linked) {
if (MyPtr_)
MyPtr_ = MyPtr_->GetPrevious();
} else {
throw std::logic_error("Not Supported");
}
return *this;
}
bool operator<(raw_linkedlist_iterator<Ty_> const &rhs) const {
if (!MyPtr_)
return false;
else if (!rhs.MyPtr_)
return true;
return (MyPtr_ < rhs.MyPtr_);
}
bool operator<=(raw_linkedlist_iterator<Ty_> const &rhs) const {
if (MyPtr_ == rhs.MyPtr_)
return true;
return operator<(rhs);
}
bool operator>(raw_linkedlist_iterator<Ty_> const &rhs) const {
return !operator<=(rhs);
}
bool operator>=(raw_linkedlist_iterator<Ty_> const &rhs) const {
return !operator<(rhs);
}
operator bool() const {
return MyPtr_ != nullptr;
}
protected:
Ty_ *MyPtr_;
};
/// <summary>
/// Tree container for CActionNode.
/// </summary>
/// <remarks>The tree is implemented as a singularly linked list.</remarks>
class CCommandTree : public CActionNode {
public:
typedef CActionNode base_type;
typedef CActionNode const const_base_type;
typedef CActionNode const &const_base_ref_type;
typedef CActionNode const *const_base_ptr_type;
typedef CCommandTree self_type;
public:
typedef CCommandTree &reference;
typedef CCommandTree const &const_reference;
typedef raw_linkedlist_iterator<base_type> iterator;
typedef raw_linkedlist_iterator<const base_type> const_iterator;
CCommandTree() {
}
explicit CCommandTree(std::string id, std::string label, std::string description,
SiActionNodeType_t type)
: base_type(std::move(id), std::move(label), std::move(description), type) {
}
explicit CCommandTree(std::string id, std::string label, SiActionNodeType_t type)
: base_type(std::move(id), std::move(label), type) {
}
#if defined(_MSC_VER) && _MSC_VER < 1900
CCommandTree(CCommandTree &&other) : base_type(std::forward<base_type>(other)) {
}
CCommandTree &operator=(CCommandTree &&other) {
base_type::operator=(std::forward<base_type>(other));
return *this;
}
private:
CCommandTree(const CCommandTree &) {
}
const CCommandTree &operator=(const CCommandTree &){};
#else
CCommandTree(CCommandTree &&) = default;
CCommandTree &operator=(CCommandTree &&) = default;
// No copying
CCommandTree(const CCommandTree &) = delete;
const CCommandTree &operator=(const CCommandTree &) = delete;
#endif // defined(_MSC_VER) && _MSC_VER<1900
public:
void push_back(base_type &&value) {
#if (defined(_MSC_VER) && _MSC_VER < 1900)
std::unique_ptr<base_type> node(new base_type(std::forward<base_type>(value)));
#else
std::unique_ptr<base_type> node = std::make_unique<base_type>(std::forward<base_type>(value));
#endif
push_back(std::move(node));
}
template <class T>
void
push_back(std::unique_ptr<T> &&value,
typename std::enable_if<std::is_base_of<CActionNode, T>::value>::type * = nullptr) {
base_type *last = this->GetChild();
if (!last) {
PutChild(std::unique_ptr<base_type>(static_cast<base_type *>(value.release())));
} else {
while (last->GetNext() != nullptr) {
last = last->GetNext();
}
last->PutNext(std::unique_ptr<base_type>(static_cast<base_type *>(value.release())));
}
}
void push_front(base_type &&value) {
#if (defined(_MSC_VER) && _MSC_VER < 1900)
std::unique_ptr<base_type> node(new base_type(std::forward<base_type>(value)));
#else
std::unique_ptr<base_type> node = std::make_unique<base_type>(std::forward<base_type>(value));
#endif
push_front(std::move(node));
}
void push_front(std::unique_ptr<base_type> &&value) {
value->PutNext(std::unique_ptr<base_type>(DetachChild()));
PutChild(std::forward<std::unique_ptr<base_type>>(value));
}
const_reference back() const {
const base_type *last = this->GetChild();
if (!last) {
return *this;
}
while (last->GetNext() != nullptr) {
last = last->GetNext();
}
return *static_cast<const self_type *>(last);
}
reference back() {
base_type *last = this->GetChild();
if (!last) {
return *this;
}
while (last->GetNext() != nullptr) {
last = last->GetNext();
}
return *static_cast<self_type *>(last);
}
void clear() {
base_type *head = this->DetachChild();
if (head) {
head->clear();
}
}
const_reference front() const {
const base_type *head = this->GetChild();
if (!head) {
return *this;
}
return *static_cast<const self_type *>(head);
}
reference front() {
base_type *head = this->GetChild();
if (!head) {
return *this;
}
return *static_cast<self_type *>(head);
}
const_iterator begin() const {
if (empty()) {
return end();
}
return const_iterator(this->GetChild());
}
iterator begin() {
if (empty()) {
return end();
}
return iterator(this->GetChild());
}
bool empty() const {
return (this->GetChild() == nullptr);
}
const_iterator end() const {
return nullptr;
}
iterator end() {
return nullptr;
}
};
typedef CCommandTree CCommandTreeNode;
} // namespace TDx
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
#endif // CCommandTreeNode_HPP_INCLUDED

View File

@@ -0,0 +1,102 @@
#ifndef CCookieCollection_HPP_INCLUDED
#define CCookieCollection_HPP_INCLUDED
// <copyright file="CCookieCollection.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CCookieCollection.hpp 16047 2019-04-05 12:51:24Z mbonk $
//
// </history>
#include <navlib/navlib_types.h>
// stdlib
#include <map>
#include <memory>
#include <stdexcept>
#if (!defined(_MSC_VER) || (_MSC_VER > 1600))
#include <mutex>
#else
#pragma warning(disable : 4482) // non-standard
#include <boost/thread/lock_guard.hpp>
#include <boost/thread/mutex.hpp>
namespace std {
using boost::lock_guard;
using boost::mutex;
using boost::unique_lock;
} // namespace std
#endif
namespace TDx {
namespace SpaceMouse {
/// <summary>
/// The class maps a cookie to a shared_ptr<typeparam name="T"></typeparam>.
/// </summary>
template <class T>
class CCookieCollection : protected std::map<navlib::param_t, std::shared_ptr<T>> {
typedef std::map<navlib::param_t, std::shared_ptr<T>> map_t;
public:
typedef typename map_t::size_type size_type;
/// <summary>
/// Gets the <see cref="std::shared_ptr{T}"/> corresponding to the passed in cookie.
/// </summary>
/// <param name="cookie">The <see cref="navlib::param_t"/> to search for.</param>
/// <returns>The <see cref="std::shared_ptr{T}"/>.</returns>
/// <exception cref="std::out_of_range">If the cookie does not exist.</exception>
std::shared_ptr<T> at(const navlib::param_t &cookie) {
std::lock_guard<std::mutex> guard(m_mutex);
typename map_t::iterator iter = map_t::find(cookie);
if (iter != map_t::end()) {
return iter->second;
}
throw std::out_of_range("Cookie does not exist in the Collection");
}
/// <summary>
/// Removes the elements that match the cookie.
/// </summary>
/// <param name="cookie">The cookie entry to remove.</param>
/// <returns>The number of elements that have been removed.</returns>
size_type erase(const navlib::param_t &cookie) {
std::lock_guard<std::mutex> guard(m_mutex);
return map_t::erase(cookie);
}
/// <summary>
/// Inserts a <see cref="std::shared_ptr{T}"/> and returns a cookie that is needed to retrieve it later.
/// </summary>
/// <param name="sp">The <see cref="std::shared_ptr{T}"/> to insert.</param>
/// <returns>A cookie that is needed to find the shared pointer.</returns>
navlib::param_t insert(std::shared_ptr<T> sp) {
navlib::param_t param = 0;
if (sp) {
std::lock_guard<std::mutex> guard(m_mutex);
do {
using namespace std::chrono;
param = static_cast<navlib::param_t>(
duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count());
} while (map_t::find(param) != map_t::end());
(*this)[param] = std::move(sp);
}
return param;
}
protected:
/// <summary>
/// When changing the contents of the collection always use the mutex as a guard
/// </summary>
std::mutex m_mutex;
};
} // namespace SpaceMouse
} // namespace TDx
#endif // CCookieCollection_HPP_INCLUDED

View File

@@ -0,0 +1,132 @@
#ifndef CHitTest_HPP_INCLUDED
#define CHitTest_HPP_INCLUDED
// <copyright file="CHitTest.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CHitTest.hpp 16056 2019-04-10 13:42:31Z mbonk $
//
// 01/20/14 MSB Initial design
// </history>
// 3dxware
#include <navlib/navlib_types.h>
namespace TDx {
namespace SpaceMouse {
/// <summary>
/// Class can be used to hold the hit-test properties.
/// </summary>
template <class point_ = navlib::point_t, class vector_ = navlib::vector_t> class CHitTest {
public:
typedef point_ point_type;
typedef vector_ vector_type;
public:
/// <summary>
/// Creates a new instance of the <see cref="CHitTest"/> class.
/// </summary>
CHitTest() : m_aperture(1), m_dirty(false), m_selectionOnly(false) {
}
#if defined(_MSC_EXTENSIONS)
/// <summary>
/// Property accessors
/// </summary>
__declspec(property(get = GetDirection, put = PutDirection)) vector_type Direction;
__declspec(property(get = GetLookFrom, put = PutLookFrom)) point_type LookFrom;
__declspec(property(get = GetLookingAt, put = PutLookingAt)) point_type LookingAt;
__declspec(property(get = GetIsDirty, put = PutIsDirty)) bool IsDirty;
__declspec(property(get = GetAperture, put = PutAperture)) double Aperture;
__declspec(property(get = GetSelectionOnly, put = PutSelectionOnly)) bool SelectionOnly;
#endif
/// <summary>
/// Gets or sets the ray direction.
/// </summary>
void PutDirection(vector_type value) {
if (!m_dirty) {
m_dirty = static_cast<bool>(m_direction != value);
}
m_direction = std::move(value);
}
vector_type GetDirection() const {
return m_direction;
}
/// <summary>
/// Gets or sets the ray origin.
/// </summary>
void PutLookFrom(point_type value) {
if (!m_dirty) {
m_dirty = static_cast<bool>(m_lookFrom != value);
}
m_lookFrom = std::move(value);
}
const point_type GetLookFrom() const {
return m_lookFrom;
}
/// <summary>
/// Gets or sets the ray hit test result location.
/// </summary>
void PutLookingAt(point_type value) {
m_lookingAt = std::move(value);
m_dirty = false;
}
const point_type GetLookingAt() const {
return m_lookingAt;
}
/// <summary>
/// Gets or sets a value indicating if a the parameters have changed since the last hit calculation.
/// </summary>
void PutIsDirty(bool value) {
m_dirty = value;
}
bool GetIsDirty() const {
return m_dirty;
}
/// <summary>
/// Gets or sets the ray diameter / aperture on the near clipping plane.
/// </summary>
void PutAperture(double value) {
m_dirty = (m_aperture != value);
m_aperture = value;
}
double GetAperture() const {
return m_aperture;
}
/// <summary>
/// Gets or sets a value indicating whether the hit-testing is limited to the selection set.
/// </summary>
void PutSelectionOnly(bool value) {
m_selectionOnly = value;
}
bool GetSelectionOnly() const {
return m_selectionOnly;
}
private:
double m_aperture;
mutable bool m_dirty;
vector_type m_direction;
point_type m_lookFrom;
mutable point_type m_lookingAt;
bool m_selectionOnly;
};
} // namespace SpaceMouse
} // namespace TDx
#endif // CHitTest_HPP_INCLUDED

View File

@@ -0,0 +1,322 @@
#ifndef CImage_HPP_INCLUDED
#define CImage_HPP_INCLUDED
// <copyright file="CImage.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CImage.hpp 16056 2019-04-10 13:42:31Z mbonk $
//
// </history>
// stdlib
#include <string>
#include <sstream>
// 3dxware
#include <siappcmd_types.h>
#if defined(_MSC_VER) && _MSC_VER<1800
// #pragma warning(1 : 4519) // convert error C4519 'default template arguments are only allowed on a class template' to warning
#pragma warning(disable : 4519) // disable error C4519
#if _MSC_VER < 1700
#pragma warning(disable : 4482) // warning C4482: nonstandard extension used
#endif
#endif
#ifdef __APPLE__
#define IS_INTRESOURCE_(x) false
#elif !defined(IS_INTRESOURCE_)
#define IS_INTRESOURCE_(_r) (((reinterpret_cast<intptr_t>(_r)) >> 16) == 0)
#endif
namespace TDx {
/// <summary>
/// A class that represents the SiImage_t structure.
/// </summary>
class CImage {
public:
/// <summary>
/// Initializes a new instance of the <see cref="CImage"/> class.
/// </summary>
CImage() : m_type(SiImageType_t::e_none), m_index(0) {
}
/// <summary>
/// Initializes a new instance of the <see cref="CImage"/> class from a <see cref="SiImage_t"/>.
/// </summary>
/// <param name="image"></param>
explicit CImage(const SiImage_t &siImage) : m_id(siImage.id), m_type(siImage.type) {
if (siImage.size != sizeof(SiImage_t)) {
throw std::invalid_argument("Invalid SiImage_t structure.");
}
switch (m_type) {
case SiImageType_t::e_image_file:
m_source = siImage.file.file_name;
m_index = siImage.file.index;
break;
case SiImageType_t::e_resource_file:
m_source = siImage.resource.file_name;
m_resourceId = siImage.resource.id;
m_resourceType = siImage.resource.type;
m_index = siImage.resource.index;
break;
case SiImageType_t::e_image:
m_source.assign(reinterpret_cast<const char *>(siImage.image.data), siImage.image.size);
m_index = siImage.image.index;
break;
case SiImageType_t::e_glyph:
m_source = siImage.glyph.font_family;
m_glyphs = siImage.glyph.glyphs;
break;
case SiImageType_t::e_none:
default:
break;
}
}
#if defined(_MSC_EXTENSIONS)
/// <summary>
/// Gets or sets the image id.
/// </summary>
__declspec(property(get = GetId, put = PutId)) std::string Id;
/// <summary>
/// Gets or sets the resource id.
/// </summary>
__declspec(property(get = GetResourceId, put = PutResourceId)) std::string ResourceId;
/// <summary>
/// Gets the image type.
/// </summary>
__declspec(property(get = GetType)) SiImageType_t Type;
#endif
/// <summary>
/// Sets the id of the image.
/// </summary>
/// <param name="id">A <see cref="std::string"/> representing the name or id of the image.</param>
void PutId(std::string id) {
m_id = std::move(id);
}
/// <summary>
/// Gets the image id.
/// </summary>
/// <returns>A <see cref="std::string"/> representing the name or id of the image.</returns>
std::string GetId() const {
return m_id;
}
/// <summary>
/// Sets the id of the resource in the resource file.
/// </summary>
/// <param name="id">A <see cref="std::string"/> representing the name or id of the image in the
/// resource file.</param>
/// <remarks>For example for Microsoft resource libraries MAKEINTRESOURCE(216) = "#216".</remarks>
void PutResourceId(std::string id) {
m_resourceId = std::move(id);
}
/// <summary>
/// Gets the resource id.
/// </summary>
/// <returns>A <see cref="std::string"/> representing the name or id of the image.</returns>
/// <remarks>For example for Microsoft resource libraries MAKEINTRESOURCE(216) = "#216".</remarks>
std::string GetResourceId() const {
return m_resourceId;
}
/// <summary>
/// Gets the image type.
/// </summary>
/// <returns>One of <see cref="SiImageType_t"/>.</returns>
SiImageType_t GetType() const {
return m_type;
}
/// <summary>
/// Assigns image data to the <see cref="CImage"/> instance.
/// </summary>
/// <param name="buffer">The image data. The image may be in any format that can be loaded by
/// Gdiplus::Bitmap::FromStream() or is in a recognizable svg format.</param>
/// <returns>true if successful, otherwise false.</returns>
/// <remarks>The <see cref="CImage"/> type is set to <see
/// cref="SiImageType_t::e_image"/>.</remarks>
bool AssignImage(std::string buffer, uint32_t index = 0) {
m_source = std::move(buffer);
m_type = e_image;
m_index = index;
m_resourceId.clear();
m_resourceType.clear();
return true;
}
/// <summary>
/// Initializes a new instance of the <see cref="CImage"/> class that contains the data for an
/// image held in a resource file.
/// </summary>
/// <param name="resourceFile">The name of the resource file.</param>
/// <param name="resourceId">The name or id of the image in the resource file. i.e.
/// MAKEINTRESOURCE(216) = "#216".</param>
/// <param name="resourceType">The type of the resource in the resource file. i.e. RT_BITMAP =
/// "#2".</param>
/// <param name="index">The index in a multi-image resource.</param>
/// <param name="id">The id of the command to associate with this image.</param>
/// <returns>A <see cref="CImage"/> instance.</returns>
template <class T = CImage>
static T FromResource(const std::string &resourceFile, const char *resourceId,
const char *resourceType, uint32_t index = 0, const char *id = nullptr) {
std::string r_id;
if (resourceId != nullptr) {
if (IS_INTRESOURCE_(resourceId)) {
std::ostringstream stream;
stream << "#" << reinterpret_cast<uintptr_t>(resourceId);
r_id = stream.str();
} else {
r_id = resourceId;
}
}
std::string r_type;
if (resourceType != nullptr) {
if (IS_INTRESOURCE_(resourceType)) {
std::ostringstream stream;
stream << "#" << reinterpret_cast<uintptr_t>(resourceType);
r_type = stream.str();
} else {
r_type = resourceType;
}
}
T image(resourceFile, r_id, r_type, id != nullptr ? id : "", e_resource_file,
index);
return image;
}
/// <summary>
/// Initializes a new instance of the <see cref="CImage"/> class that contains the data for an
/// image in a file.
/// </summary>
/// <param name="filename">The name of the image file.</param>
/// <param name="index">The index in a multi-image file.</param>
/// <param name="id">The id of the command to associate with this image.</param>
/// <returns>A <see cref="CImage"/> instance.</returns>
template <class T = CImage>
static T FromFile(const std::string &filename, uint32_t index = 0, const char *id = nullptr) {
T image(filename, id != nullptr ? id : "", e_image_file, index);
return image;
}
/// <summary>
/// Initializes a new instance of the <see cref="CImage"/> class that contains the data for an
/// image in a font.
/// </summary>
/// <param name="fontFamily">The name of the font family.</param>
/// <param name="index">The glyphs from which to create the image.</param>
/// <param name="id">The id of the command to associate with this image.</param>
/// <returns>A <see cref="CImage"/> instance.</returns>
template <class T = CImage>
static T FromFont(const std::string &fontFamily, const std::wstring &glyph,
const char *id = nullptr) {
T image(fontFamily, glyph, id != nullptr ? id : "", e_glyph);
return image;
}
/// <summary>
/// Initializes a new instance of the CImage class that contains the data for an image in a buffer.
/// </summary>
/// <param name="buffer">The image data. The image may be in any format that can be loaded by
/// Gdiplus::Bitmap::FromStream() or is in a recognizable svg format.</param>
/// <param name="index">The index in a multi-image file.</param>
/// <param name="id">The id of the command to associate with this image.</param>
/// <returns>A <see cref="CImage"/> instance.</returns>
template <class T = CImage>
static T FromData(const std::string &buffer, uint32_t index = 0, const char *id = nullptr) {
T image(buffer, id != nullptr ? id : "", e_image, index);
return image;
}
/// <summary>
/// Returns an <see cref="SiImage_t"/> view of the <see cref="CImage"/> instance.
/// </summary>
/// <returns>A <see cref="SiImage_t"/>.</returns>
operator SiImage_t() const {
SiImage_t siImage = {
sizeof(SiImage_t), SiImageType_t::e_none, m_id.c_str(), {}};
switch (m_type) {
case SiImageType_t::e_image_file:
siImage.type = m_type;
siImage.file.file_name = m_source.c_str();
siImage.file.index = m_index;
break;
case SiImageType_t::e_resource_file:
siImage.type = m_type;
siImage.resource.file_name = m_source.c_str();
siImage.resource.id = m_resourceId.c_str();
siImage.resource.type = m_resourceType.c_str();
siImage.resource.index = m_index;
break;
case SiImageType_t::e_image:
siImage.type = m_type;
siImage.image.data = reinterpret_cast<const uint8_t *>(m_source.data());
siImage.image.size = m_source.size();
siImage.image.index = m_index;
break;
case SiImageType_t::e_glyph:
siImage.type = m_type;
siImage.glyph.font_family = m_source.c_str();
siImage.glyph.glyphs = m_glyphs.c_str();
break;
case SiImageType_t::e_none:
break;
}
return siImage;
}
/// <summary>
/// checks whether the image is empty.
/// </summary>
/// <returns>true if the image contains data, otherwise false.</returns>
bool empty() const {
return m_type == SiImageType_t::e_none || (m_type == SiImageType_t::e_image && m_source.empty());
}
protected:
CImage(std::string source, std::wstring glyphs, std::string id, SiImageType_t type)
: m_source(std::move(source)), m_glyphs(std::move(glyphs)), m_id(std::move(id)), m_type(type) {
}
CImage(std::string source, std::string id, SiImageType_t type, uint32_t index = 0)
: m_source(std::move(source)), m_id(std::move(id)), m_type(type), m_index(index) {
}
CImage(std::string source, std::string resourceName, std::string resourceType, std::string id,
SiImageType_t type, uint32_t index = 0)
: m_source(std::move(source)), m_resourceId(std::move(resourceName)),
m_resourceType(std::move(resourceType)), m_id(std::move(id)), m_type(type), m_index(index) {
}
protected:
std::string m_source;
std::string m_resourceId;
std::string m_resourceType;
std::wstring m_glyphs;
std::string m_id;
SiImageType_t m_type;
uint32_t m_index;
};
} // namespace TDx
#endif // CImage_HPP_INCLUDED

View File

@@ -0,0 +1,568 @@
#ifndef CNavigation3D_HPP_INCLUDED
#define CNavigation3D_HPP_INCLUDED
// <copyright file="CNavigation3D.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CNavigation3D.hpp 16056 2019-04-10 13:42:31Z mbonk $
//
// </history>
// SpaceMouse
#include <SpaceMouse/CCategory.hpp>
#include <SpaceMouse/CCommand.hpp>
#include <SpaceMouse/CCommandSet.hpp>
#include <SpaceMouse/CHitTest.hpp>
#include <SpaceMouse/CImage.hpp>
#include <SpaceMouse/CNavlibImpl.hpp>
#include <SpaceMouse/IAccessors.hpp>
#include <SpaceMouse/INavlib.hpp>
// stdlib
#include <memory>
#include <string>
#include <vector>
#if (!defined(_MSC_VER) || (_MSC_VER > 1600))
#include <chrono>
#else
#include <boost/chrono.hpp>
namespace std {
namespace chrono = boost::chrono;
using boost::milli;
} // namespace std
#endif
// navlib
#include <navlib/navlib.h>
#include <navlib/navlib_error.h>
namespace TDx {
namespace SpaceMouse {
/// <summary>
/// Contains types that support 3DMouse navigation.
/// </summary>
namespace Navigation3D {
/// <summary>
/// The base class for 3D navigation implements defaults for the <see cref="IAccessors"/> interface.
/// </summary>
/// <remarks>This class can be used as the base class for the application specific implementation of
/// the accessors.</remarks>
class CNavigation3D : public INavlibProperty, protected IAccessors {
public:
/// <summary>
/// The timing source for the frame time.
/// </summary>
enum TimingSource {
/// <summary>
/// The space mouse is the source of the frame timing.
/// </summary>
SpaceMouse = 0,
/// <summary>
/// The application is the source of the frame timing.
/// </summary>
Application = 1,
};
public:
/// <summary>
/// Initializes a new instance of the CNavigation3D class.
/// </summary>
/// <param name="multiThreaded">true to use multi-threading, false for single-threaded.</param>
/// <param name="columnVectors">true for column vectors, false for row vectors as used by OpenGL.
/// </param>
/// <remarks>The default is single-threaded, row vectors</remarks>
explicit CNavigation3D(bool multiThreaded = false, bool columnVectors = false)
: m_enabled(false), m_pImpl(CNavlibImpl::CreateInstance(this, multiThreaded, columnVectors)) {
}
/// <summary>
/// Initializes a new instance of the CNavigation3D class.
/// </summary>
/// <param name="multiThreaded">true to use multi-threading, false for single-threaded.</param>
/// <param name="options">A combination of the <see cref="navlib::nlOptions_t"/> values.</param>
explicit CNavigation3D(bool multiThreaded, navlib::nlOptions_t options)
: m_enabled(false), m_pImpl(CNavlibImpl::CreateInstance(this, multiThreaded, options)) {
}
#if defined(_MSC_EXTENSIONS)
/// <summary>
/// Gets or sets a value indicating whether the 3DMouse navigation is enabled.
/// </summary>
__declspec(property(get = IsEnabled, put = EnableNavigation)) bool Enable;
/// <summary>
/// Gets or sets the animation frame time.
/// </summary>
__declspec(property(get = GetFrameTime,
put = PutFrameTime)) std::chrono::high_resolution_clock::time_point FrameTime;
/// <summary>
/// Gets or sets the frame timing source.
/// </summary>
__declspec(property(get = GetFrameTimingSource,
put = PutFrameTimingSource)) TimingSource FrameTiming;
/// <summary>
/// Gets or sets the text to pass to the 3Dconnexion driver to use in Properties Utility.
/// </summary>
/// <remarks>If the connection to the navlib is already open, the connection is closed and
/// reopened.</remarks>
__declspec(property(get = GetProfileHint, put = PutProfileHint)) std::string Profile;
/// <summary>
/// Gets or sets a value representing the active command set.
/// </summary>
/// <exception cref="std::system_error"></exception>
__declspec(property(get = GetActiveCommands, put = PutActiveCommands)) std::string ActiveCommands;
#endif
/// <summary>
/// Gets a value indicating whether 3DMouse navigation is enabled.
/// </summary>
/// <returns>true if enabled, otherwise false.</returns>
bool IsEnabled() const {
return m_enabled;
}
/// <summary>
/// Sets a value indicating whether 3DMouse navigation is enabled.
/// </summary>
/// <param name="value">true to enable, false to disable.</param>
/// <exception cref="std::invalid_argument">The text for the '3Dconnexion Properties' is
/// empty.</exception>
/// <exception cref="std::system_error">Cannot create a connection to the library.</exception>
void EnableNavigation(bool value) {
if (m_enabled == value) {
return;
}
if (value) {
m_pImpl->Open(m_profileHint);
m_enabled = true;
} else {
m_pImpl->Close();
m_enabled = false;
}
}
/// <summary>
/// Sets a value indicating whether 3DMouse navigation is enabled.
/// </summary>
/// <param name="value">true to enable, false to disable.</param>
/// <param name="ec">The <see cref="std::error_code"/> contains the error if something goes
/// wrong.</param>
/// <exception cref="std::invalid_argument">The text for the '3Dconnexion Properties' is
/// empty.</exception>
/// <exception cref="std::system_error">Cannot create a connection to the library.</exception>
void EnableNavigation(bool value, std::error_code &ec) NOEXCEPT {
try {
EnableNavigation(value);
}
#if defined(_DEBUG) && defined(TRACE_NAVLIB)
catch (const std::system_error &e) {
ec = e.code();
std::cout << "system_error exception thrown in EnableNavigation(" << value << ") 0x" << std::hex
<< ec.value() << std::dec << ", " << ec.message() << ", " << e.what() << "\n";
} catch (const std::invalid_argument &e) {
ec = std::make_error_code(std::errc::invalid_argument);
std::cout << "invalid_argument exception thrown in EnableNavigation(" << value << ") 0x"
<< std::hex << ec.value() << std::dec << ", " << ec.message() << ", " << e.what()
<< "\n";
} catch (const std::exception &e) {
ec = std::make_error_code(std::errc::io_error);
std::cout << "exception thrown in EnableNavigation(" << value << ") 0x" << std::hex << ec.value()
<< std::dec << ", " << ec.message() << ", " << e.what() << "\n";
}
#else
catch (const std::system_error &e) {
ec = e.code();
} catch (const std::invalid_argument &) {
ec = std::make_error_code(std::errc::invalid_argument);
} catch (const std::exception &) {
ec = std::make_error_code(std::errc::io_error);
}
#endif
}
/// <summary>
/// Gets or sets the animation frame time.
/// </summary>
std::chrono::high_resolution_clock::time_point GetFrameTime() {
return m_frameTime;
}
void PutFrameTime(std::chrono::high_resolution_clock::time_point value) {
if (m_frameTime != value) {
m_frameTime = std::move(value);
auto elapsed = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(
m_frameTime.time_since_epoch());
m_pImpl->Write(navlib::frame_time_k, elapsed.count());
}
}
/// <summary>
/// Gets or sets the frame timing source.
/// </summary>
TimingSource GetFrameTimingSource() {
return m_frameTimingSource;
}
void PutFrameTimingSource(TimingSource value) {
if (m_frameTimingSource != value) {
m_frameTimingSource = value;
m_pImpl->Write(navlib::frame_timing_source_k, static_cast<long>(value));
}
}
/// <summary>
/// Gets or sets the text to pass to the 3Dconnexion driver to use in Properties Utility.
/// </summary>
/// <remarks>If the connection to the navlib is already open, the connection is closed and
/// reopened.</remarks>
std::string GetProfileHint() const {
return m_profileHint;
}
void PutProfileHint(std::string value) {
if (m_profileHint != value) {
m_profileHint = std::move(value);
if (IsEnabled()) {
EnableNavigation(false);
EnableNavigation(true);
}
}
}
/// <summary>
/// Gets or sets a value representing the active command set.
/// </summary>
/// <exception cref="std::system_error"></exception>
std::string GetActiveCommands() const {
std::string result;
long error = m_pImpl->Read(navlib::commands_activeSet_k, result);
if (error != 0) {
throw std::system_error(make_error_code(error));
}
return result;
}
void PutActiveCommands(const std::string &id) {
long error = m_pImpl->Write(navlib::commands_activeSet_k, id);
if (error != 0) {
throw std::system_error(make_error_code(error));
}
}
/// <summary>
/// Add commands to the sets of commands.
/// </summary>
/// <param name="commands">The <see cref="CCommandTree"/> to add.</param>
/// <exception cref="std::system_error"></exception>
void AddCommands(const CCommandTree &commands) {
const SiActionNodeEx_t *pnode = &commands.GetSiActionNode();
long error = m_pImpl->Write(navlib::commands_tree_k, pnode);
if (error != 0) {
throw std::system_error(make_error_code(error));
}
}
/// <summary>
/// Add a set of commands to the sets of commands.
/// </summary>
/// <param name="commands">The <see cref="CCommandSet"/> to add.</param>
/// <exception cref="std::system_error"></exception>
void AddCommandSet(const CCommandSet &commands) {
AddCommands(commands);
}
/// <summary>
/// Add to the images available to the 3Dconnexion properties utility.
/// </summary>
/// <param name="images">The <see cref="std::vector"/> container containing the images to
/// add.</param>
/// <exception cref="std::system_error"></exception>
template <class T>
void AddImages(const std::vector<T> &images,
typename std::enable_if<std::is_base_of<SiImage_t, T>::value &&
sizeof(T) == sizeof(SiImage_t)>::type * = nullptr) {
long error;
navlib::imagearray_t imagearray = {images.data(), images.size()};
error = m_pImpl->Write(navlib::images_k, imagearray);
if (error != 0) {
throw std::system_error(make_error_code(error));
}
}
/// <summary>
/// Add to the images available to the 3Dconnexion properties utility.
/// </summary>
/// <param name="images">The <see cref="std::vector{T}"/> container containing the images to
/// add.</param>
/// <exception cref="std::system_error"></exception>
template <class T>
void
AddImages(const std::vector<T> &images,
typename std::enable_if<std::is_base_of<TDx::CImage, T>::value>::type * = nullptr) {
std::vector<SiImage_t> siImages;
for (auto iter = images.begin(); iter != images.end(); ++iter) {
siImages.push_back(static_cast<SiImage_t>(*iter));
}
navlib::imagearray_t imagearray = {siImages.data(), siImages.size()};
long error = m_pImpl->Write(navlib::images_k, imagearray);
if (error != 0) {
throw std::system_error(make_error_code(error));
}
}
/// <summary>
/// Writes the value of a property to the navlib.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// write.</param>
/// <param name="value">The <see cref="navlib::value"/> to write.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
long Write(const std::string &propertyName, const navlib::value &value) override {
return m_pImpl->Write(propertyName, value);
}
/// <summary>
/// Reads the value of a navlib property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="value">The <see cref="navlib::value"/> to read.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
long Read(const std::string &propertyName, navlib::value &value) const override {
return m_pImpl->Read(propertyName, value);
}
/// <summary>
/// Reads the value of a navlib string property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="string">The <see cref="std::string"/> value of the property.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib.</exception>
long Read(const std::string &propertyName, std::string &string) const override {
return m_pImpl->Read(propertyName, string);
}
protected:
// IEvents overrides
/// <summary>
/// Default for SetSettingsChanged.
/// </summary>
/// <param name="count">The change count.</param>
/// <returns>navlib::navlib_errc::function_not_supported error.</returns>
long SetSettingsChanged(long count) override {
(void)count;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
/// <summary>
/// Default for SetKeyPress.
/// </summary>
/// <param name="vkey">The virtual key code of the key pressed.</param>
/// <returns>navlib::navlib_errc::function_not_supported error.</returns>
long SetKeyPress(long vkey) override {
(void)vkey;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
/// <summary>
/// Default for SetKeyRelease.
/// </summary>
/// <param name="vkey">The virtual key code of the key pressed.</param>
/// <returns>navlib::navlib_errc::function_not_supported error.</returns>
long SetKeyRelease(long vkey) override {
(void)vkey;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
/// ISpace3D overrides
/// <summary>
/// Gets the coordinate system used by the client.
/// </summary>
/// <param name="matrix">The coordinate system <see cref="navlib::matrix_t"/>.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>The matrix describes the applications coordinate frame in the navlib coordinate
/// system. i.e. the application to navlib transform. The default is a right-handed coordinate
/// system X-right, Z-up, Y-in (column-major)</remarks>
long GetCoordinateSystem(navlib::matrix_t &matrix) const override {
// Use the right-handed coordinate system X-right, Y-up, Z-out (same as navlib)
navlib::matrix_t cs = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
// Use the right-handed coordinate system X-right, Z-up, Y-in (column-major/row vectors)
// navlib::matrix_t cs = {{{1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1}}};
matrix = cs;
return 0;
}
/// <summary>
/// Gets the orientation of the front view.
/// </summary>
/// <param name="matrix">The front view transform <see cref="navlib::matrix_t"/>.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>The default is the inverse of the coordinate system, i.e. in this case the identity
/// matrix.</remarks>
long GetFrontView(navlib::matrix_t &matrix) const override {
navlib::matrix_t front = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
matrix = front;
return 0;
}
// IModel overrides
/// <summary>
/// Gets the length of the model/world unit in meters.
/// </summary>
/// <param name="meters">The length of a model/world unit in meters.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>
/// <para>The conversion factor is used by the Navigation Library to calculate the height above
/// the floor in walk mode and the speed in the first-person motion model.</para>
/// <para>The Navigation Library assumes that this value does not change and it is only queried
/// once.</para>
/// </remarks>
long GetUnitsToMeters(double &meters) const override {
(void)meters;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
/// <summary>
/// Gets the plane equation of the floor.
/// </summary>
/// <param name="floor">The plane equation of the floor plane.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>
/// <para>The plane equation is used by the Navigation Library to determine the floor for the
/// walk navigation mode, where the height of the eye is fixed to 1.5m above the floor plane.
/// The floor need not be parallel to the world ground plane.</para>
/// </remarks>
long GetFloorPlane(navlib::plane_t &floor) const override {
(void)floor;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
// IState overrides
/// <summary>
/// Is called when the navigation library starts or stops a navigation transaction.
/// </summary>
/// <param name="transaction">The transaction number: >0 begin, ==0 end.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
long SetTransaction(long transaction) override {
(void)transaction;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
/// <summary>
/// Is called when the navigation instance starts or stops a sequence of motion frames.
/// </summary>
/// <param name="motion">The motion flag: true = start, false = end.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>This marks the start and end of user interaction with the scene using the
/// 3D Mouse.</remarks>
long SetMotionFlag(bool motion) override {
(void)motion;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
/// <summary>
/// Gets the camera's target.
/// </summary>
/// <param name="target">The position of the camera target in world coordinates.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>Free cameras do not have a target.</remarks>
long GetCameraTarget(navlib::point_t &target) const override {
(void)target;
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
/// <summary>
/// Gets the view's construction plane.
/// </summary>
/// <param name="plane">The plane equation of the construction plane.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>Required to disable rotations when constructing.</remarks>
long GetViewConstructionPlane(navlib::plane_t &plane) const override {
(void)plane;
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
/// <summary>
/// Gets a value indicating whether the view can be rotated.
/// </summary>
/// <param name="isRotatable">true if the view can be rotated, false otherwise.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>For paper space return false.</remarks>
long GetIsViewRotatable(navlib::bool_t &isRotatable) const override {
isRotatable = true;
return 0;
}
/// <summary>
/// Gets the distance to the view's focused object.
/// </summary>
/// <param name="distance">The distance to the object in world units.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>The distance to the object determines the translation velocity in camera mode
/// navigation modes. Generally the navigation library attempts to determine this value by
/// hit-testing the scene. There are, however, cases when the user wants to move to a far
/// off object and is not interested in what is nearby.</remarks>
long GetViewFocusDistance(double &distance) const override {
(void)distance;
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
/// <summary>
/// Sets the camera's target position.
/// </summary>
/// <param name="target">The position of the camera target in world coordinates.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>Free cameras do not have a target.</remarks>
long SetCameraTarget(const navlib::point_t &target) override {
(void)target;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
/// <summary>
/// Sets the position of the pointer on the projection plane.
/// </summary>
/// <param name="position">The <see cref="navlib::point_t"/> in world coordinates of the
/// pointer.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
long SetPointerPosition(const navlib::point_t &position) override {
(void)position;
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
protected:
std::error_code make_error_code(long result_code) const {
int errc = result_code & 0xffff;
int facility = result_code >> 16 & 0x7fff;
if (facility == FACILITY_NAVLIB) {
return std::error_code(errc, navlib_category);
}
return std::error_code(errc, std::generic_category());
}
protected:
bool m_enabled;
std::string m_profileHint;
std::chrono::high_resolution_clock::time_point m_frameTime;
TimingSource m_frameTimingSource;
std::shared_ptr<CNavlibImpl> m_pImpl;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // CNavigationModelImpl_HPP_INCLUDED

View File

@@ -0,0 +1,319 @@
#ifndef CNavlibImpl_HPP_INCLUDED
#define CNavlibImpl_HPP_INCLUDED
// <copyright file="CNavlibImpl.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CNavlibImpl.hpp 16062 2019-04-11 12:58:50Z mbonk $
//
// 05/25/20 MSB Fix C2280. Use std::static_pointer_cast<> instead of std::dynamic_pointer_cast<>.
// </history>
#include <SpaceMouse/CNavlibInterface.hpp>
#include <SpaceMouse/IAccessors.hpp>
#include <SpaceMouse/INavlib.hpp>
// stdlib
#include <map>
#include <memory>
#include <string>
#include <vector>
// navlib
#include <navlib/navlib.h>
#include <navlib/navlib_error.h>
namespace TDx {
namespace SpaceMouse {
namespace Navigation3D {
/// <summary>
/// Implementation for creating a shared pointer.
/// </summary>
class CNavlibImpl : public INavlib,
#if defined(_MSC_VER) && _MSC_VER <= 1800
public IAccessors,
#else
private IAccessors,
#endif
public std::enable_shared_from_this<CNavlibImpl> {
typedef CNavlibImpl this_type;
friend std::shared_ptr<IAccessors>
std::static_pointer_cast<IAccessors, CNavlibImpl>(const std::shared_ptr<CNavlibImpl> &) NOEXCEPT;
/// <summary>
/// Make the constructors private to force creation of a shared pointer.
/// </summary>
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
CNavlibImpl() = default;
#else
CNavlibImpl() {
}
#endif
CNavlibImpl(IAccessors *iclient) : m_iclient(iclient) {
}
public:
/// <summary>
/// Creates a new instance of the CNavlibImpl class.
/// </summary>
/// <param name="iclient">pointer to the instance implementing the IAccessors interface.</param>
/// <param name="multiThreaded">true to use multi-threading, false for single-threaded.</param>
/// <param name="rowMajor">true for row-major ordered matrices, false for column-major.</param>
/// <returns>
/// A <see cref="std::shared_ptr{CNavlibImpl}"/> to the new CNavlibImpl instance.
/// </returns>
static std::shared_ptr<CNavlibImpl>
CreateInstance(IAccessors *iclient, bool multiThreaded = false, bool rowMajor = false) {
return CreateInstance(iclient, multiThreaded,
rowMajor ? navlib::row_major_order : navlib::none);
}
/// <summary>
/// Creates a new instance of the CNavlibImpl class.
/// </summary>
/// <param name="iclient">pointer to the instance implementing the IAccessors interface.</param>
/// <param name="multiThreaded">true to use multi-threading, false for single-threaded.</param>
/// <param name="options">A combination of the <see cref="navlib::nlOptions_t"/> values.</param>
/// <returns>
/// A <see cref="std::shared_ptr{CNavlibImpl}"/> to the new CNavlibImpl instance.
/// </returns>
static std::shared_ptr<CNavlibImpl> CreateInstance(IAccessors *iclient, bool multiThreaded,
navlib::nlOptions_t options) {
if (iclient == nullptr) {
throw std::logic_error("The accessor interface is null");
}
// So that std::make_shared<> can be used with the private constructor.
struct make_shared_enabler : public this_type {
make_shared_enabler(IAccessors *iclient) : this_type(iclient) {
}
};
std::shared_ptr<CNavlibImpl> result = std::make_shared<make_shared_enabler>(iclient);
result->m_pNavlib = std::unique_ptr<CNavlibInterface>(
new CNavlibInterface(std::static_pointer_cast<IAccessors>(result), multiThreaded, options));
return result;
}
/// <summary>
/// Clean up the resources
/// </summary>
virtual ~CNavlibImpl() {
}
// INavlib implementation
/// <summary>
/// Close the connection to the 3D navigation library.
/// </summary>
void Close() override {
m_pNavlib->Close();
}
/// <summary>
/// Opens a connection to the 3D navigation library.
/// </summary>
void Open() override {
m_pNavlib->Open();
}
/// <summary>
/// Opens a connection to the 3D navigation library
/// </summary>
/// <param name="profileName">The name of the 3Dconnexion profile to use.</param>
/// <exception cref="std::system_error">The connection to the library is already open.</exception>
/// <exception cref="std::system_error">Cannot create a connection to the library.</exception>
/// <exception cref="std::invalid_argument">The name of the profile is empty.</exception>
void Open(std::string profileName) override {
m_pNavlib->Open(std::move(profileName));
}
/// <summary>
/// Writes the value of a property to the navlib.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// write.</param>
/// <param name="value">The <see cref="navlib::value"/> to write.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
long Write(const std::string &propertyName, const navlib::value &value) override {
return m_pNavlib->Write(propertyName, value);
}
/// <summary>
/// Reads the value of a navlib property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="value">The <see cref="navlib::value"/> to read.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
long Read(const std::string &propertyName, navlib::value &value) const override {
return m_pNavlib->Read(propertyName, value);
}
/// <summary>
/// Reads the value of a navlib string property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="string">The <see cref="std::string"/> value of the property.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib.</exception>
long Read(const std::string &propertyName, std::string &string) const override {
return m_pNavlib->Read(propertyName, string);
}
private:
// IEvents overrides
long SetActiveCommand(std::string commandId) override {
return m_iclient->SetActiveCommand(commandId);
}
long SetSettingsChanged(long change) override {
return m_iclient->SetSettingsChanged(change);
}
long SetKeyPress(long vkey) override {
return m_iclient->SetKeyPress(vkey);
}
long SetKeyRelease(long vkey) override {
return m_iclient->SetKeyRelease(vkey);
}
// IHit overrides
long GetHitLookAt(navlib::point_t &position) const override {
return m_iclient->GetHitLookAt(position);
}
long SetHitAperture(double aperture) override {
return m_iclient->SetHitAperture(aperture);
}
long SetHitDirection(const navlib::vector_t &direction) override {
return m_iclient->SetHitDirection(direction);
}
long SetHitLookFrom(const navlib::point_t &eye) override {
return m_iclient->SetHitLookFrom(eye);
}
long SetHitSelectionOnly(bool onlySelection) override {
return m_iclient->SetHitSelectionOnly(onlySelection);
}
// IModel overrides
long GetModelExtents(navlib::box_t &extents) const override {
return m_iclient->GetModelExtents(extents);
}
long GetSelectionExtents(navlib::box_t &extents) const override {
return m_iclient->GetSelectionExtents(extents);
}
long GetSelectionTransform(navlib::matrix_t &transform) const override {
return m_iclient->GetSelectionTransform(transform);
}
long GetIsSelectionEmpty(navlib::bool_t &empty) const override {
return m_iclient->GetIsSelectionEmpty(empty);
}
long SetSelectionTransform(const navlib::matrix_t &matrix) override {
return m_iclient->SetSelectionTransform(matrix);
}
long GetUnitsToMeters(double &meters) const override {
return m_iclient->GetUnitsToMeters(meters);
}
long GetFloorPlane(navlib::plane_t &floor) const override {
return m_iclient->GetFloorPlane(floor);
}
// IPivot overrides
long GetPivotPosition(navlib::point_t &position) const override {
return m_iclient->GetPivotPosition(position);
}
long IsUserPivot(navlib::bool_t &userPivot) const override {
return m_iclient->IsUserPivot(userPivot);
}
long SetPivotPosition(const navlib::point_t &position) override {
return m_iclient->SetPivotPosition(position);
}
long GetPivotVisible(navlib::bool_t &visible) const override {
return m_iclient->GetPivotVisible(visible);
}
long SetPivotVisible(bool visible) override {
return m_iclient->SetPivotVisible(visible);
}
// ISpace3D overrides
long GetCoordinateSystem(navlib::matrix_t &matrix) const override {
return m_iclient->GetCoordinateSystem(matrix);
}
long GetFrontView(navlib::matrix_t &matrix) const override {
return m_iclient->GetFrontView(matrix);
}
// IState overrides
long SetTransaction(long transaction) override {
return m_iclient->SetTransaction(transaction);
}
long SetMotionFlag(bool motion) override {
return m_iclient->SetMotionFlag(motion);
}
// IView overrides
long GetCameraMatrix(navlib::matrix_t &matrix) const override {
return m_iclient->GetCameraMatrix(matrix);
}
long GetCameraTarget(navlib::point_t &point) const override {
return m_iclient->GetCameraTarget(point);
}
long GetPointerPosition(navlib::point_t &position) const override {
return m_iclient->GetPointerPosition(position);
}
long GetViewConstructionPlane(navlib::plane_t &plane) const override {
return m_iclient->GetViewConstructionPlane(plane);
}
long GetViewExtents(navlib::box_t &extents) const override {
return m_iclient->GetViewExtents(extents);
}
long GetViewFocusDistance(double &distance) const override {
return m_iclient->GetViewFocusDistance(distance);
}
long GetViewFOV(double &fov) const override {
return m_iclient->GetViewFOV(fov);
}
long GetViewFrustum(navlib::frustum_t &frustum) const override {
return m_iclient->GetViewFrustum(frustum);
}
long GetIsViewPerspective(navlib::bool_t &perspective) const override {
return m_iclient->GetIsViewPerspective(perspective);
}
long GetIsViewRotatable(navlib::bool_t &isRotatable) const override {
return m_iclient->GetIsViewRotatable(isRotatable);
}
long SetCameraMatrix(const navlib::matrix_t &matrix) override {
return m_iclient->SetCameraMatrix(matrix);
}
long SetCameraTarget(const navlib::point_t &target) override {
return m_iclient->SetCameraTarget(target);
}
long SetPointerPosition(const navlib::point_t &position) override {
return m_iclient->SetPointerPosition(position);
}
long SetViewExtents(const navlib::box_t &extents) override {
return m_iclient->SetViewExtents(extents);
}
long SetViewFOV(double fov) override {
return m_iclient->SetViewFOV(fov);
}
long SetViewFrustum(const navlib::frustum_t &frustum) override {
return m_iclient->SetViewFrustum(frustum);
}
private:
IAccessors *m_iclient = nullptr;
std::unique_ptr<CNavlibInterface> m_pNavlib;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // CNavlibImpl_HPP_INCLUDED

View File

@@ -0,0 +1,991 @@
#ifndef CNavlibInterface_HPP_INCLUDED
#define CNavlibInterface_HPP_INCLUDED
// <copyright file="CNavilibInterface.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: CNavlibInterface.hpp 16051 2019-04-09 11:29:53Z mbonk $
//
// 07/23/19 MSB Do not set the cookie to zero when the open fails.
// </history>
#include <SpaceMouse/CCookieCollection.hpp>
#include <SpaceMouse/IAccessors.hpp>
#include <SpaceMouse/IActionAccessors.hpp>
#include <SpaceMouse/INavlib.hpp>
// stdlib
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <iostream>
// navlib
#include <navlib/navlib.h>
#include <navlib/navlib_error.h>
#include <navlib/navlib_ostream.h>
#if defined(WAMP_CLIENT) && (WAMP_CLIENT==1)
// wamp
#include <wamp/net.hpp>
#include <wamp/navlib_client_session.hpp>
#endif
namespace TDx {
namespace SpaceMouse {
/// <summary>
/// Template to get a specific interface from a unique pointer.
/// </summary>
template <typename Ty_, typename I_> Ty_ *GetInterface(const std::unique_ptr < I_>& p) {
I_ *i = p.get();
if (i == nullptr) {
return nullptr;
}
Ty_ *t = static_cast<Ty_ *>(*p.get());
return t;
}
/// <summary>
/// The base class for the Accessors items.
/// </summary>
/// <remarks> The purpose of the class is to use polymorphism to avoid dynamic casts.
/// <remarks/>
class AccessorInterface {
public:
explicit operator Navigation3D::ISpace3D *() {
return GetISpace3DInterface();
}
explicit operator Navigation3D::IView *() {
return GetIViewInterface();
}
explicit operator Navigation3D::IModel *() {
return GetIModelInterface();
}
explicit operator Navigation3D::IPivot *() {
return GetIPivotInterface();
}
explicit operator Navigation3D::IHit *() {
return GetIHitInterface();
}
explicit operator Navigation3D::IEvents *() {
return GetIEventsInterface();
}
explicit operator Navigation3D::IState *() {
return GetIStateInterface();
}
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
AccessorInterface() = default;
virtual ~AccessorInterface() = default;
AccessorInterface(const AccessorInterface &) = delete;
AccessorInterface &operator=(const AccessorInterface &) = delete;
#else
AccessorInterface(){};
virtual ~AccessorInterface(){};
private:
AccessorInterface(const AccessorInterface &);
AccessorInterface &operator=(const AccessorInterface &);
#endif
protected:
virtual Navigation3D::ISpace3D *GetISpace3DInterface() {
return nullptr;
}
virtual Navigation3D::IView *GetIViewInterface() {
return nullptr;
}
virtual Navigation3D::IModel *GetIModelInterface() {
return nullptr;
}
virtual Navigation3D::IPivot *GetIPivotInterface() {
return nullptr;
}
virtual Navigation3D::IHit *GetIHitInterface() {
return nullptr;
}
virtual Navigation3D::IEvents *GetIEventsInterface() {
return nullptr;
}
virtual Navigation3D::IState *GetIStateInterface() {
return nullptr;
}
};
class IWeakPtr {
public:
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
virtual ~IWeakPtr() = default;
#else
virtual ~IWeakPtr() = 0 {
}
#endif
virtual std::unique_ptr<AccessorInterface> lock() = 0;
};
// General template for a <see cref="WeakAccessorPtr{T}"/>.
template <typename T_> class WeakAccessorPtr : public IWeakPtr {
public:
std::unique_ptr<AccessorInterface> lock() override {
return std::unique_ptr<AccessorInterface>();
}
};
/// <summary>
/// Specialization of the <see cref="WeakAccessorPtr{T}"/> template for the <see cref="Navigation3D::IAccessors"/> interface.
/// </summary>
template <> class WeakAccessorPtr<Navigation3D::IAccessors> : public IWeakPtr {
// Implementation of the accessors interfaces.
class Accessors : public AccessorInterface {
public:
Accessors(std::shared_ptr<Navigation3D::IAccessors> accessors)
: m_interface(std::forward<std::shared_ptr<Navigation3D::IAccessors>>(accessors)) {
}
protected:
Navigation3D::ISpace3D *GetISpace3DInterface() override {
return static_cast<Navigation3D::ISpace3D *>(m_interface.get());
}
Navigation3D::IView *GetIViewInterface() override {
return static_cast<Navigation3D::IView *>(m_interface.get());
}
Navigation3D::IModel *GetIModelInterface() override {
return static_cast<Navigation3D::IModel *>(m_interface.get());
}
Navigation3D::IPivot *GetIPivotInterface() override {
return static_cast<Navigation3D::IPivot *>(m_interface.get());
}
Navigation3D::IHit *GetIHitInterface() override {
return static_cast<Navigation3D::IHit *>(m_interface.get());
}
Navigation3D::IEvents *GetIEventsInterface() override {
return static_cast<Navigation3D::IEvents *>(m_interface.get());
}
Navigation3D::IState *GetIStateInterface() override {
return static_cast<Navigation3D::IState *>(m_interface.get());
}
private:
std::shared_ptr<Navigation3D::IAccessors> m_interface;
};
public:
WeakAccessorPtr(std::shared_ptr<Navigation3D::IAccessors> &&accessors)
: m_interface(std::forward<std::shared_ptr<Navigation3D::IAccessors>>(accessors)) {
}
std::unique_ptr<AccessorInterface> lock() override {
return std::unique_ptr<AccessorInterface>(new Accessors(m_interface.lock()));
}
protected:
std::weak_ptr<Navigation3D::IAccessors> m_interface;
};
/// <summary>
/// Specialization of the <see cref="WeakAccessorPtr{T}"/> template for the <see cref="ActionInput::IActionAccessors"/> interface.
/// </summary>
template <> class WeakAccessorPtr<ActionInput::IActionAccessors> : public IWeakPtr {
// Implementation of the accessors interfaces.
class Accessors : public AccessorInterface {
public:
Accessors(std::shared_ptr<ActionInput::IActionAccessors> accessors)
: m_interface(std::forward<std::shared_ptr<ActionInput::IActionAccessors>>(accessors)) {
}
protected:
Navigation3D::IEvents *GetIEventsInterface() override {
return static_cast<Navigation3D::IEvents *>(m_interface.get());
}
private:
std::shared_ptr<ActionInput::IActionAccessors> m_interface;
};
public:
WeakAccessorPtr(std::shared_ptr<ActionInput::IActionAccessors> &&accessors)
: m_interface(std::forward<std::shared_ptr<ActionInput::IActionAccessors>>(accessors)) {
}
std::unique_ptr<AccessorInterface> lock() override {
return std::unique_ptr<AccessorInterface>(new Accessors(m_interface.lock()));
}
protected:
std::weak_ptr<ActionInput::IActionAccessors> m_interface;
};
/// <summary>
/// Template to allow defining the static members in the header file
/// </summary>
template <typename Ty_, typename I_> struct StaticSinkCollection {
protected:
static CCookieCollection<I_> s_sinkCollection;
static std::mutex s_mutex;
};
template <class Ty_, class I_>
CCookieCollection<I_> StaticSinkCollection<Ty_, I_>::s_sinkCollection;
/// <summary>
/// Mutex used to synchronize the trace output.
/// </summary>
template <class Ty_, class I_> std::mutex StaticSinkCollection<Ty_, I_>::s_mutex;
namespace Navigation3D {
/// <summary>
/// Class implements the interface to the navlib.
/// </summary>
class CNavlibInterface : public INavlib,
private StaticSinkCollection<CNavlibInterface, IWeakPtr> {
public:
/// <summary>
/// Initializes a new instance of the CNavlibInterface class.
/// </summary>
/// <param name="sink">Shared pointer to the instance implementing the IAccessors interface
/// accessors and mutators.</param>
/// <param name="multiThreaded">true to use multi-threading, false for single-threaded.</param>
/// <param name="rowMajor">true for row-major ordered matrices, false for column-major.</param>
template <class T_>
explicit CNavlibInterface(std::shared_ptr<T_> sink, bool multiThreaded = false,
bool rowMajor = false)
: m_hdl(INVALID_NAVLIB_HANDLE),
m_cookie(s_sinkCollection.insert(std::make_shared<WeakAccessorPtr<T_>>(std::move(sink))))
#if defined(_MSC_VER) && (_MSC_VER < 1800)
{
navlib::nlCreateOptions_t options = {sizeof(navlib::nlCreateOptions_t), multiThreaded,
rowMajor ? navlib::row_major_order : navlib::none};
m_createOptions = options;
}
#else
,
m_createOptions{sizeof(navlib::nlCreateOptions_t), multiThreaded,
rowMajor ? navlib::row_major_order : navlib::none} {
}
#endif
/// <summary>
/// Initializes a new instance of the CNavlibInterface class.
/// </summary>
/// <param name="sink">Shared pointer to the instance implementing the IAccessors interface
/// accessors and mutators.</param>
/// <param name="multiThreaded">true to use multi-threading, false for single-threaded.</param>
/// <param name="options">A combination of the <see cref="navlib::nlOptions_t"/> values.</param>
template <class T_>
explicit CNavlibInterface(std::shared_ptr<T_> sink, bool multiThreaded,
navlib::nlOptions_t options)
: m_hdl(INVALID_NAVLIB_HANDLE),
m_cookie(s_sinkCollection.insert(std::make_shared<WeakAccessorPtr<T_>>(std::move(sink))))
#if defined(_MSC_VER) && (_MSC_VER < 1800)
{
navlib::nlCreateOptions_t createOptions = {sizeof(navlib::nlCreateOptions_t), multiThreaded,
options};
m_createOptions = createOptions;
}
#else
,
m_createOptions({sizeof(navlib::nlCreateOptions_t), multiThreaded, options}) {
}
#endif
/// <summary>
/// Clean up the resources
/// </summary>
~CNavlibInterface() override {
using namespace ::navlib;
if (m_cookie) {
s_sinkCollection.erase(m_cookie);
}
if (m_hdl != INVALID_NAVLIB_HANDLE) {
NlClose(m_hdl);
}
}
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
CNavlibInterface(const CNavlibInterface &) = delete;
CNavlibInterface& operator=(const CNavlibInterface &) = delete;
#else
private:
CNavlibInterface(const CNavlibInterface &);
CNavlibInterface &operator=(const CNavlibInterface &);
#endif
public :
/// <summary>
/// Close the connection to the 3D navigation library.
/// </summary>
void Close() override {
using namespace ::navlib;
if (m_hdl != INVALID_NAVLIB_HANDLE) {
std::unique_lock<std::mutex> lock(m_mutex);
if (m_hdl != INVALID_NAVLIB_HANDLE) {
NlClose(m_hdl);
m_hdl = INVALID_NAVLIB_HANDLE;
}
}
}
/// <summary>
/// Opens a connection to the 3D navigation library.
/// </summary>
void Open() override {
Open(m_name);
}
/// <summary>
/// Opens a connection to the 3D navigation library
/// </summary>
/// <param name="profileText">The text to display in the 3Dconnexion profile.</param>
/// <exception cref="std::system_error">The connection to the library is already open.</exception>
/// <exception cref="std::system_error">Cannot create a connection to the library.</exception>
/// <exception cref="std::invalid_argument">The text for the profile is empty.</exception>
void Open(std::string profileText) override {
using namespace ::navlib;
if (profileText.empty()) {
throw std::invalid_argument("The text for the profile is empty.");
}
std::unique_lock<std::mutex> lock(m_mutex);
if (m_hdl != INVALID_NAVLIB_HANDLE) {
throw std::system_error(navlib::make_error_code(navlib_errc::already_connected),
"Connection to the library is already open.");
}
#if defined(WAMP_CLIENT) && (WAMP_CLIENT == 1)
if (!m_session) {
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::tlsv12_client};
m_session = std::make_shared<tdx::wamp::client::NlSession>(ctx);
}
if (!m_session->is_running()) {
std::error_code ec;
m_session->run(ec);
if (ec) {
throw std::system_error(ec, "Cannot run navlib session.");
}
}
#endif
auto isink = s_sinkCollection.at(m_cookie)->lock();
std::vector<accessor_t> accessors;
// Event accessors
if (nullptr != GetInterface<IEvents>(isink)) {
accessors.insert(
accessors.end(),
{{commands_activeCommand_k, nullptr, &CNavlibInterface::SetActiveCommand, m_cookie},
{events_keyPress_k, nullptr, &CNavlibInterface::SetKeyPress, m_cookie},
{events_keyRelease_k, nullptr, &CNavlibInterface::SetKeyRelease, m_cookie},
{settings_changed_k, nullptr, &CNavlibInterface::SetSettingsChanged, m_cookie}});
}
// 3D space accessors
if (nullptr != GetInterface<ISpace3D>(isink)) {
accessors.insert(
accessors.end(),
{{coordinate_system_k, &CNavlibInterface::GetCoordinateSystem, nullptr, m_cookie},
{views_front_k, &CNavlibInterface::GetFrontView, nullptr, m_cookie}});
}
// state accessors
if (nullptr != GetInterface<IState>(isink)) {
accessors.insert(
accessors.end(),
{{motion_k, nullptr, &CNavlibInterface::SetMotionFlag, m_cookie},
{transaction_k, nullptr, &CNavlibInterface::SetTransaction, m_cookie}});
}
// view access
if (nullptr != GetInterface<IView>(isink)) {
accessors.insert(accessors.end(),
{{view_affine_k, &CNavlibInterface::GetCameraMatrix, &CNavlibInterface::SetCameraMatrix,
m_cookie},
{view_constructionPlane_k, &CNavlibInterface::GetViewConstructionPlane, nullptr,
m_cookie},
{view_extents_k, &CNavlibInterface::GetViewExtents, &CNavlibInterface::SetViewExtents,
m_cookie},
{view_focusDistance_k, &CNavlibInterface::GetViewFocusDistance, nullptr, m_cookie},
{view_fov_k, &CNavlibInterface::GetViewFOV, &CNavlibInterface::SetViewFOV, m_cookie},
{view_frustum_k, &CNavlibInterface::GetViewFrustum, &CNavlibInterface::SetViewFrustum,
m_cookie},
{view_perspective_k, &CNavlibInterface::GetIsViewPerspective, nullptr, m_cookie},
{view_target_k, &CNavlibInterface::GetCameraTarget, &CNavlibInterface::SetCameraTarget,
m_cookie},
{view_rotatable_k, &CNavlibInterface::GetIsViewRotatable, nullptr, m_cookie},
{pointer_position_k, &CNavlibInterface::GetPointerPosition,
&CNavlibInterface::SetPointerPosition, m_cookie}});
}
// pivot accessors
if (nullptr != GetInterface<IPivot>(isink)) {
accessors.insert(
accessors.end(),
{{pivot_position_k, &CNavlibInterface::GetPivotPosition, &CNavlibInterface::SetPivotPosition, m_cookie},
{pivot_user_k, &CNavlibInterface::IsUserPivot, nullptr, m_cookie},
{pivot_visible_k, &CNavlibInterface::GetPivotVisible, &CNavlibInterface::SetPivotVisible, m_cookie}});
}
// hit testing for auto pivot algorithm etc.
if (nullptr != GetInterface<IHit>(isink)) {
accessors.insert(accessors.end(),
{{hit_lookfrom_k, nullptr, &CNavlibInterface::SetHitLookFrom, m_cookie},
{hit_direction_k, nullptr, &CNavlibInterface::SetHitDirection, m_cookie},
{hit_aperture_k, nullptr, &CNavlibInterface::SetHitAperture, m_cookie},
{hit_lookat_k, &CNavlibInterface::GetHitLookAt, nullptr, m_cookie},
{hit_selectionOnly_k, nullptr, &CNavlibInterface::SetHitSelectionOnly, m_cookie}});
}
// model access
if (nullptr != GetInterface<IModel>(isink)) {
accessors.insert(accessors.end(),
{{model_extents_k, &CNavlibInterface::GetModelExtents, nullptr, m_cookie},
{selection_empty_k, &CNavlibInterface::GetIsSelectionEmpty, nullptr, m_cookie},
{selection_extents_k, &CNavlibInterface::GetSelectionExtents, nullptr, m_cookie},
{selection_affine_k, &CNavlibInterface::GetSelectionTransform,
&CNavlibInterface::SetSelectionTransform, m_cookie},
{model_unitsToMeters_k, &CNavlibInterface::GetUnitsToMeters, nullptr, m_cookie},
{model_floorPlane_k, &CNavlibInterface::GetFloorPlane, nullptr, m_cookie}});
}
// Create the navlib instance
long error = NlCreate(&m_hdl, profileText.c_str(), accessors.data(),
accessors.size(), &m_createOptions);
if (error != 0) {
throw std::system_error(
navlib::make_error_code(static_cast<navlib_errc::navlib_errc_t>(error & 0xffff)),
"Cannot create a connection to the 3DMouse.");
}
m_name = std::move(profileText);
}
/// <summary>
/// Writes the value of a property to the navlib.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// write.</param>
/// <param name="value">The <see cref="navlib::value"/> to write.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib.</exception>
long Write(const std::string &propertyName, const navlib::value &value) override {
if (m_hdl == INVALID_NAVLIB_HANDLE) {
return navlib::make_result_code(navlib::navlib_errc::invalid_operation);
}
long resultCode = WriteValue(m_hdl, propertyName.c_str(), &value);
return resultCode;
}
/// <summary>
/// Reads the value of a navlib property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="value">The <see cref="navlib::value"/> to read.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib.</exception>
long Read(const std::string &propertyName, navlib::value &value) const override {
if (m_hdl == INVALID_NAVLIB_HANDLE) {
return navlib::make_result_code(navlib::navlib_errc::invalid_operation);
}
long resultCode = ReadValue(m_hdl, propertyName.c_str(), &value);
return resultCode;
}
/// <summary>
/// Reads the value of a navlib string property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="string">The <see cref="std::string"/> value of the property.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib.</exception>
long Read(const std::string &propertyName, std::string &string) const override {
if (m_hdl == INVALID_NAVLIB_HANDLE) {
return navlib::make_result_code(navlib::navlib_errc::invalid_operation);
}
navlib::value value(&string[0], string.length());
long resultCode = ReadValue(m_hdl, propertyName.c_str(), &value);
if ((resultCode & 0xffff) == static_cast<int>(navlib::navlib_errc::insufficient_buffer)) {
string.resize(value.string.length);
value = navlib::value(&string[0], string.length());
resultCode = ReadValue(m_hdl, propertyName.c_str(), &value);
}
if (resultCode == 0) {
string.resize(value.string.length);
}
return resultCode;
}
private:
typedef std::unique_ptr<AccessorInterface> isink_t;
template <typename F>
static long GetValue(navlib::param_t cookie, navlib::property_t property, navlib::value_t *value,
F fn) {
try {
isink_t isink = s_sinkCollection.at(cookie)->lock();
long result = fn(std::move(isink));
#if defined(_DEBUG) && defined(TRACE_NAVLIB)
std::unique_lock<std::mutex> lock(s_mutex);
std::clog << "GetValue(0x" << std::hex << cookie << std::dec << ", " << property << ", "
<< *value << ") result =0x" << std::hex << result << std::endl;
#endif
return result;
}
catch (const std::out_of_range &e) {
std::unique_lock<std::mutex> lock(s_mutex);
std::cerr << "std::out_of_range exception thrown in GetValue(0x" << std::hex << cookie
<< std::dec << ", " << property << ", value)\n"
<< *value << e.what() << std::endl;
return navlib::make_result_code(navlib::navlib_errc::invalid_argument);
} catch (const std::exception &e) {
std::cerr << "Uncaught exception thrown in GetValue(0x" << std::hex << cookie << std::dec
<< ", " << property << ", value)\n"
<< *value << e.what() << std::endl;
}
return navlib::make_result_code(navlib::navlib_errc::error);
}
template <typename F>
static long SetValue(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value, F fn) {
try {
isink_t isink = s_sinkCollection.at(cookie)->lock();
long result = fn(std::move(isink));
#if defined(_DEBUG) && defined(TRACE_NAVLIB)
std::clog << "SetValue(0x" << std::hex << cookie << std::dec << ", " << property << ", "
<< *value << ") result =0x" << std::hex << result << std::endl;
#endif
return result;
}
catch (const std::out_of_range &e) {
std::unique_lock<std::mutex> lock(s_mutex);
std::cerr << "std::out_of_range exception thrown in SetValue(0x" << std::hex << cookie
<< std::dec << ", " << property << ", value)\n"
<< *value << e.what() << std::endl;
return navlib::make_result_code(navlib::navlib_errc::invalid_argument);
} catch (const std::exception &e) {
std::unique_lock<std::mutex> lock(s_mutex);
std::cerr << "Uncaught exception thrown in SetValue(0x" << std::hex << cookie << std::dec
<< ", " << property << "," << *value << ")\n"
<< e.what() << std::endl;
}
return navlib::make_result_code(navlib::navlib_errc::error);
}
/// <summary>
/// IEvents accessors and mutators
/// </summary>
static long SetActiveCommand(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IEvents>(isink)->SetActiveCommand(static_cast<const char *>(*value));
});
}
static long SetSettingsChanged(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IEvents>(isink)->SetSettingsChanged(*value);
});
}
static long SetKeyPress(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IEvents>(isink)->SetKeyPress(*value);
});
}
static long SetKeyRelease(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IEvents>(isink)->SetKeyRelease(*value);
});
}
/// <summary>
/// IHit accessors and mutators
/// </summary>
static long GetHitLookAt(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IHit>(isink)->GetHitLookAt(*value);
});
}
static long SetHitAperture(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IHit>(isink)->SetHitAperture(*value);
});
}
static long SetHitDirection(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IHit>(isink)->SetHitDirection(*value);
});
}
static long SetHitLookFrom(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IHit>(isink)->SetHitLookFrom(*value);
});
}
static long SetHitSelectionOnly(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IHit>(isink)->SetHitSelectionOnly(*value);
});
}
/// <summary>
/// IModel accessors and mutators
/// </summary>
static long GetModelExtents(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IModel>(isink)->GetModelExtents(*value);
});
}
static long GetSelectionExtents(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IModel>(isink)->GetSelectionExtents(*value);
});
}
static long GetSelectionTransform(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IModel>(isink)->GetSelectionTransform(*value);
});
}
static long GetIsSelectionEmpty(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IModel>(isink)->GetIsSelectionEmpty(*value);
});
}
static long SetSelectionTransform(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IModel>(isink)->SetSelectionTransform(*value);
});
}
static long GetUnitsToMeters(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IModel>(isink)->GetUnitsToMeters(*value);
});
}
static long GetFloorPlane(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IModel>(isink)->GetFloorPlane(*value);
});
}
/// <summary>
/// IPivot accessors and mutators
/// </summary>
static long GetPivotPosition(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IPivot>(isink)->GetPivotPosition(*value);
});
}
static long IsUserPivot(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IPivot>(isink)->IsUserPivot(*value);
});
}
static long SetPivotPosition(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IPivot>(isink)->SetPivotPosition(*value);
});
}
static long GetPivotVisible(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IPivot>(isink)->GetPivotVisible(*value);
});
}
static long SetPivotVisible(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IPivot>(isink)->SetPivotVisible(*value);
});
}
/// <summary>
/// ISpace3D accessors and mutators
/// </summary>
static long GetCoordinateSystem(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<ISpace3D>(isink)->GetCoordinateSystem(*value);
});
}
static long GetFrontView(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<ISpace3D>(isink)->GetFrontView(*value);
});
}
/// <summary>
/// IState accessors and mutators
/// </summary>
static long SetTransaction(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IState>(isink)->SetTransaction(*value);
});
}
static long SetMotionFlag(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IState>(isink)->SetMotionFlag(*value);
});
}
/// <summary>
/// IView accessors and mutators
/// </summary>
static long GetCameraMatrix(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->GetCameraMatrix(*value);
});
}
static long GetCameraTarget(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->GetCameraTarget(*value);
});
}
static long GetPointerPosition(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->GetPointerPosition(*value);
});
}
static long GetViewConstructionPlane(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->GetViewConstructionPlane(*value);
});
}
static long GetViewExtents(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->GetViewExtents(*value);
});
}
static long GetViewFOV(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value,
[&](isink_t isink) { return GetInterface<IView>(isink)->GetViewFOV(*value); });
}
static long GetViewFrustum(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->GetViewFrustum(*value);
});
}
static long GetIsViewPerspective(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->GetIsViewPerspective(*value);
});
}
static long GetIsViewRotatable(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->GetIsViewRotatable(*value);
});
}
static long GetViewFocusDistance(navlib::param_t cookie, navlib::property_t property,
navlib::value_t *value) {
return GetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->GetViewFocusDistance(*value);
});
}
static long SetCameraMatrix(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->SetCameraMatrix(*value);
});
}
static long SetCameraTarget(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->SetCameraTarget(*value);
});
}
static long SetPointerPosition(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->SetPointerPosition(*value);
});
}
static long SetViewExtents(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->SetViewExtents(*value);
});
}
static long SetViewFOV(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value,
[&](isink_t isink) { return GetInterface<IView>(isink)->SetViewFOV(*value); });
}
static long SetViewFrustum(navlib::param_t cookie, navlib::property_t property,
const navlib::value_t *value) {
return SetValue(cookie, property, value, [&](isink_t isink) {
return GetInterface<IView>(isink)->SetViewFrustum(*value);
});
}
private:
/// <summary>
/// Read a <see cref="navlib::property_t"/> value from the navlib.
/// </summary>
/// <param name="nh">The <see cref="navlib::nlHandle_t"/> to the navigation library returned by
/// a previous call to <see cref="navlib::NlCreate"/>.</param>
/// <param name="name">The name of the navlib property to read.</param>
/// <param name="value">Pointer to a <see cref="navlib::value_t"/> to receive the value.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
long ReadValue(navlib::nlHandle_t nh, navlib::property_t name, navlib::value_t *value) const {
using namespace ::navlib;
try {
long resultCode = NlReadValue(nh, name, value);
#if defined(_DEBUG) && defined(TRACE_NAVLIB)
std::unique_lock<std::mutex> lock(s_mutex);
std::clog << "NlReadValue(0x" << std::hex << nh << std::dec << ", " << name << ", " << *value
<< ") result =0x" << std::hex << resultCode << std::endl;
#endif
return resultCode;
}
catch (const std::exception &e) {
std::unique_lock<std::mutex> lock(s_mutex);
std::cerr << "exception thrown in NlReadValue(0x" << std::hex << nh << std::dec
<< ", " << name << ", value)\n"
<< *value << " " << e.what() << std::endl;
}
return navlib::make_result_code(navlib::navlib_errc::error);
}
/// <summary>
/// Write a <see cref="navlib::property_t"/> value to the navlib.
/// </summary>
/// <param name="nh">The <see cref="navlib::nlHandle_t"/> to the navigation library returned by
/// a previous call to <see cref="navlib::NlCreate"/>.</param>
/// <param name="name">The name of the navlib property to read.</param>
/// <param name="value">Pointer to a <see cref="navlib::value_t"/> to receive the value.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
long WriteValue(navlib::nlHandle_t nh, navlib::property_t name,
const navlib::value_t *value) {
using namespace ::navlib;
try {
long resultCode = NlWriteValue(nh, name, value);
#if defined(_DEBUG) && defined(TRACE_NAVLIB)
std::unique_lock<std::mutex> lock(s_mutex);
std::clog << "NlWriteValue(0x" << std::hex << nh << std::dec << ", " << name << ", " << *value
<< ") result =0x" << std::hex << resultCode << std::endl;
#endif
return resultCode;
}
catch (const std::exception &e) {
std::unique_lock<std::mutex> lock(s_mutex);
std::cerr << "exception thrown in NlWriteValue(0x" << std::hex << nh << std::dec
<< ", " << name << ", value)\n"
<< *value << " " << e.what() << std::endl;
}
return navlib::make_result_code(navlib::navlib_errc::error);
}
#if defined(WAMP_CLIENT) && (WAMP_CLIENT == 1)
private:
long NlCreate(navlib::nlHandle_t* nh, const char *appname,
const navlib::accessor_t property_accessors[], size_t accessor_count,
const navlib::nlCreateOptions_t *options) {
if (nh == nullptr) {
return navlib::make_result_code(navlib::navlib_errc::invalid_argument);
}
return m_session->NlCreate(*nh, appname, property_accessors, accessor_count, options);
}
long NlClose(navlib::nlHandle_t nh) {
return m_session->NlClose(nh);
}
long NlReadValue(navlib::nlHandle_t nh, navlib::property_t name, navlib::value_t *value) const {
if (value == nullptr) {
return navlib::make_result_code(navlib::navlib_errc::invalid_argument);
}
if (!m_session->is_running()) {
throw std::system_error(navlib::make_error_code(navlib::navlib_errc::invalid_operation),
"No active NL-Session.");
}
return m_session->NlReadValue(nh, name, *value);
}
long NlWriteValue(navlib::nlHandle_t nh, navlib::property_t name,
const navlib::value_t *value) {
if (value == nullptr) {
return navlib::make_result_code(navlib::navlib_errc::invalid_argument);
}
if (!m_session->is_running()) {
throw std::system_error(navlib::make_error_code(navlib::navlib_errc::invalid_operation),
"No active NL-Session.");
}
return m_session->NlWriteValue(nh, name, *value);
}
mutable std::shared_ptr<tdx::wamp::client::NlSession> m_session;
#endif
private:
navlib::nlHandle_t m_hdl;
std::mutex m_mutex;
navlib::param_t m_cookie;
std::string m_name;
navlib::nlCreateOptions_t m_createOptions;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // CNavigationModelImpl_HPP_INCLUDED

View File

@@ -0,0 +1,44 @@
#ifndef IAccessors_HPP_INCLUDED
#define IAccessors_HPP_INCLUDED
// <copyright file="IAccessors.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: IAccessors.hpp 16047 2019-04-05 12:51:24Z mbonk $
//
// </history>
#include <SpaceMouse/IEvents.hpp>
#include <SpaceMouse/IHit.hpp>
#include <SpaceMouse/IModel.hpp>
#include <SpaceMouse/IPivot.hpp>
#include <SpaceMouse/ISpace3D.hpp>
#include <SpaceMouse/IState.hpp>
#include <SpaceMouse/IView.hpp>
namespace TDx {
namespace SpaceMouse {
namespace Navigation3D {
/// <summary>
/// The accessor interface to the client 3D properties.
/// </summary>
class IAccessors : public ISpace3D,
public IView,
public IModel,
public IPivot,
public IHit,
public IEvents,
public IState {};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // IAccessors_HPP_INCLUDED

View File

@@ -0,0 +1,33 @@
#ifndef IActionAccessors_HPP_INCLUDED
#define IActionAccessors_HPP_INCLUDED
// <copyright file="IActionAccessors.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id$
//
// </history>
#include <SpaceMouse/IEvents.hpp>
namespace TDx {
namespace SpaceMouse {
namespace ActionInput {
/// <summary>
/// The accessor interface to the client action input properties.
/// </summary>
class IActionAccessors : public Navigation3D::IEvents {
};
} // namespace ActionInput
} // namespace SpaceMouse
} // namespace TDx
#endif // IActionAccessors_HPP_INCLUDED

View File

@@ -0,0 +1,74 @@
#ifndef IEvents_HPP_INCLUDED
#define IEvents_HPP_INCLUDED
// <copyright file="IEvents.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: IEvents.hpp 16047 2019-04-05 12:51:24Z mbonk $
//
// </history>
// navlib
#include <navlib/navlib_types.h>
//stdlib
#include <string>
namespace TDx {
namespace SpaceMouse {
namespace Navigation3D {
/// <summary>
/// The Events interface
/// </summary>
class IEvents {
public:
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
virtual ~IEvents() = default;
#else
virtual ~IEvents() = 0 {
}
#endif
/// <summary>
/// Is called when the user invokes an application command from the SpaceMouse.
/// </summary>
/// <param name="commandId">The id of the command to invoke.</param>
/// <returns>The result of the function: 0 = no error, otherwise &lt;0.</returns>
virtual long SetActiveCommand(std::string commandId) = 0;
/// <summary>
/// Is called when the navigation settings change.
/// </summary>
/// <param name="count">The change count.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetSettingsChanged(long count) = 0;
/// <summary>
/// Is invoked when the user releases a key on the 3D Mouse, which has been programmed to send a
/// virtual key code.
/// </summary>
/// <param name="vkey">The virtual key code of the key pressed.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetKeyPress(long vkey) = 0;
/// <summary>
/// Is invoked when the user releases a key on the 3D Mouse, which has been programmed to send a
/// virtual key code.
/// </summary>
/// <param name="vkey">The virtual key code of the key released.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetKeyRelease(long vkey) = 0;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // IEvents_HPP_INCLUDED

View File

@@ -0,0 +1,74 @@
#ifndef IHit_HPP_INCLUDED
#define IHit_HPP_INCLUDED
// <copyright file="IHit.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: IHit.hpp 16047 2019-04-05 12:51:24Z mbonk $
//
// </history>
#include <navlib/navlib_types.h>
namespace TDx {
namespace SpaceMouse {
namespace Navigation3D {
/// <summary>
/// The hit-testing interface.
/// </summary>
class IHit {
public:
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
virtual ~IHit() = default;
#else
virtual ~IHit() = 0 {
}
#endif
/// <summary>
/// Is called when the navigation library queries the result of the hit-testing.
/// </summary>
/// <param name="position">The hit <see cref="navlib::point_t"/> in world coordinates.</param>
/// <returns>0 =no error, otherwise &lt;0 <see cref="navlib::make_result_code"/>.</returns>
virtual long GetHitLookAt(navlib::point_t &position) const = 0;
/// <summary>
/// Is called when the navigation library sets the aperture of the hit-testing ray/cone.
/// </summary>
/// <param name="aperture">The aperture of the ray/cone on the near plane.</param>
/// <returns>0 =no error, otherwise &lt;0 <see cref="navlib::make_result_code"/>.</returns>
virtual long SetHitAperture(double aperture) = 0;
/// <summary>
/// Is called when the navigation library sets the direction of the hit-testing ray/cone.
/// </summary>
/// <param name="direction">The <see cref="navlib::vector_t"/> direction of the ray/cone.</param>
/// <returns>0 =no error, otherwise &lt;0 <see cref="navlib::make_result_code"/>.</returns>
virtual long SetHitDirection(const navlib::vector_t& direction) = 0;
/// <summary>
/// Is called when the navigation library sets the source of the hit-testing ray/cone.
/// </summary>
/// <param name="eye">The source <see cref="navlib::point_t"/> of the hit cone.</param>
/// <returns>0 =no error, otherwise &lt;0 <see cref="navlib::make_result_code"/>.</returns>
virtual long SetHitLookFrom(const navlib::point_t& eye) = 0;
/// <summary>
/// Is called when the navigation library sets the selection filter for hit-testing.
/// </summary>
/// <param name="onlySelection">true = ignore non-selected items.</param>
/// <returns>0 =no error, otherwise &lt;0 <see cref="navlib::make_result_code"/>.</returns>
virtual long SetHitSelectionOnly(bool onlySelection) = 0;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // IHit_HPP_INCLUDED

View File

@@ -0,0 +1,102 @@
#ifndef IModel_HPP_INCLUDED
#define IModel_HPP_INCLUDED
// <copyright file="IModel.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: IModel.hpp 16047 2019-04-05 12:51:24Z mbonk $
//
// </history>
#include <navlib/navlib_types.h>
namespace TDx {
namespace SpaceMouse {
namespace Navigation3D {
/// <summary>
/// The Model interface
/// </summary>
class IModel {
public:
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
virtual ~IModel() = default;
#else
virtual ~IModel() = 0 {
}
#endif
/// <summary>
/// Is called when the navigation library needs to get the extents of the model.
/// </summary>
/// <param name="extents">A <see cref="navlib::box_t"/> representing the extents of the
/// model.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetModelExtents(navlib::box_t &extents) const = 0;
/// <summary>
/// Is called when the navigation library needs to get the extents of the selection.
/// </summary>
/// <param name="extents">A <see cref="navlib::box_t"/> representing the extents of the
/// selection.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetSelectionExtents(navlib::box_t &extents) const = 0;
/// <summary>
/// Is called to get the selections's transform <see cref="navlib::matrix_t"/>.
/// </summary>
/// <param name="transform">The world affine <see cref="navlib::matrix_t"/> of the
/// selection.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetSelectionTransform(navlib::matrix_t &transform) const = 0;
/// <summary>
/// Is called to query if the selection is empty.
/// </summary>
/// <param name="empty">true if nothing is selected.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetIsSelectionEmpty(navlib::bool_t &empty) const = 0;
/// <summary>
/// Is called to set the selections's transform <see cref="navlib::matrix_t"/>.
/// </summary>
/// <param name="matrix">The world affine <see cref="navlib::matrix_t"/> of the selection.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetSelectionTransform(const navlib::matrix_t& matrix) = 0;
/// <summary>
/// Is called to retrieve the length of the model/world units in meters.
/// </summary>
/// <param name="meters">The length of a model/world unit in meters.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>
/// <para>The conversion factor is used by the Navigation Library to calculate the height above
/// the floor in walk mode and the speed in the first-person motion model.</para>
/// <para>The Navigation Library assumes that this value does not change and it is only queried
/// once.</para>
/// </remarks>
virtual long GetUnitsToMeters(double &meters) const = 0;
/// <summary>
/// Is called to retrieve the plane equation of the floor.
/// </summary>
/// <param name="floor">The plane equation of the floor plane.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>
/// <para>The plane equation is used by the Navigation Library to determine the floor for the
/// walk navigation mode, where the height of the eye is fixed to 1.5m above the floor plane.
/// The floor need not be parallel to the world ground plane.</para>
/// </remarks>
virtual long GetFloorPlane(navlib::plane_t &floor) const = 0;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // IModel_HPP_INCLUDED

View File

@@ -0,0 +1,98 @@
#ifndef INavlib_HPP_INCLUDED
#define INavlib_HPP_INCLUDED
// <copyright file="INavlib.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: INavlib.hpp 16047 2019-04-05 12:51:24Z mbonk $
//
// </history>
#include <navlib/navlib_types.h>
// stdlib
#include <string>
namespace TDx {
namespace SpaceMouse {
namespace Navigation3D {
/// <summary>
/// The interface to access the navigation library properties.
/// </summary>
class INavlibProperty {
public:
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
virtual ~INavlibProperty() = default;
#else
virtual ~INavlibProperty() = 0 {
}
#endif
/// <summary>
/// Writes the value of a property to the navlib.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// write.</param>
/// <param name="value">The <see cref="navlib::value"/> to write.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
virtual long Write(const std::string &propertyName, const navlib::value &value) = 0;
/// <summary>
/// Reads the value of a navlib property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="value">The <see cref="navlib::value"/> to read.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib / 3D Mouse.</exception>
virtual long Read(const std::string &propertyName, navlib::value &value) const = 0;
/// <summary>
/// Reads the value of a navlib string property.
/// </summary>
/// <param name="propertyName">The <see cref="navlib::property_t"/> name of the navlib property to
/// read.</param>
/// <param name="string">The <see cref="std::string"/> value of the property.</param>
/// <returns>0 =no error, otherwise a value from <see cref="navlib::make_result_code"/>.</returns>
/// <exception cref="std::system_error">No connection to the navlib.</exception>
virtual long Read(const std::string &propertyName, std::string &string) const = 0;
};
/// <summary>
/// The interface to access the navigation library.
/// </summary>
class INavlib : public INavlibProperty {
public:
/// <summary>
/// Close the connection to the 3D navigation library.
/// </summary>
virtual void Close() = 0;
/// <summary>
/// Opens a connection to the 3D navigation library.
/// </summary>
virtual void Open() = 0;
/// <summary>
/// Opens a connection to the 3D navigation library
/// </summary>
/// <param name="profileName">The name of the 3Dconnexion profile to use.</param>
/// <exception cref="std::system_error">The connection to the library is already open.</exception>
/// <exception cref="std::system_error">Cannot create a connection to the library.</exception>
/// <exception cref="std::invalid_argument">The name of the profile is empty.</exception>
virtual void Open(std::string profileName) = 0;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // INavlib_HPP_INCLUDED

View File

@@ -0,0 +1,74 @@
#ifndef IPivot_HPP_INCLUDED
#define IPivot_HPP_INCLUDED
// <copyright file="IPivot.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: IPivot.hpp 16047 2019-04-05 12:51:24Z mbonk $
//
// </history>
#include <navlib/navlib_types.h>
namespace TDx {
namespace SpaceMouse {
namespace Navigation3D {
/// <summary>
/// The interface to access the pivot.
/// </summary>
class IPivot {
public:
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
virtual ~IPivot() = default;
#else
virtual ~IPivot() = 0 {
}
#endif
/// <summary>
/// Gets the position of the rotation pivot.
/// </summary>
/// <param name="position">The pivot <see cref="navlib::point_t"/> in world coordinates.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetPivotPosition(navlib::point_t &position) const = 0;
/// <summary>
/// Queries if the user has manually set a pivot point.
/// </summary>
/// <param name="userPivot">true if the user has set a pivot otherwise false.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long IsUserPivot(navlib::bool_t &userPivot) const = 0;
/// <summary>
/// Sets the position of the rotation pivot.
/// </summary>
/// <param name="position">The pivot <see cref="navlib::point_t"/> in world coordinates.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetPivotPosition(const navlib::point_t& position) = 0;
/// <summary>
/// Queries the visibility of the pivot image.
/// </summary>
/// <param name="visible">true if the pivot is visible otherwise false.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetPivotVisible(navlib::bool_t &visible) const = 0;
/// <summary>
/// Sets the visibility of the pivot image.
/// </summary>
/// <param name="visible">true if the pivot is visible otherwise false.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetPivotVisible(bool visible) = 0;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // IPivot_HPP_INCLUDED

View File

@@ -0,0 +1,55 @@
#ifndef ISpace3D_HPP_INCLUDED
#define ISpace3D_HPP_INCLUDED
// <copyright file="ISpace3D.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: ISpace3D.hpp 16047 2019-04-05 12:51:24Z mbonk $
//
// </history>
#include <navlib/navlib_types.h>
namespace TDx {
namespace SpaceMouse {
namespace Navigation3D {
/// <summary>
/// The interface to access the client coordinate system.
/// </summary>
class ISpace3D {
public:
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
virtual ~ISpace3D() = default;
#else
virtual ~ISpace3D() = 0 {
}
#endif
/// <summary>
/// Gets the coordinate system used by the client.
/// </summary>
/// <param name="matrix">The coordinate system <see cref="navlib::matrix_t"/>.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>The matrix describes the applications coordinate frame in the navlib coordinate
/// system. i.e. the application to navlib transform.</remarks>
virtual long GetCoordinateSystem(navlib::matrix_t &matrix) const = 0;
/// <summary>
/// Gets the orientation of the front view.
/// </summary>
/// <param name="matrix">The front view transform <see cref="navlib::matrix_t"/>.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetFrontView(navlib::matrix_t &matrix) const = 0;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // ISpace3D_HPP_INCLUDED

View File

@@ -0,0 +1,54 @@
#ifndef IState_HPP_INCLUDED
#define IState_HPP_INCLUDED
// <copyright file="IState.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: IState.hpp 16047 2019-04-05 12:51:24Z mbonk $
//
// </history>
#include <navlib/navlib_types.h>
namespace TDx {
namespace SpaceMouse {
namespace Navigation3D {
/// <summary>
/// Interface to access the navigation state.
/// </summary>
class IState {
public:
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
virtual ~IState() = default;
#else
virtual ~IState() = 0 {
}
#endif
/// <summary>
/// Is called when the navigation library starts or stops a navigation transaction.
/// </summary>
/// <param name="transaction">The transaction number: >0 begin, ==0 end.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetTransaction(long transaction) = 0;
/// <summary>
/// Is called when the navigation instance starts or stops a sequence of motion frames.
/// </summary>
/// <param name="motion">The motion flag: true = start, false = end.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>This can be used to start an animation loop.</remarks>
virtual long SetMotionFlag(bool motion) = 0;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // IState_HPP_INCLUDED

View File

@@ -0,0 +1,156 @@
#ifndef IView_HPP_INCLUDED
#define IView_HPP_INCLUDED
// <copyright file="IView.hpp" company="3Dconnexion">
// ------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// ------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// ************************************************************************************************
// File History
//
// $Id: IView.hpp 16047 2019-04-05 12:51:24Z mbonk $
//
// </history>
#include <navlib/navlib_types.h>
namespace TDx {
namespace SpaceMouse {
namespace Navigation3D {
/// <summary>
/// View callback interface.
/// </summary>
class IView {
public:
#if !defined(_MSC_VER) || (_MSC_VER > 1700)
virtual ~IView() = default;
#else
virtual ~IView() = 0 {
}
#endif
/// <summary>
/// Gets the camera matrix of the view.
/// </summary>
/// <param name="matrix">The camera/view <see cref="navlib::matrix_t"/>.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetCameraMatrix(navlib::matrix_t &matrix) const = 0;
/// <summary>
/// Gets the camera's target point.
/// </summary>
/// <param name="target">The position of the camera target in world coordinates.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>Free cameras do not have a target.</remarks>
virtual long GetCameraTarget(navlib::point_t &target) const = 0;
/// <summary>
/// Gets the position of the pointer on the near clipping plane.
/// </summary>
/// <param name="position">The <see cref="navlib::point_t"/> in world coordinates of the
/// pointer.</param> <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetPointerPosition(navlib::point_t &position) const = 0;
/// <summary>
/// Gets the view's construction plane.
/// </summary>
/// <param name="plane">The plane equation of the construction plane.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetViewConstructionPlane(navlib::plane_t &plane) const = 0;
/// <summary>
/// Gets the extents of the view.
/// </summary>
/// <param name="extents">A <see cref="navlib::box_t"/> representing the extents of the
/// view.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetViewExtents(navlib::box_t &extents) const = 0;
/// <summary>
/// Gets the camera's/view's distance to the focused object.
/// </summary>
/// <param name="fov">The distance in world units.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetViewFocusDistance(double &distance) const = 0;
/// <summary>
/// Gets the camera's/view's field of view.
/// </summary>
/// <param name="fov">The field of view in radians.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetViewFOV(double &fov) const = 0;
/// <summary>
/// Gets the camera/view frustum.
/// </summary>
/// <param name="frustum">The camera/view <see cref="navlib::frustum_t"/>.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetViewFrustum(navlib::frustum_t &frustum) const = 0;
/// <summary>
/// Get's the view's projection type
/// </summary>
/// <param name="perspective">true for a perspective view, false for an orthographic view.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetIsViewPerspective(navlib::bool_t &perspective) const = 0;
/// <summary>
/// Gets a value indicating whether the view can be rotated.
/// </summary>
/// <param name="isRotatable">true if the view can be rotated, false otherwise.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long GetIsViewRotatable(navlib::bool_t &isRotatable) const = 0;
/// <summary>
/// Sets the camera affine matrix.
/// </summary>
/// <param name="matrix">The camera/view <see cref="navlib::matrix_t"/>.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetCameraMatrix(const navlib::matrix_t& matrix) = 0;
/// <summary>
/// Sets the camera's target position.
/// </summary>
/// <param name="target">The position of the camera target in world coordinates.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
/// <remarks>Free cameras do not have a target.</remarks>
virtual long SetCameraTarget(const navlib::point_t &target) = 0;
/// <summary>
/// Sets the position of the pointer on the near clipping plane.
/// </summary>
/// <param name="position">The <see cref="navlib::point_t"/> in world coordinates of the
/// pointer.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetPointerPosition(const navlib::point_t& position) = 0;
/// <summary>
/// Sets the extents of the view.
/// </summary>
/// <param name="extents">A <see cref="navlib::box_t"/> representing the extents of the
/// view.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetViewExtents(const navlib::box_t& extents) = 0;
/// <summary>
/// Sets the camera's/view's field of view.
/// </summary>
/// <param name="fov">The field of view in radians.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetViewFOV(double fov) = 0;
/// <summary>
/// Sets the camera/view frustum.
/// </summary>
/// <param name="frustum">The camera/view <see cref="navlib::frustum_t"/>.</param>
/// <returns>0 = no error, otherwise &lt;0.</returns>
virtual long SetViewFrustum(const navlib::frustum_t& frustum) = 0;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // IView_HPP_INCLUDED

View File

@@ -0,0 +1,672 @@
#ifndef NAVLIB_H_INCLUDED_
#define NAVLIB_H_INCLUDED_
// <copyright file="navlib.h" company="3Dconnexion">
// -------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// -------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// *************************************************************************************************
// File History
//
// $Id: navlib.h 19940 2023-01-25 07:17:44Z mbonk $
//
// 01/23/14 MSB Initial design
// </history>
// <description>
// *************************************************************************************************
// File Description
//
// This header file describes the interface for navigating in a 2D or 3D view.
//
// *************************************************************************************************
// </description>
#include <navlib/navlib_types.h>
/// <summary>
/// Contains the navigation library API types and functions
/// </summary>
/// <remarks>
/// The functions and types describe an interface for navigating in a 2D or 3D view.
/// <para>
/// In this scheme, a 3dconnexion library is responsible for calculating the position of the camera
/// viewing the scene or object as well as displaying the settings and for supporting user
/// customization.
/// </para>
/// <para>
/// The application is responsible for passing the description of an interface of the 2D/3D view to
/// the 3dconnexion library, and for reacting to the changes to the properties identified by the
/// 3dconnexion library.
/// </para>
/// </remarks>
NAVLIB_BEGIN_
// ************************************************************************************************
// Properties
/// <summary>
/// Property set by the client to indicate that the connection is currently active.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="bool_t"/> and <see cref="propertyType_t"/> is
/// <see cref="bool_type"/>.</para>
/// <para>Clients that have multiple navigation instances open need to inform the navlib which of
/// them is the target for 3D Mouse input. They do this by setting the active_k property of a
/// navigation instance to true.</para>
/// </remarks>
static const property_t active_k = "active";
/// <summary>
/// Property that a client sets to indicate it has keyboard focus.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="bool_t"/> and <see cref="propertyType_t"/> is
/// <see cref="bool_type"/>.</para>
/// <para>Clients that run in container applications via the NLServer proxy set this property to
/// indicate keyboard focus. This will set 3DMouse focus to the navlib connection.</para>
/// </remarks>
static const property_t focus_k = "focus";
/// <summary>
/// Client property that the navlib sets when a motion model is active.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="bool_t"/> and <see cref="propertyType_t"/> is
/// <see cref="bool_type"/>.</para>
/// <para>The motion_k property is set to true by the navlib to notify
/// the client that it is executing a motion model and will update the camera matrix regularly. This
/// is useful for clients that need to run an animation loop. When the navlib has finished
/// navigating the camera position it will set the property to false. By setting motion_k to false,
/// a client may temporarily interrupt a navigation communication and force the Navlib to
/// reinitialize the navigation.</para>
/// </remarks>
static const property_t motion_k = "motion";
/// <summary>
/// Specifies the transform from the client's coordinate system to the navlib coordinate system.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="matrix_t"/> and <see cref="propertyType_t"/> is
/// <see cref="matrix_type"/>.</para>
/// <para>The Navigation Library coordinate system is Y up, X to the right and Z out of the screen.
/// This property is queried directly after new navigation instance is created. This allows the
/// client to specify the other properties using the coordinate system used in the client. For the
/// keep Y up ('Lock Horizon') algorithm to work correctly a non-identity matrix needs to be
/// specified whenever the ground plane is not the X-Z plane.</para>
/// </remarks>
static const property_t coordinate_system_k = "coordinateSystem";
/* Frame properties*/
/// <summary>
/// Specifies the begin and end of a navigation transaction.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="long"/> and <see cref="propertyType_t"/> is
/// <see cref="long_type"/>.</para>
/// <para>The Navigation Library can set more than one client property for a single navigation
/// frame. For example when navigating in an orthographic projection possibly both the view affine
/// and extents will be modified depending on the 3DMouse input. The Navigation Library sets the
/// transaction_k property to a value >0 at the beginning of a navigation frame and to 0 at the end.
/// Clients that need to actively refresh the view can trigger the refresh when the value is set to
/// 0.</para>
/// </remarks>
static const property_t transaction_k = "transaction";
/// <summary>
/// Specifies the time stamp of an animation frame in milliseconds.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="double"/> and <see cref="propertyType_t"/> is
/// <see cref="double_type"/>.</para>
/// <para>When the frame_timing_source_k property is set to 1, the client initiates a frame
/// transaction by informing the Navigation Library of the frame time. When the value is 0, the
/// Navigation Library attempts to synchronize the frames to the monitor vertical blanking
/// rate.</para>
/// </remarks>
static const property_t frame_time_k = "frame.time";
/// <summary>
/// Specifies the source of the frame timing.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="long"/> and <see cref="propertyType_t"/> is
/// <see cref="long_type"/>.</para>
/// <para>By setting the frame_timing_source_k property to 1, the client application informs the
/// Navigation Library that the client has an animation loop and will be the source of the frame
/// timing.</para>
/// </remarks>
static const property_t frame_timing_source_k = "frame.timingSource";
/// <summary>
/// Specifies whether a device is present
/// </summary>
/// <remarks>
/// <para>The type is <see cref="bool_t"/> and <see cref="propertyType_t"/> is
/// <see cref="bool_type"/>.</para>
/// <para>Currently this always returns true.</para>
/// </remarks>
static const property_t device_present_k = "device.present";
/// <summary>
/// Defines a set of commands.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="SiActionNode_t"/>* and <see cref="propertyType_t"/> is
/// <see cref="actionnodeexptr_type"/>.</para>
/// <para>Command sets can be considered to be button banks. The set can be either the complete list
/// of commands that are available in the application or a single set of commands for a specific
/// application context. The navlib will not query the application for this property. It is the
/// responsibility of the application to update this property when commands are to be made available
/// to the user.</para>
/// </remarks>
static const property_t commands_tree_k = "commands.tree";
/// <summary>
/// The active command.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="string_t"/> and <see cref="propertyType_t"/> is
/// <see cref="string_type"/>.</para>
/// <para>When the user presses a 3DMouse button that has been assign an application command
/// exposed by the commands_tree_k property, the navlib will write this property. The string value
/// will be the corresponding id passed in the commands_tree_k property. Generally the navlib will
/// set this property to an empty string when the corresponding button has been released.</para>
/// </remarks>
static const property_t commands_activeCommand_k = "commands.activeCommand";
/// <summary>
/// Specifies the active set of commands.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="string_t"/> and <see cref="propertyType_t"/> is
/// <see cref="string_type"/>.</para>
/// <para>In applications that have exposed multiple command sets this property needs to be set to
/// define the command set that is active. The navlib will not query the application for this
/// property. It is the responsibility of the application to update this property when the set of
/// commands need to be changed. Normally this will be due to change in application state and may
/// correspond to a menu/toolbar change. If only a single set of commands has been defined, this
/// property defaults to that set.</para>
/// </remarks>
static const property_t commands_activeSet_k = "commands.activeSet";
/// <summary>
/// Specifies an array of images for the 3Dconnexion UI.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="imagearray_t"/> and <see cref="propertyType_t"/> is
/// <see cref="imagearray_type"/>.</para>
/// <para>An image with the same <see cref="SiImage_t.id"/> as a command
/// <see cref="SiActionNodeEx_t.id"/> will be associated with that command in the 3Dconnexion
/// UI.</para>
/// </remarks>
static const property_t images_k = "images";
/* view properties */
/// <summary>
/// Specifies the transformation matrix of the view camera.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="matrix_t"/> and <see cref="propertyType_t"/> is
/// <see cref="matrix_type"/>.</para>
/// <para>This matrix specifies the camera to world transformation of the view. That is,
/// transforming the position (0, 0, 0) by this matrix yields the position of the camera in world
/// coordinates. The navlib will, generally, query this matrix at the beginning of a navigation
/// action and then set the property once per frame.</para>
/// </remarks>
static const property_t view_affine_k = "view.affine";
/// <summary>
/// Specifies the plane equation of the construction plane.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="plane_t"/> and <see cref="propertyType_t"/> is
/// <see cref="plane_type"/>.</para>
/// <para>The plane equation is used by the Navigation Library to distinguish views used for
/// construction in orthographic projections: typically the top, right left etc. views. The
/// Navigation Library assumes that when the camera's look-at axis is parallel to the plane normal,
/// the view should not be rotated.</para>
/// </remarks>
static const property_t view_constructionPlane_k = "view.constructionPlane";
/// <summary>
/// Specifies the orthographic extents of the view in camera coordinates.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="box_t"/> and <see cref="propertyType_t"/> is
/// <see cref="box_type"/>.</para>
/// <para>The orthographic extents of the view are returned as a bounding box in world units
/// relative to the camera/view frame. The view frame is a right-handed coordinate system centered
/// on the view with x to the right and y up. The Navigation Library will only access this property
/// if the view is orthographic.</para>
/// </remarks>
static const property_t view_extents_k = "view.extents";
/// <summary>
/// Specifies the vertical field-of-view of a perspective camera/view in radians.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="double"/> and <see cref="propertyType_t"/> is
/// <see cref="double_type"/>.</para>
/// </remarks>
static const property_t view_fov_k = "view.fov";
/// <summary>
/// Specifies the frustum of a perspective camera/view in camera coordinates.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="frustum_t"/> and <see cref="propertyType_t"/> is
/// <see cref="frustum_type"/>.</para>
/// <para>The navlib uses this property to calculate the field-of-view of the perspective camera.
/// The frustum is also used in algorithms that need to determine if the model is currently visible.
/// The navlib will not write to this property. Instead, if necessary, the navlib will write to the
/// <see cref="view_fov_k"/> property and leave the client to change the frustum as it
/// wishes.</para>
/// </remarks>
static const property_t view_frustum_k = "view.frustum";
/// <summary>
/// Specifies whether the projection type of the view/camera is perspective.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="bool_t"/> and <see cref="propertyType_t"/> is
/// <see cref="bool_type"/>.</para>
/// <para>This property defaults to true. If the client does not supply a function for the navlib to
/// query the view's projection (which it will generally do at the onset of motion), then it must
/// set the property in the navlib if the projection is orthographic or when it changes.</para>
/// </remarks>
static const property_t view_perspective_k = "view.perspective";
/// <summary>
/// Specifies the position of the target of the view/camera.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="point_t"/> and <see cref="propertyType_t"/> is
/// <see cref="point_type"/>.</para>
/// <para>The view interest.</para>
/// </remarks>
static const property_t view_target_k = "view.target";
/// <summary>
/// Specifies whether the view can be rotated.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="bool_t"/> and <see cref="propertyType_t"/> is
/// <see cref="bool_type"/>.</para>
/// <para>This property is generally used to differentiate between orthographic 3D views and views
/// that can only be panned and zoomed such as plan views.</para>
/// </remarks>
static const property_t view_rotatable_k = "view.rotatable";
/// <summary>
/// Specifies the distance between the view camera and the object the user is focused on.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="double"/> and <see cref="propertyType_t"/> is
/// <see cref="double_type"/>.</para>
/// <para>This property is used to define the distance to the users object of interest and determines
/// the translation speed sensitivity of the camera or SpaceMouse. </para>
/// </remarks>
static const property_t view_focusDistance_k = "view.focusDistance";
/// <summary>
/// Specifies the orientation of the view designated as the front view.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="matrix_t"/> and <see cref="propertyType_t"/> is
/// <see cref="matrix_type"/>.</para>
/// <para>The Navigation Library will only query the value of this property when the connection is
/// created. It is used to orientate the model to one of the 'Front', 'Back', 'Right', 'Left' etc.
/// views in response to the respective pre-defined view commands. If the orientation of the front
/// view is redefined after the connection is opened by the user, the client application is required
/// to update the property to the new value.</para>
/// </remarks>
static const property_t views_front_k = "views.front";
/// <summary>
/// Specifies the position of the rotation pivot.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="point_t"/> and <see cref="propertyType_t"/> is
/// <see cref="point_type"/>.</para>
/// <para>The Navigation Library will generally set <see cref="pivot_position_k"/> property when
/// navigation ends. The position will depend on which pivot model is being used. The application
/// can set the pivot to a fix position by setting this property. A side effect of the application
/// setting the property is that the <see cref="pivot_user_k"/> property is set to true.</para>
/// </remarks>
static const property_t pivot_position_k = "pivot.position";
/// <summary>
/// Specifies whether the position of the rotation pivot is set by the user.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="bool_t"/> and <see cref="propertyType_t"/> is
/// <see cref="point_type"/>.</para>
/// <para>With the property set to true, the Navigation Library will disable the internal pivot
/// position algorithms.</para>
/// </remarks>
static const property_t pivot_user_k = "pivot.user";
/// <summary>
/// Specifies whether the rotation pivot widget is visible.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="bool_t"/> and <see cref="propertyType_t"/> is
/// <see cref="bool_type"/>.</para>
/// <para>Set by the Navigation Library when it wants to set the visibility of the pivot used for
/// the 3D navigation. This will be dependent on the user setting for the pivot visibility in the
/// 3Dconnexion Settings configuration and whether the Navigation Library is actively navigating
/// the scene.</para>
/// </remarks>
static const property_t pivot_visible_k = "pivot.visible";
/// <summary>
/// Specifies the origin of the ray used for hit-testing.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="point_t"/> and <see cref="propertyType_t"/> is
/// <see cref="point_type"/>.</para>
/// <para>Set by the Navigation Library. The location is relative to the world coordinate
/// system.</para>
/// </remarks>
static const property_t hit_lookfrom_k = "hit.lookfrom";
/// <summary>
/// Specifies the direction of the ray used for hit-testing.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="vector_t"/> and <see cref="propertyType_t"/> is
/// <see cref="vector_type"/>.</para>
/// <para>Set by the Navigation Library. The direction is relative to the world coordinate
/// system frame.</para>
/// </remarks>
static const property_t hit_direction_k = "hit.direction";
/// <summary>
/// Specifies the diameter of the ray used for hit-testing.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="double"/> and <see cref="propertyType_t"/> is
/// <see cref="double_type"/>.</para>
/// <para>Set by the Navigation Library. This is the diameter of the aperture on the frustum near
/// plane. In a perspective project the ray is a cone.</para>
/// </remarks>
static const property_t hit_aperture_k = "hit.aperture";
/// <summary>
/// Specifies the point of the model that is hit by the ray originating from
/// <see cref="hit_lookfrom_k"/>.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="point_t"/> and <see cref="propertyType_t"/> is
/// <see cref="point_type"/>.</para>
/// <para>This property is queried by the navlib. The navlib will generally calculate if it is
/// possible to hit a part of the model from the <see cref="model_extents_k"/> and
/// <see cref="selection_extents_k"/> properties before setting up the hit-test properties and
/// querying the property. The position is relative to the world coordinate system frame.</para>
/// </remarks>
static const property_t hit_lookat_k = "hit.lookat";
/// <summary>
/// Specifies whether the hit-testing is limited solely to the current selection set.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="bool_t"/> and <see cref="propertyType_t"/> is
/// <see cref="bool_type"/>.</para>
/// </remarks>
static const property_t hit_selectionOnly_k = "hit.selectionOnly";
/// <summary>
/// Specifies the transformation matrix of the selection set.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="matrix_t"/> and <see cref="propertyType_t"/> is
/// <see cref="matrix_type"/>.</para>
/// <para>This matrix specifies the object to world transformation of the selection set. That is,
/// transforming the position (0, 0, 0) by this matrix yields the position of the set in world
/// coordinates. The navlib will, generally, query this matrix at the beginning of a navigation
/// action that involves moving the selection and then set the property once per frame.</para>
/// </remarks>
static const property_t selection_affine_k = "selection.affine";
/// <summary>
/// Specifies whether the selection set is empty.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="bool_t"/> and <see cref="propertyType_t"/> is
/// <see cref="bool_type"/>.</para>
/// <para>When true, nothing is selected.</para>
/// </remarks>
static const property_t selection_empty_k = "selection.empty";
/// <summary>
/// Specifies the bounding box of the selection set.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="box_t"/> and <see cref="propertyType_t"/> is
/// <see cref="box_type"/>.</para>
/// <para>The extents of the selection are returned as a bounding box in world coordinates. The
/// Navigation Library will only access this property if the <see cref="selection_empty_k"/>
/// property is false.</para>
/// </remarks>
static const property_t selection_extents_k = "selection.extents";
/// <summary>
/// Specifies the bounding box of the model.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="box_t"/> and <see cref="propertyType_t"/> is
/// <see cref="box_type"/>.</para>
/// </remarks>
static const property_t model_extents_k = "model.extents";
/// <summary>
/// Specifies the plane equation of the floor. /// </summary>
/// <remarks>
/// <para>The type is <see cref="plane_t"/> and <see cref="propertyType_t"/> is
/// <see cref="plane_type"/>.</para>
/// <para>The plane equation is used by the Navigation Library to determine the floor for the
/// walk navigation mode, where the height of the eye is fixed to 1.5m above the floor plane.
/// The floor need not be parallel to the world ground plane.</para>
/// Introduced in 3DxWare 10 version 10.8.12.</remarks>
static const property_t model_floorPlane_k = "model.floorPlane";
/// <summary>
/// Specifies the length of the model/world units in meters. /// </summary>
/// <remarks>
/// <para>The type is <see cref="double"/> and <see cref="propertyType_t"/> is
/// <see cref="double_type"/>.</para>
/// <para>The conversion factor is used by the Navigation Library to calculate the height above the
/// floor in walk mode and the speed in the first person motion model.</para>
/// Introduced in 3DxWare 10 version 10.8.12.</remarks>
static const property_t model_unitsToMeters_k = "model.unitsToMeters";
/// <summary>
/// Specifies the position of the mouse cursor. on the projection plane in world coordinates.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="point_t"/> and <see cref="propertyType_t"/> is
/// <see cref="point_type"/>.</para>
/// <para>The position of the mouse cursor is in world coordinates on the projection plane. For a
/// perspective projection the Navigation Library uses the near clipping as the projection plane.
/// In OpenGL the position would typically be retrieved using gluUnProject with winZ set to
/// 0.0.</para>
/// </remarks>
static const property_t pointer_position_k = "pointer.position";
/// <summary>
/// V3DK press event.
/// </summary>
static const property_t events_keyPress_k = "events.keyPress";
/// <summary>
/// V3DK release event.
/// </summary>
static const property_t events_keyRelease_k = "events.keyRelease";
/// <summary>
/// Used to query and apply settings in the 3Dconnexion Settings UI.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="string_t"/> and <see cref="propertyType_t"/> is
/// <see cref="string_type"/>.</para>
/// <para>The property settings_k does not actually exist in the Navigation Library. To read or
/// write a property to the application profile, the settings_k needs to be appended with "." and
/// the name of the profile property.<example>"settings.MoveObjects" is used to read or write the
/// value of the "MoveObjects" property in the profile settings.</example></para>
/// </remarks>
static const property_t settings_k = "settings";
/// <summary>
/// Specifies the change revision of the profile settings.
/// </summary>
/// <remarks>
/// <para>The type is <see cref="long"/> and <see cref="propertyType_t"/> is
/// <see cref="long_type"/>.</para>
/// <para>This property is incremented when the settings changed. The value is only valid for the
/// current connection to the Navigation Library and is not persistent over multiple sessions. If
/// the client needs to know the value of a 3Dconnexion profile setting it should re-read the value
/// when settings_changed_k is changed.</para>
/// </remarks>
static const property_t settings_changed_k = "settings.changed";
// Workaround for error C2099: initializer is not a constant when compiling .c
#if __cplusplus
/// <summary>
/// Defines the type of a property and the access required of the client application.
/// </summary>
static const propertyDescription_t propertyDescription[] = {
/* property, type, required client access */
{active_k, bool_type, eno_access},
{focus_k, bool_type, eno_access},
{motion_k, bool_type, ewrite_access},
{coordinate_system_k, matrix_type, eread_access},
{device_present_k, bool_type, eno_access},
{events_keyPress_k, long_type, ewrite_access},
{events_keyRelease_k, long_type, ewrite_access},
/* frame properties*/
{transaction_k, long_type, ewrite_access},
{frame_time_k, double_type, eread_access},
{frame_timing_source_k, long_type, eread_access},
/* view properties */
{view_affine_k, matrix_type, eread_write_access},
{view_constructionPlane_k, plane_type, eread_access},
{view_extents_k, box_type, eread_write_access},
{view_fov_k, float_type, eread_write_access},
{view_frustum_k, frustum_type, eread_access},
{view_perspective_k, bool_type, eread_access},
{view_rotatable_k, bool_type, eread_access},
{view_target_k, point_type, eread_access},
{view_focusDistance_k, float_type, eread_access},
/* views properties*/
{views_front_k, matrix_type, eread_access},
/* pivot properties */
{pivot_position_k, point_type, eread_write_access},
{pivot_user_k, bool_type, eno_access},
{pivot_visible_k, bool_type, ewrite_access},
/* hit-test properties */
{hit_lookfrom_k, point_type, ewrite_access},
{hit_direction_k, vector_type, ewrite_access},
{hit_aperture_k, float_type, ewrite_access},
{hit_lookat_k, point_type, eread_access},
{hit_selectionOnly_k, bool_type, ewrite_access},
/* selection properties */
{selection_affine_k, matrix_type, eread_write_access},
{selection_empty_k, bool_type, eread_access},
{selection_extents_k, box_type, eread_access},
/* model properties */
{model_extents_k, box_type, eread_access},
{model_floorPlane_k, plane_type, eread_access},
{model_unitsToMeters_k, float_type, eread_access},
/* pointer (cursor) properties */
{pointer_position_k, point_type, eread_access},
/* commands properties */
{commands_tree_k, actionnodeexptr_type, eno_access},
{commands_activeSet_k, string_type, eno_access},
{commands_activeCommand_k, string_type, ewrite_access},
/* images properties*/
{images_k, imagearray_type, eno_access},
/* settings property*/
{settings_k, string_type, eno_access},
{settings_changed_k, long_type, ewrite_access}};
#endif
/**********************************************************************************************
Functions exported from the library
**********************************************************************************************/
/// <summary>
/// Creates a new navigation instance.
/// </summary>
/// <remarks>The client specifies the name of the instance and the properties that are available
/// for querying and updating by the navigation framework.</remarks>
/// <param name="pnh">A pointer to a <see cref="nlHandle_t"/> for the new navigation
/// instance.</param>
/// <param name="appname">The name of the application.</param>
/// <param name="property_accessors">An array of <see cref="accessor_t"/> structures containing the
/// property name, accessor and mutator functions that the client exposes to the navigation
/// instance.</param>
/// <param name="accessor_count">The number of <see cref="accessor_t"/> entries passed in the
/// property_accessors parameter.</param>
/// <param name="options">Pointer to a <see cref="nlCreateOptions_t"/>. This parameter is optional
/// and may be null.</param>
/// <returns>0 on success or a navlib error, see <see cref="navlib_errc::navlib_errc_t"/> and
/// <see cref="make_result_code"/>.</returns>
NAVLIB_DLLAPI_ long __cdecl NlCreate(nlHandle_t *pnh, const char *appname,
const accessor_t property_accessors[], size_t accessor_count,
const nlCreateOptions_t *options);
/// <summary>
/// Closes an open navigation instance handle and destroys the navigation instance.
/// </summary>
/// <param name="nh">A valid <see cref="nlHandle_t"/> of an open navigation instance.</param>
/// <returns>0 if the function succeeds, otherwise a navlib error, see
/// <see cref="navlib_errc::navlib_errc_t"/> and <see cref="make_result_code"/>.</returns>
NAVLIB_DLLAPI_ long __cdecl NlClose(nlHandle_t nh);
/// <summary>
/// Read the value of a property cached in the navlib.
/// </summary>
/// <param name="nh">The <see cref="nlHandle_t"/> of the open navigation instance.</param>
/// <param name="name">The name of the property whose value is being queried.</param>
/// <param name="value">A pointer to a <see cref="value_t"/> that contains the property value when
/// the function returns.</param>
/// <returns>0 if the function succeeds, otherwise a navlib error, see
/// <see cref="navlib_errc::navlib_errc_t"/> and <see cref="make_result_code"/>.</returns>
NAVLIB_DLLAPI_ long __cdecl NlReadValue(nlHandle_t nh, property_t name, value_t *value);
/// <summary>
/// Write the value for a property to the navlib.
/// </summary>
/// <param name="nh">The <see cref="nlHandle_t"/> of the open navigation instance.</param>
/// <param name="name">The name of the property whose value is to be written.</param>
/// <param name="value">A pointer to a <see cref="value_t"/> that contains the new property
/// value.</param>
/// <returns>0 if the function succeeds, otherwise a navlib error, see
/// <see cref="navlib_errc::navlib_errc_t"/> and <see cref="make_result_code"/>.</returns>
NAVLIB_DLLAPI_ long __cdecl NlWriteValue(nlHandle_t nh, property_t name, const value_t *value);
/// <summary>
/// Query the type of a navlib property.
/// </summary>
/// <param name="name">The name of the property whose type is to be queried.</param>
/// <returns>One of the <see cref="propertyTypes"/> values.</returns>
NAVLIB_DLLAPI_ propertyType_t __cdecl NlGetType(property_t name);
NAVLIB_END_
#endif // NAVLIB_H_INCLUDED_

View File

@@ -0,0 +1,72 @@
#ifndef NAVLIB_DEFINES_H_INCLUDED_
#define NAVLIB_DEFINES_H_INCLUDED_
// <copyright file="navlib.h" company="3Dconnexion">
// -------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// -------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// *************************************************************************************************
// File History
//
// $Id: navlib_defines.h 19940 2023-01-25 07:17:44Z mbonk $
//
// 01/23/14 MSB Initial design
// </history>
// <description>
// *************************************************************************************************
// File Description
//
// This header file defines the macros used in the 3dconnexion interface and header files.
//
// *************************************************************************************************
// </description>
// Invalid handle
#define INVALID_NAVLIB_HANDLE 0
// Navlib facility used to generate error codes
// Note this is identical to FACILITY_ITF on windows
#define FACILITY_NAVLIB 4
// resources
#define NAVLIB_IDB_ManualPivot 0x6004
#define NAVLIB_IDB_AutoPivot 0x6005
#if defined(__cplusplus)
#define NAVLIB_BEGIN_ namespace navlib {
#define NAVLIB_END_ }
#define NAVLIB_ ::navlib::
#define USING_NAVLIB_ using namespace navlib;
#else
#define NAVLIB_BEGIN_
#define NAVLIB_END_
#define NAVLIB_
#define USING_NAVLIB_
#endif
#if defined(_MSC_VER) && defined(NAVLIB_EXPORTS)
#define NAVLIB_DLLAPI_ extern "C" __declspec(dllexport)
#elif defined(__cplusplus)
#define NAVLIB_DLLAPI_ extern "C"
#else
#define NAVLIB_DLLAPI_
#endif
#ifndef NOEXCEPT
#if defined(_MSC_VER) && (_MSC_VER <= 1800)
#ifdef _NOEXCEPT
#define NOEXCEPT _NOEXCEPT
#else
#define NOEXCEPT
#endif
#else
#define NOEXCEPT noexcept
#endif
#endif
#endif // NAVLIB_DEFINES_H_INCLUDED_

View File

@@ -0,0 +1,88 @@
#ifndef NAVLIB_ERROR_H_INCLUDED_
#define NAVLIB_ERROR_H_INCLUDED_
// <copyright file="navlib_error.h" company="3Dconnexion">
// -------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// -------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// *************************************************************************************************
// File History
//
// $Id: navlib_error.h 19940 2023-01-25 07:17:44Z mbonk $
//
// 01/23/14 MSB Initial design
// </history>
// <description>
// *************************************************************************************************
// File Description
//
// This header file defines the classes used for error reporting.
//
// *************************************************************************************************
// </description>
#include <system_error>
#include <navlib/navlib_types.h>
namespace std {
template <> struct is_error_code_enum<NAVLIB_ navlib_errc::navlib_errc_t> : true_type {};
} // namespace std
namespace { // Anonymous namespace
/// <summary>
/// Navigation library error category.
/// </summary>
struct navlib_error_category : public std::error_category {
typedef std::error_category base_type;
public:
navlib_error_category() NOEXCEPT {
}
const char *name() const NOEXCEPT override {
return "navlib";
}
std::string message(int errorValue) const override {
namespace navlib_errc = navlib::navlib_errc;
switch (static_cast<navlib_errc::navlib_errc_t>(errorValue)) {
case navlib_errc::property_not_found:
return "Cannot locate the requested navlib property.";
case navlib_errc::invalid_function:
return "The requested function is not valid.";
case navlib_errc::insufficient_buffer:
return "Insufficient buffer space.";
default:
return std::generic_category().message(errorValue);
}
}
};
/// <summary>
/// Navigation library error category.
/// </summary>
static const navlib_error_category navlib_category;
} // namespace
NAVLIB_BEGIN_
/// <summary>
/// Makes a <see cref="std::error_code"/>.
/// </summary>
/// <param name="errc">The Navigation library error.</param>
/// <returns>A <see cref="std::error_code"/> with the Navigation library category.</returns>
inline std::error_code make_error_code(navlib_errc::navlib_errc_t errc) {
std::error_code ec(static_cast<int>(errc), navlib_category);
return ec;
}
NAVLIB_END_ // namespace navlib
#endif /* NAVLIB_ERROR_H_INCLUDED_ */

View File

@@ -0,0 +1,105 @@
#ifndef NAVLIB_OPERATORS_H_INCLUDED_
#define NAVLIB_OPERATORS_H_INCLUDED_
// <copyright file="navlib_operators.h" company="3Dconnexion">
// -------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// -------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// *************************************************************************************************
// File History
//
// $Id: navlib_operators.h 19944 2023-01-25 14:56:02Z mbonk $
//
// 01/23/14 MSB Initial design
// </history>
// <description>
// *************************************************************************************************
// File Description
//
// This header file defines the operator overloads for variable types used in the 3dconnexion
// interface.
//
// *************************************************************************************************
// </description>
#include <navlib/navlib_types.h>
// stdlib
#include <float.h>
#include <math.h>
NAVLIB_BEGIN_
/// <summary>
/// Compare floating point numbers.
/// </summary>
/// <param name="a">First value to compare.</param>
/// <param name="b">Second value to compare.</param>
/// <param name="epsilon">Maximum relative error.</param>
/// <returns></returns>
/// <remarks>
/// From https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition.
/// Copyright Bruce Dawson.
/// </remarks>
template <class T> bool equals(T a, T b, T epsilon = static_cast<T>(FLT_EPSILON)) {
T diff = fabs(a - b);
if (diff < epsilon) {
return true;
}
a = fabs(a);
b = fabs(b);
T largest = (a > b) ? a : b;
if (diff <= largest * epsilon) {
return true;
}
return false;
}
inline bool operator==(const vector_t &lhs, const vector_t &rhs) {
return (equals(lhs.x, rhs.x) && equals(lhs.y, rhs.y) && equals(lhs.z, rhs.z));
}
inline bool operator!=(const vector_t &lhs, const vector_t &rhs) {
return !(lhs == rhs);
}
inline bool operator==(const point_t &lhs, const point_t &rhs) {
return (equals(lhs.x, rhs.x) && equals(lhs.y, rhs.y) && equals(lhs.z, rhs.z));
}
inline bool operator!=(const point_t &lhs, const point_t &rhs) {
return !(lhs == rhs);
}
inline bool operator==(const box_t &lhs, const box_t &rhs) {
return lhs.min == rhs.min && lhs.max == rhs.max;
}
inline bool operator!=(const box_t &lhs, const box_t &rhs) {
return !(lhs == rhs);
}
inline bool operator==(const matrix_t &lhs, const matrix_t &rhs) {
for (size_t i = 0; i < sizeof(rhs) / sizeof(rhs[0]); ++i) {
if (!equals(lhs[i], rhs[i])) {
return false;
}
}
return true;
}
inline bool operator!=(const matrix_t &lhs, const matrix_t &rhs) {
return !(lhs == rhs);
}
inline nlOptions_t operator|(nlOptions_t lhs, nlOptions_t rhs) {
return static_cast<nlOptions_t>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
NAVLIB_END_
#endif /* NAVLIB_OPERATORS_H_INCLUDED_ */

View File

@@ -0,0 +1,237 @@
#ifndef NAVLIB_OSTREAM_INCLUDED_
#define NAVLIB_OSTREAM_INCLUDED_
// <copyright file="navlib_ostream.h" company="3Dconnexion">
// -------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// -------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// *************************************************************************************************
// File History
//
// $Id: navlib_ostream.h 19940 2023-01-25 07:17:44Z mbonk $
//
// 01/23/14 MSB Initial design
// </history>
// <description>
// *************************************************************************************************
// File Description
//
// This header file defines stream operators for the navlib types.
//
// *************************************************************************************************
// </description>
#include <navlib/navlib_types.h>
// C++ convenience functions
#include <iomanip>
#include <limits>
#include <ostream>
#include <string>
NAVLIB_BEGIN_
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const vector_t &vector) {
stream << std::setprecision(std::numeric_limits<float>::digits10 + 1);
stream << "[" << vector.x << ", " << vector.y << ", " << vector.z << "]";
return stream;
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const point_t &position) {
stream << std::setprecision(std::numeric_limits<float>::digits10 + 1);
stream << "[" << position.x << ", " << position.y << ", " << position.z << "]";
return stream;
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const plane_t &plane) {
stream << std::setprecision(std::numeric_limits<float>::digits10 + 1);
stream << "[" << plane.n.x << ", " << plane.n.y << ", " << plane.n.z << ", " << plane.d << "]";
return stream;
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const box_t &box) {
stream << std::setprecision(std::numeric_limits<float>::digits10 + 1);
stream << box.min << ", " << box.max;
return stream;
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const frustum_t &frustum) {
stream << std::setprecision(std::numeric_limits<float>::digits10 + 1);
stream << "[" << frustum.left << ", " << frustum.right << ", " << frustum.bottom << ", "
<< frustum.top << ", " << frustum.nearVal << ", " << frustum.farVal << "]";
return stream;
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const matrix_t &matrix) {
stream << std::endl;
stream << std::setprecision(std::numeric_limits<float>::digits10 + 1);
stream << "\t[" << matrix.m00 << ", " << matrix.m01 << ", " << matrix.m02 << ", " << matrix.m03
<< "]" << std::endl;
stream << "\t[" << matrix.m10 << ", " << matrix.m11 << ", " << matrix.m12 << ", " << matrix.m13
<< "]" << std::endl;
stream << "\t[" << matrix.m20 << ", " << matrix.m21 << ", " << matrix.m22 << ", " << matrix.m23
<< "]" << std::endl;
stream << "\t[" << matrix.m30 << ", " << matrix.m31 << ", " << matrix.m32 << ", " << matrix.m33
<< "]";
return stream;
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const struct siResource_s &resource) {
stream << "{file_name: " << (resource.file_name ? resource.file_name : "nullptr")
<< ", id: " << (resource.id ? resource.id : "nullptr")
<< ", type: " << (resource.type ? resource.type : "nullptr")
<< ", index: " << resource.index << "}";
return stream;
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const struct siImageFile_s &file) {
stream << "{file_name: " << (file.file_name ? file.file_name : "nullptr")
<< ", index: " << file.index << "}";
return stream;
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const struct siImageData_s &image) {
stream << "{data: 0x" << std::hex << reinterpret_cast<uintptr_t>(image.data) << std::dec
<< ", size: " << image.size << ", index: " << image.index << "}";
return stream;
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const imagearray_t &images) {
stream << "count: " << images.count;
std::string indent("\n");
indent.resize(5, ' ');
for (size_t i = 0; i < images.count; ++i) {
SiImage_t const &image = images.p[i];
stream << indent << "{size: " << image.size << ", id: " << (image.id ? image.id : "nullptr");
if (image.type == e_image_file)
stream << ", type: e_image_file, " << image.file;
else if (image.type == e_resource_file)
stream << ", type: e_resource_file, " << image.resource;
if (image.type == e_image)
stream << ", type: e_image, " << image.image;
else
stream << ", type: e_none";
stream << "}";
}
return stream;
}
template <class Elem_, class Traits_>
void StreamActionNodeHeader(std::basic_ostream<Elem_, Traits_> &stream,
const SiActionNodeEx_t &node, size_t level) {
std::string indent("\n");
indent.resize(4 * level + 1, ' ');
stream << indent << "{size: " << node.size << ", type: " << node.type
<< ", id: " << (node.id ? node.id : "nullptr")
<< ", label: " << (node.label ? node.label : "nullptr")
<< ", description: " << (node.description ? node.description : "nullptr") << "}";
if (node.children != nullptr)
StreamActionNodeHeader(stream, *node.children, level + 1);
if (node.next != nullptr)
StreamActionNodeHeader(stream, *node.next, level);
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const SiActionNodeEx_t &node) {
StreamActionNodeHeader(stream, node, 1);
return stream;
}
template <class Elem_, class Traits_>
std::basic_ostream<Elem_, Traits_> &operator<<(std::basic_ostream<Elem_, Traits_> &stream,
const value_t &value) {
try {
switch (value.type) {
case voidptr_type:
stream << value.p;
break;
case bool_type:
stream << (value.b ? "true" : "false");
break;
case long_type:
stream << value.l;
break;
case float_type:
stream << std::setprecision(std::numeric_limits<float>::digits10 + 1) << value.f;
break;
case double_type:
stream << std::setprecision(std::numeric_limits<double>::digits10 + 2) << value.d;
break;
case point_type:
stream << value.point;
break;
case vector_type:
stream << value.vector;
break;
case matrix_type:
stream << value.matrix;
break;
case string_type:
if (value.string.p)
stream << value.string.p;
else
stream << "empty";
break;
case actionnodeexptr_type:
stream << *value.pnode;
break;
case imagearray_type:
stream << value.imagearray;
break;
case plane_type:
stream << value.plane;
break;
case box_type:
stream << value.box;
break;
case frustum_type:
stream << value.frustum;
break;
case cstr_type:
if (value.cstr_.p)
stream << value.cstr_.p;
else
stream << "empty";
break;
default:
stream << "null";
break;
}
} catch (std::runtime_error &e) {
stream << "std::runtime_error " << e.what();
}
return stream;
}
NAVLIB_END_
#endif // NAVLIB_OSTREAM_INCLUDED_

View File

@@ -0,0 +1,527 @@
#ifndef NAVLIB_TEMPLATES_H_INCLUDED_
#define NAVLIB_TEMPLATES_H_INCLUDED_
// <copyright file="navlib_templates.h" company="3Dconnexion">
// -------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// -------------------------------------------------------------------------------------------------
// </copyright>
// <history>
// *************************************************************************************************
// File History
//
// $Id: navlib_templates.h 19940 2023-01-25 07:17:44Z mbonk $
//
// 06/17/20 MSB Changed condition evaluation away from boolean macros to avoid C4668
// 01/23/14 MSB Initial design
// </history>
// <description>
// *************************************************************************************************
// File Description
//
// This header file defines the templates used in the 3dconnexion interface.
//
// *************************************************************************************************
// </description>
#if (defined _MSC_VER && _MSC_VER < 1900)
#define CONSTEXPR const
#else
#define CONSTEXPR constexpr
#define has_constexpr
#endif
namespace navlib {
template <class T> struct property_type_v {
static CONSTEXPR propertyType_t type = unknown_type;
#ifdef has_constexpr
static constexpr char const *name = "unknown_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
template <class T> const char *property_type_v<T>::name = "unknown_type";
#endif
template <> struct property_type_v<void *> {
static CONSTEXPR propertyType_t type = voidptr_type;
#ifdef has_constexpr
static constexpr char const *name = "voidptr_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<void *>::name = "voidptr_type";
#endif
template <> struct property_type_v<bool_t> {
static CONSTEXPR propertyType_t type = bool_type;
#ifdef has_constexpr
static constexpr char const *name = "bool_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<bool_t>::name = "bool_type";
#endif
template <> struct property_type_v<long> {
static CONSTEXPR propertyType_t type = long_type;
#ifdef has_constexpr
static constexpr char const *name = "long_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<long>::name = "long_type";
#endif
template <> struct property_type_v<float> {
static CONSTEXPR propertyType_t type = float_type;
#ifdef has_constexpr
static constexpr char const *name = "float_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<float>::name = "float_type";
#endif
template <> struct property_type_v<double> {
static CONSTEXPR propertyType_t type = double_type;
#ifdef has_constexpr
static constexpr char const *name = "double_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<double>::name = "double_type";
#endif
template <> struct property_type_v<point_t> {
static CONSTEXPR propertyType_t type = point_type;
#ifdef has_constexpr
static constexpr char const *name = "point_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<point_t>::name = "point_type";
#endif
template <> struct property_type_v<vector_t> {
static CONSTEXPR propertyType_t type = vector_type;
#ifdef has_constexpr
static constexpr char const *name = "vector_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<vector_t>::name = "vector_type";
#endif
template <> struct property_type_v<plane_t> {
static CONSTEXPR propertyType_t type = plane_type;
#ifdef has_constexpr
static constexpr char const *name = "plane_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<plane_t>::name = "plane_type";
#endif
template <> struct property_type_v<box_t> {
static CONSTEXPR propertyType_t type = box_type;
#ifdef has_constexpr
static constexpr char const *name = "box_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<box_t>::name = "box_type";
#endif
template <> struct property_type_v<frustum_t> {
static CONSTEXPR propertyType_t type = frustum_type;
#ifdef has_constexpr
static constexpr char const *name = "frustum_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<frustum_t>::name = "frustum_type";
#endif
template <> struct property_type_v<matrix_t> {
static CONSTEXPR propertyType_t type = matrix_type;
#ifdef has_constexpr
static constexpr char const *name = "matrix_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<matrix_t>::name = "matrix_type";
#endif
template <> struct property_type_v<SiActionNodeEx_t *> {
static CONSTEXPR propertyType_t type = actionnodeexptr_type;
#ifdef has_constexpr
static constexpr char const *name = "actionnodeexptr_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const
char *property_type_v<SiActionNodeEx_t *>::name = "actionnodeexptr_type";
#endif
template <> struct property_type_v<string_t> {
static CONSTEXPR propertyType_t type = string_type;
#ifdef has_constexpr
static constexpr char const *name = "string_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<string_t>::name = "string_type";
#endif
template <> struct property_type_v<cstr_t> {
static CONSTEXPR propertyType_t type = cstr_type;
#ifdef has_constexpr
static constexpr char const *name = "cstr_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<cstr_t>::name = "cstr_type";
#endif
template <> struct property_type_v<imagearray_t> {
static CONSTEXPR propertyType_t type = imagearray_type;
#ifdef has_constexpr
static constexpr char const *name = "imagearray_type";
#else
static const char *name;
#endif
};
#ifndef has_constexpr
__declspec(selectany) const char *property_type_v<imagearray_t>::name = "imagearray_type";
#endif
template <class T> struct remove_cvref {
typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type;
};
// navlib property type from variable type
template <class T> struct property_type : property_type_v<typename remove_cvref<T>::type> {
typedef property_type_v<typename remove_cvref<T>::type> base_type;
typedef propertyType_t value_type;
CONSTEXPR value_type operator()() const {
return base_type::value;
}
#ifdef has_constexpr
constexpr operator value_type() const {
return base_type::value;
}
constexpr operator char *() const {
return base_type::name;
}
#else
operator const value_type() const {
return base_type::value;
}
operator const char *() const {
return base_type::name;
}
#endif
};
template <typename T, typename V, typename TargetType> struct value_member {}; // primary template
// specialization for void*
template <typename T, typename V> struct value_member<T, V, void *> {
T operator()(V &v) {
return v.p;
}
};
// specialization for void**
template <typename T, typename V> struct value_member<T, V, void **> {
T operator()(V &v) {
return &v.p;
}
};
// specialization for bool
template <typename T, typename V> struct value_member<T, V, bool> {
T operator()(V &v) {
return v.b != 0;
}
};
// specialization for bool_t
template <typename T, typename V> struct value_member<T, V, bool_t> {
T operator()(V &v) {
return v.b;
}
};
// specialization for bool_t*
template <typename T, typename V> struct value_member<T, V, bool_t *> {
T operator()(V &v) {
return &v.b;
}
};
// specialization for int
template <typename T, typename V> struct value_member<T, V, int> {
T operator()(V &v) {
return v.l;
}
};
// specialization for long
template <typename T, typename V> struct value_member<T, V, long> {
T operator()(V &v) {
return v.l;
}
};
// specialization for long*
template <typename T, typename V> struct value_member<T, V, long *> {
T operator()(V &v) {
return &v.l;
}
};
// specialization for float
template <typename T, typename V> struct value_member<T, V, float> {
T operator()(V &v) {
return v.f;
}
};
// specialization for float*
template <typename T, typename V> struct value_member<T, V, float *> {
T operator()(V &v) {
return &v.f;
}
};
// specialization for double
template <typename T, typename V> struct value_member<T, V, double> {
T operator()(V &v) {
return v.d;
}
};
// specialization for double*
template <typename T, typename V> struct value_member<T, V, double *> {
T operator()(V &v) {
return &v.d;
}
};
// specialization for point_t
template <typename T, typename V> struct value_member<T, V, point_t> {
T operator()(V &v) {
return v.point;
}
};
// specialization for point_t*
template <typename T, typename V> struct value_member<T, V, point_t *> {
T operator()(V &v) {
return &v.point;
}
};
// specialization for vector_t
template <typename T, typename V> struct value_member<T, V, vector_t> {
T operator()(V &v) {
return v.vector;
}
};
// specialization for vector_t*
template <typename T, typename V> struct value_member<T, V, vector_t *> {
T operator()(V &v) {
return &v.vector;
}
};
// specialization for plane_t
template <typename T, typename V> struct value_member<T, V, plane_t> {
T operator()(V &v) {
return v.plane;
}
};
// specialization for plane_t*
template <typename T, typename V> struct value_member<T, V, plane_t *> {
T operator()(V &v) {
return &v.plane;
}
};
// specialization for box_t
template <typename T, typename V> struct value_member<T, V, box_t> {
T operator()(V &v) {
return v.box;
}
};
// specialization for box_t*
template <typename T, typename V> struct value_member<T, V, box_t *> {
T operator()(V &v) {
return &v.box;
}
};
// specialization for frustum_t
template <typename T, typename V> struct value_member<T, V, frustum_t> {
T operator()(V &v) {
return v.frustum;
}
};
// specialization for frustum_t*
template <typename T, typename V> struct value_member<T, V, frustum_t *> {
T operator()(V &v) {
return &v.frustum;
}
};
// specialization for matrix_t
template <typename T, typename V> struct value_member<T, V, matrix_t> {
T operator()(V &v) {
return v.matrix;
}
};
// specialization for matrix_t*
template <typename T, typename V> struct value_member<T, V, matrix_t *> {
T operator()(V &v) {
return &v.matrix;
}
};
// specialization for SiActionNodeEx_t*
template <typename T, typename V> struct value_member<T, V, const SiActionNodeEx_t *> {
T operator()(V &v) {
return v.pnode;
}
};
// specialization for SiActionNodeEx_t**
template <typename T, typename V> struct value_member<T, V, SiActionNodeEx_t **> {
T operator()(V &v) {
return &v.pnode;
}
};
// specialization for string_t
template <typename T, typename V> struct value_member<T, V, string_t> {
T operator()(V &v) {
return v.string;
}
};
// specialization for string_t*
template <typename T, typename V> struct value_member<T, V, string_t *> {
T operator()(V &v) {
return &v.string;
}
};
// specialization for cstr_t
template <typename T, typename V> struct value_member<T, V, cstr_t> {
T operator()(V &v) {
return v.cstr_;
}
};
// specialization for cstr_t*
template <typename T, typename V> struct value_member<T, V, cstr_t *> {
T operator()(V &v) {
return &v.cstr_;
}
};
// specialization for imagearray_t
template <typename T, typename V> struct value_member<T, V, imagearray_t> {
T operator()(V &v) {
return v.imagearray;
}
};
// specialization for imagearray_t*
template <typename T, typename V> struct value_member<T, V, imagearray_t *> {
T operator()(V &v) {
return &v.imagearray;
}
};
template <typename T, class V> struct cast_value {
T operator()(V &value) {
switch (value.type) {
case bool_type:
return static_cast<T>(value.b);
case long_type:
return static_cast<T>(value.l);
case float_type:
return static_cast<T>(value.f);
case double_type:
return static_cast<T>(value.d);
default:
return static_cast<T>(0);
}
}
};
// Specialization for bool
template <class V> struct cast_value<bool, V> {
bool operator()(V &value) {
switch (value.type) {
case bool_type:
return value.b != 0;
case long_type:
return value.l != 0;
case float_type:
return value.f != 0.0f;
case double_type:
return value.d != 0.0;
default:
return false;
}
}
};
} // namespace navlib
#endif /* NAVLIB_TEMPLATES_H_INCLUDED_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,190 @@
#ifndef siappcmd_types_H_INCLUDED_
#define siappcmd_types_H_INCLUDED_
// <copyright file="siappcmd_types.h" company="3Dconnexion">
// -------------------------------------------------------------------------------------------------
// This file is part of the FreeCAD CAx development system.
//
// Copyright (c) 2014-2023 3Dconnexion.
//
// This source code is released under the GNU Library General Public License, (see "LICENSE").
// -------------------------------------------------------------------------------------------------
// </copyright>
// <description>
// *************************************************************************************************
// File Description
//
// This header file describes the variable types used in the 3dconnexion interface that allows a
// user to assign an arbitrary action to a 3dconnexion device button.
//
// Data structures are described in detail below.
//
// *************************************************************************************************
// </description>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_MSC_VER) && (_MSC_VER<1600)
typedef unsigned __int32 uint32_t;
typedef unsigned __int8 uint8_t;
#if _WIN64
typedef unsigned __int64 uintptr_t;
#else
typedef unsigned int uintptr_t;
#endif
#else
#include <stdint.h>
#include <wchar.h>
#endif
typedef enum siActionNodeType_e
{
SI_ACTIONSET_NODE = 0
, SI_CATEGORY_NODE
, SI_ACTION_NODE
} SiActionNodeType_t;
/*------------------------------------+---------------------------------------
SiActionNodeEx_t
The application passes a pointer to a structure of type SiActionNodeEx_t to
the function SiAppCmdWriteActionSet
A set of actions is composed of a linked list of SiActionNodeEx_t structures.
Sibling nodes are linked by the next field of the structure and child nodes
by the children field. The root node of the tree represents the name of the
action set while the leaf nodes of the tree represent the actions that can be
assigned to buttons and invoked by the user. The intermediate nodes represent
categories and sub-categories for the actions. An example of this would be the
menu item structure in a menu bar. The menus in the menu bar would be
represented by the SiActionNodeEx_t structures with type SI_CATEGORY_NODE pointed
to by each successively linked next field and the first menu item of each menu
represented by the structure pointed to by their child fields (the rest of the
menu items in each menu would again be linked by the next fields).
size
The size field must always be the byte size of siActionNodeEx_s
type
The type field specifies one of the following values.
SI_ACTIONSET_NODE
SI_CATEGORY_NODE
SI_ACTION_NODE
The root node (and only the root node) of the tree always has type
SI_ACTIONSET_NODE. Only the leaf nodes of the tree have type SI_ACTION_NODE.
All intermediate nodes have type SI_CATEGORY_NODE.
id
The id field specifies a UTF8 string identifier for the action set,
category, or action represented by the node. The field is always non-NULL.
This string needs to remain constant across application sessions and more
or less constant across application releases. The id is used by the
application to identify an action.
label
The label field specifies a UTF8 localized/internationalized name
for the action set, category, or action represented by the node. The label
field can be NULL for the root and intermediate category nodes that are not
explicitly presented to users. All leaf (action) and intermediate nodes
containing leaf nodes have non-NULL labels. If the application only has a
single action tree set, then the label of the root (context) node can also
be NULL.
description
The description field specifies a UTF8 localized/internationalized tooltip
for the action set, category, or action represented by the node. The description
field can be NULL for the root and intermediate category nodes that are not
explicitly presented to users. Leaf (action) nodes should have non-NULL descriptions.
--------------------------------------+-------------------------------------*/
typedef struct siActionNodeEx_s
{
uint32_t size;
SiActionNodeType_t type;
struct siActionNodeEx_s *next;
struct siActionNodeEx_s *children;
const char *id;
const char *label;
const char *description;
} SiActionNodeEx_t;
/*------------------------------------+---------------------------------------
SiImage_t
The application passes a pointer to an array of type SiImage_t to
the function SiAppCmdWriteActionImages
size
The size field specifies the size of the SiImage_t type in bytes.
id
The id field specifies a UTF8 string identifier for the image. The field
is always non-NULL. This string needs to remain constant across application
sessions and more or less constant across application releases.
The id is used by the application to identify the image. To associate an
image with a command the id needs to be identical to the value of the
SiActionNodeEx_t::id of the action.
siImageData_s::size
The siImageData_s::size field specifies the size of the data pointed to
by the siImageData_s::data field in bytes.
siImageData_s::data
The image field contains a pointer to the image. The image may be in coded
in any recognizable format.
--------------------------------------+-------------------------------------*/
typedef enum eSiImageType {
e_none = 0
, e_image_file
, e_resource_file
, e_image
, e_glyph
} SiImageType_t;
struct siResource_s {
const char *file_name;
const char *id;
const char *type;
uint32_t index;
};
struct siImageFile_s {
const char *file_name;
uint32_t index;
};
struct siImageData_s {
const uint8_t *data;
uintptr_t size;
uint32_t index;
};
struct siImageGlyph_s {
const char* font_family;
const wchar_t* glyphs;
const uint32_t* reserved1;
uint32_t reserved2;
};
typedef struct siImage_s
{
uint32_t size;
SiImageType_t type;
const char *id;
union {
struct siResource_s resource;
struct siImageFile_s file;
struct siImageData_s image;
struct siImageGlyph_s glyph;
};
} SiImage_t;
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* siappcmd_types_H_INCLUDED_ */

View File

@@ -0,0 +1,12 @@
/******************************************************************************
This file is part of the FreeCAD CAx development system.
Copyright (c) 2014-2023 3Dconnexion.
This source code is released under the GNU Library General Public License, (see "LICENSE").
******************************************************************************/
extern "C" {
extern long NlLoadLibrary();
extern const long NlErrorCode = NlLoadLibrary();
}

View File

@@ -0,0 +1,171 @@
/******************************************************************************
This file is part of the FreeCAD CAx development system.
Copyright (c) 2014-2023 3Dconnexion.
This source code is released under the GNU Library General Public License, (see "LICENSE").
******************************************************************************/
/**
* @file navlib_stub.c
* @brief interface routines to the navlib library routines.
*/
/*-----------------------------------------------------------------------------
* The module contains interface routines to the navlib library routines
* contained in the associated Dynamic Link Library. The DLL is loaded
* explicitly when NlLoadLibrary is invoked. When the DLL is loaded, the
* initialization routine finds the addresses of the routines that it exposes
* and allows them to be used in this code.
*/
#if _WIN32
// windows
#include <Windows.h>
#include <errno.h>
#elif __APPLE__
#include <dlfcn.h>
#include <errno.h>
#include <stdio.h>
#endif
#ifndef EISCONN
#define EISCONN 113
#define ENOBUFS 119
#define ENODATA 120
#define EOPNOTSUPP 130
#endif
// navlib
#include <navlib/navlib.h>
/* DLL library name */
#ifdef _WIN32
static const char *TheLibrary = "TDxNavLib";
#elif __APPLE__
static const char *TheLibrary = "/Library/Frameworks/3DconnexionNavlib.framework/3DconnexionNavlib";
#endif
/* Names of functions contained in DLL; used to find their addresses at load time */
static const char *cNlCreate = "NlCreate";
static const char *cNlClose = "NlClose";
static const char *cNlReadValue = "NlReadValue";
static const char *cNlWriteValue = "NlWriteValue";
static const char *cNlGetType = "NlGetType";
typedef long(__cdecl *PFN_NLCREATE)(nlHandle_t *pnh, const char *appname,
const accessor_t accessors[], size_t accessor_count,
nlCreateOptions_t const *options);
typedef long(__cdecl *PFN_NLCLOSE)(nlHandle_t nh);
typedef long(__cdecl *PFN_NLREADVALUE)(nlHandle_t nh, property_t name, value_t *value);
typedef long(__cdecl *PFN_NLWRITEVALUE)(nlHandle_t nh, property_t name, const value_t *value);
typedef propertyType_t(__cdecl *PFN_NLGETTYPE)(property_t name);
/* Function pointers to functions in DLL */
static PFN_NLCREATE pfnNlCreate = NULL;
static PFN_NLCLOSE pfnNlClose = NULL;
static PFN_NLREADVALUE pfnNlReadValue = NULL;
static PFN_NLWRITEVALUE pfnNlWriteValue = NULL;
static PFN_NLGETTYPE pfnNlGetType = NULL;
extern const long NlErrorCode;
#if _WIN32
long NlLoadLibrary() {
long error = 0;
HMODULE h = LoadLibraryA(TheLibrary);
if (!h) {
error = HRESULT_FROM_WIN32(GetLastError());
}
else {
/* load up the function pointer table */
if (((pfnNlCreate = (PFN_NLCREATE)GetProcAddress(h, cNlCreate)) == NULL) ||
((pfnNlClose = (PFN_NLCLOSE)GetProcAddress(h, cNlClose)) == NULL) ||
((pfnNlReadValue = (PFN_NLREADVALUE)GetProcAddress(h, cNlReadValue)) == NULL) ||
((pfnNlWriteValue = (PFN_NLWRITEVALUE)GetProcAddress(h, cNlWriteValue)) == NULL) ||
((pfnNlGetType = (PFN_NLGETTYPE)GetProcAddress(h, cNlGetType)) == NULL)) {
error = HRESULT_FROM_WIN32(GetLastError());
FreeLibrary(h);
h = NULL;
}
}
return error;
}
#elif __APPLE__
long NlLoadLibrary() {
long error = 0;
void *libHandle = dlopen(TheLibrary, RTLD_LAZY | RTLD_LOCAL);
if (NULL == libHandle) {
error = -1; // whatever error it's an error dlopen() does not set errno
fprintf(stderr, "Error: Failed to open library \"%s\"! Error: %s!\n", TheLibrary, dlerror());
}
else {
/* load up the function pointer table */
if (((pfnNlCreate = (PFN_NLCREATE)dlsym(libHandle, cNlCreate)) == NULL) ||
((pfnNlClose = (PFN_NLCLOSE)dlsym(libHandle, cNlClose)) == NULL) ||
((pfnNlReadValue = (PFN_NLREADVALUE)dlsym(libHandle, cNlReadValue)) == NULL) ||
((pfnNlWriteValue = (PFN_NLWRITEVALUE)dlsym(libHandle, cNlWriteValue)) == NULL) ||
((pfnNlGetType = (PFN_NLGETTYPE)dlsym(libHandle, cNlGetType)) == NULL)) {
error = -2; // whatever error it is - it's an error dlsym() does not set errno
fprintf(stderr, "Error: Failed to fetch symbols from \"%s\"! Error: %s!\n", TheLibrary,
dlerror());
dlclose(libHandle);
libHandle = NULL;
}
}
return error;
}
#else
long NlLoadLibrary() {
return EOPNOTSUPP;
}
#endif
long __cdecl NlCreate(nlHandle_t *pnh, const char *appname, const accessor_t accessors[],
size_t accessor_count, const nlCreateOptions_t *options) {
if (pfnNlCreate) {
return pfnNlCreate(pnh, appname, accessors, accessor_count, options);
}
return NlErrorCode;
}
long __cdecl NlClose(nlHandle_t nh) {
if (pfnNlClose) {
return pfnNlClose(nh);
}
return NlErrorCode;
}
long __cdecl NlReadValue(nlHandle_t nh, property_t name, value_t *value) {
if (pfnNlReadValue) {
return pfnNlReadValue(nh, name, value);
}
return NlErrorCode;
}
long __cdecl NlWriteValue(nlHandle_t nh, property_t name, const value_t *value) {
if (pfnNlWriteValue) {
return pfnNlWriteValue(nh, name, value);
}
return NlErrorCode;
}
propertyType_t __cdecl NlGetType(property_t name) {
if (pfnNlGetType) {
return pfnNlGetType(name);
}
return unknown_type;
}

View File

@@ -220,3 +220,4 @@ Imetric 3D
AlephObjects
KiCad Services Corporation
OpeningDesign
3Dconnexion

View File

@@ -0,0 +1,260 @@
/***************************************************************************
* Copyright (c) 2014-2023 3Dconnexion. *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include <PreCompiled.h>
#include "NavlibInterface.h"
#include <QScrollBar>
#include <QString>
#include <QBuffer>
#include <algorithm>
#include <iterator>
#include <SpaceMouse/CCategory.hpp>
#include <SpaceMouse/CCommand.hpp>
#include <SpaceMouse/CCommandSet.hpp>
#include <SpaceMouse/CImage.hpp>
#include <Gui/Action.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/MainWindow.h>
#include <Gui/View3DInventor.h>
#include <Gui/Workbench.h>
#include <Gui/WorkbenchManager.h>
constexpr uint8_t LCD_ICON_SIZE = 24u;
NavlibInterface::ParsedData NavlibInterface::parseCommandId(const std::string& commandId) const
{
ParsedData result{"", "", 0};
if (commandId.empty())
return result;
auto groupDelimiter = std::find(commandId.cbegin(), commandId.cend(), '|');
if (groupDelimiter == commandId.cend())
return result;
result.groupName = std::string(commandId.cbegin(), groupDelimiter);
groupDelimiter++;
auto commandDelimiter = std::find(groupDelimiter, commandId.cend(), '|');
result.commandName = std::string(groupDelimiter, commandDelimiter);
result.actionIndex = -1;
if (commandDelimiter != commandId.cend()) {
QString indexString =
QString::fromStdString(std::string(++commandDelimiter, commandId.cend()).c_str());
result.actionIndex = indexString.toInt();
}
return result;
}
std::string NavlibInterface::getId(const Gui::Command& command, const int32_t parameter) const
{
std::string name = std::string(command.getName());
if (parameter != -1) {
name.push_back('|');
name.append(std::to_string(parameter));
}
std::string groupName = command.getGroupName();
if (groupName.compare("<string>") == 0 || groupName.empty())
groupName = "Others";
return groupName + "|" + name;
}
TDx::CImage NavlibInterface::getImage(const QAction& qaction, const std::string& id) const
{
const QIcon iconImg = qaction.icon();
const QImage qimage = iconImg.pixmap(QSize(LCD_ICON_SIZE, LCD_ICON_SIZE)).toImage();
QByteArray qbyteArray;
QBuffer qbuffer(&qbyteArray);
qimage.save(&qbuffer, "PNG");
return TDxImage::FromData(qbyteArray.toStdString(), 0, id.c_str());
}
void NavlibInterface::removeMarkups(std::string& text) const
{
for (auto textBegin = text.cbegin(); textBegin != text.cend();) {
auto markupBegin = std::find(textBegin, text.cend(), '<');
if (markupBegin == text.cend())
return;
auto markupEnd = std::find(markupBegin, text.cend(), '>');
if (markupEnd == text.cend())
return;
if (*std::prev(markupEnd) == 'p')
text.insert(std::next(markupEnd), 2, '\n');
textBegin = text.erase(markupBegin, ++markupEnd);
}
}
TDxCommand NavlibInterface::getCCommand(const Gui::Command& command,
const QAction& qAction,
const int32_t parameter) const
{
std::string commandName = qAction.text().toStdString();
std::string commandId = getId(command, parameter);
if (commandName.empty() || commandId.empty())
return TDxCommand();
std::string commandDescription =
parameter == -1 ? command.getToolTipText() : qAction.toolTip().toStdString();
auto newEnd = std::remove(commandName.begin(), commandName.end(), '&');
commandName.erase(newEnd, commandName.end());
removeMarkups(commandDescription);
return TDxCommand(commandId, commandName, commandDescription);
}
long NavlibInterface::SetActiveCommand(std::string commandId)
{
ParsedData parsedData = parseCommandId(commandId);
auto& commandManager = Gui::Application::Instance->commandManager();
if (parsedData.groupName.compare("Others")) {
auto commands = commandManager.getGroupCommands(parsedData.groupName.c_str());
for (Gui::Command* command : commands) {
if (!std::string(command->getName()).compare(parsedData.commandName)) {
if (parsedData.actionIndex == -1) {
Gui::Action* pAction = command->getAction();
pAction->action()->trigger();
}
else
command->invoke(parsedData.actionIndex);
return 0;
}
}
}
else
commandManager.runCommandByName(parsedData.commandName.c_str());
return 0;
}
void NavlibInterface::unpackCommands(Gui::Command& command,
TDxCategory& category,
std::vector<TDx::CImage>& images)
{
if (command.getAction() == nullptr)
return;
QList<QAction*> pQActions;
TDxCategory subCategory;
int32_t index = -1;
auto actionGroup = qobject_cast<Gui::ActionGroup*>(command.getAction());
if (actionGroup != nullptr) {
pQActions = actionGroup->actions();
std::string subCategoryName = actionGroup->text().toStdString();
subCategory = TDxCategory(subCategoryName, subCategoryName);
index = 0;
}
else
pQActions.push_back(command.getAction()->action());
for (QAction* pQAction : pQActions) {
if (pQAction->isSeparator())
continue;
TDxCommand ccommand = getCCommand(command, *pQAction, index);
if (ccommand.GetId().empty())
continue;
if (!pQAction->icon().isNull()) {
TDxImage commandImage = getImage(*pQAction, ccommand.GetId());
images.push_back(commandImage);
}
if (pQActions.size() > 1)
subCategory.push_back(std::move(ccommand));
else {
category.push_back(std::move(ccommand));
return;
}
index++;
}
category.push_back(std::move(subCategory));
}
void NavlibInterface::exportCommands(const std::string& workbench)
{
if (errorCode || (workbench.compare(noneWorkbenchStr) == 0))
return;
auto exportedSetItr =
std::find(exportedCommandSets.cbegin(), exportedCommandSets.cend(), workbench);
if (exportedSetItr != exportedCommandSets.cend()) {
PutActiveCommands(workbench);
return;
}
std::string shortName(workbench);
size_t index = shortName.find(workbenchStr);
if (index != std::string::npos)
shortName.erase(index, workbenchStr.size());
auto guiCommands = Gui::Application::Instance->commandManager().getAllCommands();
std::vector<TDxImage> images;
std::unordered_map<std::string, TDxCategory> categories;
for (Gui::Command* command : guiCommands) {
std::string groupName(command->getGroupName());
std::string groupId(groupName);
if ((groupName.compare("<string>") == 0) || groupName.empty()) {
groupName = "...";
groupId = "Others";
}
categories.emplace(groupName, TDxCategory(groupId, groupName));
unpackCommands(*command, categories.at(groupName), images);
}
TDxCommandSet commandsSet(workbench, shortName);
for (auto& itr : categories)
commandsSet.push_back(std::move(itr.second));
CNav3D::AddCommandSet(commandsSet);
CNav3D::PutActiveCommands(workbench);
CNav3D::AddImages(images);
exportedCommandSets.push_back(workbench);
}

View File

@@ -0,0 +1,165 @@
/***************************************************************************
* Copyright (c) 2014-2023 3Dconnexion. *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifdef USE_3DCONNEXION_NAVLIB
#include <QImage>
#include <array>
#include <SpaceMouse/CNavigation3D.hpp>
#include <Inventor/SbVec2f.h>
#include <Inventor/SbVec3f.h>
using CNav3D = TDx::SpaceMouse::Navigation3D::CNavigation3D;
using TDxCategory = TDx::SpaceMouse::CCategory;
using TDxCommand = TDx::SpaceMouse::CCommand;
using TDxCommandSet = TDx::SpaceMouse::CCommandSet;
using TDxImage = TDx::CImage;
constexpr uint32_t hitTestingResolution = 30;
constexpr std::string_view workbenchStr("Workbench");
constexpr std::string_view noneWorkbenchStr("NoneWorkbench");
class QGraphicsView;
class QAction;
class SoTransform;
class SoSwitch;
class SoResetTransform;
class SoImage;
class SoDepthBuffer;
namespace Gui
{
class MDIView;
class View3DInventor;
class View3DInventorViewer;
class Document;
class Command;
class ActionGroup;
}// namespace Gui
class NavlibInterface: public CNav3D
{
public:
NavlibInterface();
~NavlibInterface();
void enableNavigation();
void disableNavigation();
private:
long IsUserPivot(navlib::bool_t&) const override;
long GetCameraMatrix(navlib::matrix_t&) const override;
long GetPointerPosition(navlib::point_t&) const override;
long GetViewExtents(navlib::box_t&) const override;
long GetViewFOV(double&) const override;
long GetViewFrustum(navlib::frustum_t&) const override;
long GetIsViewPerspective(navlib::bool_t&) const override;
long GetModelExtents(navlib::box_t&) const override;
long GetSelectionExtents(navlib::box_t&) const override;
long GetSelectionTransform(navlib::matrix_t&) const override;
long GetIsSelectionEmpty(navlib::bool_t&) const override;
long GetPivotPosition(navlib::point_t&) const override;
long GetPivotVisible(navlib::bool_t&) const override;
long GetHitLookAt(navlib::point_t&) const override;
long GetFrontView(navlib::matrix_t&) const override;
long GetCoordinateSystem(navlib::matrix_t&) const override;
long GetIsViewRotatable(navlib::bool_t&) const override;
long GetUnitsToMeters(double&) const override;
long SetCameraMatrix(const navlib::matrix_t&) override;
long SetViewExtents(const navlib::box_t&) override;
long SetViewFOV(double) override;
long SetViewFrustum(const navlib::frustum_t&) override;
long SetSelectionTransform(const navlib::matrix_t&) override;
long SetPivotPosition(const navlib::point_t&) override;
long SetPivotVisible(bool) override;
long SetHitAperture(double) override;
long SetHitDirection(const navlib::vector_t&) override;
long SetHitLookFrom(const navlib::point_t&) override;
long SetHitSelectionOnly(bool) override;
long SetActiveCommand(std::string) override;
long SetTransaction(long) override;
struct
{
const Gui::View3DInventor* pView3d = nullptr;
QGraphicsView* pView2d = nullptr;
} currentView;
struct
{
SbVec3f origin;
SbVec3f direction;
float radius;
bool selectionOnly;
} ray;
struct
{
SoTransform* pTransform = nullptr;
SoSwitch* pVisibility = nullptr;
SoResetTransform* pResetTransform = nullptr;
SoImage* pImage = nullptr;
SoDepthBuffer* pDepthTestAlways = nullptr;
SoDepthBuffer* pDepthTestLess = nullptr;
QImage pivotImage;
} pivot;
struct ParsedData
{
std::string groupName;
std::string commandName;
int32_t actionIndex;
};
ParsedData parseCommandId(const std::string& commandId) const;
std::string getId(const Gui::Command& command, const int32_t parameter) const;
TDxImage getImage(const QAction& qaction, const std::string& id) const;
TDxCommand getCCommand(const Gui::Command& command,
const QAction& qAction,
const int32_t parameter) const;
// This method removes markups from text (markup is a
// string enclosed with '<' and '>' characters). Paragraph
// ending markups "</p>" are being replaced with "\n\n".
void removeMarkups(std::string& text) const;
void initializePivot();
void initializePattern() const;
void connectActiveTab();
template<class CameraType>
CameraType getCamera() const;
void onViewChanged(const Gui::MDIView*);
bool is3DView() const;
bool is2DView() const;
void exportCommands(const std::string& workbench);
void unpackCommands(Gui::Command& command,
TDxCategory& category,
std::vector<TDxImage>& images);
std::error_code errorCode;
std::pair<int, std::string> activeTab;
mutable std::array<SbVec2f, hitTestingResolution> hitTestPattern;
mutable bool patternInitialized;
std::vector<std::string> exportedCommandSets;
};
#endif

View File

@@ -0,0 +1,506 @@
/***************************************************************************
* Copyright (c) 2014-2023 3Dconnexion. *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include <PreCompiled.h>
#include "NavlibInterface.h"
#include <QMatrix4x4>
#include <QMdiArea>
#include <QTabBar>
#include <Inventor/SbDPMatrix.h>
#include <Inventor/SbMatrix.h>
#include <Inventor/SbViewVolume.h>
#include <Inventor/SoRenderManager.h>
#include <Inventor/actions/SoGetBoundingBoxAction.h>
#include <Inventor/fields/SoSFVec3f.h>
#include <Inventor/nodes/SoOrthographicCamera.h>
#include <Inventor/nodes/SoPerspectiveCamera.h>
#include <Gui/Application.h>
#include <Gui/MDIView.h>
#include <Gui/MainWindow.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Gui/ViewProvider.h>
#include <Gui/Workbench.h>
#include <Gui/WorkbenchManager.h>
#include <Base/BoundBox.h>
NavlibInterface::NavlibInterface()
: CNavigation3D(false, navlib::nlOptions_t::no_ui),
patternInitialized(false),
activeTab({-1, ""})
{}
NavlibInterface::~NavlibInterface()
{
disableNavigation();
if (pivot.pVisibility != nullptr)
pivot.pVisibility->unref();
}
void NavlibInterface::initializePattern() const
{
if (patternInitialized)
return;
if (hitTestingResolution > 0) {
hitTestPattern[0][0] = 0.0;
hitTestPattern[0][1] = 0.0;
}
for (uint32_t i = 1; i < hitTestingResolution; i++) {
float coefficient = sqrt(static_cast<float>(i) / static_cast<float>(hitTestingResolution));
float angle = 2.4f * static_cast<float>(i);
float x = coefficient * sin(angle);
float y = coefficient * cos(angle);
hitTestPattern[i][0] = x;
hitTestPattern[i][1] = y;
}
patternInitialized = true;
}
long NavlibInterface::GetPointerPosition(navlib::point_t& position) const
{
if (is2DView()) {
QPoint point = currentView.pView2d->mapFromGlobal(QCursor::pos());
point = currentView.pView2d->mapToScene(point).toPoint();
position.x = point.x();
position.y = -point.y();
return 0;
}
if (is3DView()) {
const Gui::View3DInventorViewer* const inventorViewer = currentView.pView3d->getViewer();
if (inventorViewer == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
QPoint viewPoint = currentView.pView3d->mapFromGlobal(QCursor::pos());
viewPoint.setY(currentView.pView3d->height() - viewPoint.y());
SbVec3f worldPosition =
inventorViewer->getPointOnFocalPlane(SbVec2s(viewPoint.x(), viewPoint.y()));
std::copy(worldPosition.getValue(), worldPosition.getValue() + 3, &position.x);
return 0;
}
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
template<class CameraType>
CameraType NavlibInterface::getCamera() const
{
if (is3DView()) {
const Gui::View3DInventorViewer* inventorViewer = currentView.pView3d->getViewer();
if (inventorViewer != nullptr)
return dynamic_cast<CameraType>(inventorViewer->getCamera());
}
return nullptr;
}
void NavlibInterface::onViewChanged(const Gui::MDIView* view)
{
if (view == nullptr)
return;
currentView.pView3d = dynamic_cast<const Gui::View3DInventor*>(view);
currentView.pView2d = nullptr;
if (currentView.pView3d != nullptr) {
const Gui::View3DInventorViewer* const inventorViewer = currentView.pView3d->getViewer();
if (inventorViewer == nullptr)
return;
auto pGroup = dynamic_cast<SoGroup* const>(inventorViewer->getSceneGraph());
if (pGroup == nullptr)
return;
if (pGroup->findChild(pivot.pVisibility) == -1)
pGroup->addChild(pivot.pVisibility);
navlib::box_t extents;
navlib::matrix_t camera;
GetModelExtents(extents);
GetCameraMatrix(camera);
Write(navlib::model_extents_k, extents);
Write(navlib::view_affine_k, camera);
return;
}
for (auto viewinternal : view->findChildren<QGraphicsView*>()) {
QList<QGraphicsView*> views = viewinternal->scene()->views();
for (QGraphicsView* view : views) {
if (view->isActiveWindow()) {
currentView.pView2d = view;
return;
}
}
}
}
void NavlibInterface::enableNavigation()
{
PutProfileHint("FreeCAD");
CNav3D::EnableNavigation(true, errorCode);
if (errorCode)
return;
PutFrameTimingSource(TimingSource::SpaceMouse);
Gui::Application::Instance->signalActivateView.connect(
boost::bind(&NavlibInterface::onViewChanged, this, boost::placeholders::_1));
Gui::Application::Instance->signalActivateWorkbench.connect([this](const char* wb) {
exportCommands(std::string(wb));
});
exportCommands("StartWorkbench");
initializePivot();
connectActiveTab();
}
void NavlibInterface::connectActiveTab()
{
auto pQMdiArea = Gui::MainWindow::getInstance()->findChild<QMdiArea*>();
if (pQMdiArea == nullptr)
return;
auto pQTabBar = pQMdiArea->findChild<QTabBar*>();
if (pQTabBar == nullptr)
return;
pQTabBar->connect(pQTabBar, &QTabBar::currentChanged, [this, pQTabBar](int idx) {
activeTab = {idx, idx >= 0 ? pQTabBar->tabText(idx).toStdString() : ""};
});
}
void NavlibInterface::disableNavigation()
{
CNav3D::EnableNavigation(false, errorCode);
}
long NavlibInterface::GetCameraMatrix(navlib::matrix_t& matrix) const
{
if (activeTab.first == -1 || activeTab.second == "Start page")
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
if (is3DView()) {
auto pCamera = getCamera<SoCamera*>();
if (pCamera == nullptr)
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
SbMatrix cameraMatrix;
pCamera->orientation.getValue().getValue(cameraMatrix);
for (int i = 0; i < 4; i++)
std::copy(cameraMatrix[i], cameraMatrix[i] + 4, &matrix.m00 + 4 * i);
const SbVec3f position = pCamera->position.getValue();
std::copy(position.getValue(), position.getValue() + 3, &matrix.m30);
return 0;
}
if (is2DView()) {
QMatrix4x4 data;
const QWidget* viewport = currentView.pView2d->viewport();
const QPointF viewportCenter(viewport->width() / 2.0, viewport->height() / 2.0);
const QPointF scenePoint = currentView.pView2d->mapToScene(viewportCenter.toPoint());
// Only XY translations are considered for 2D view. The Z coordinate can be a constant value.
data(0, 3) = scenePoint.x();
data(1, 3) = -scenePoint.y();
data(2, 3) = 0.0;
std::copy(data.data(), data.data() + 16, &matrix.m00);
return 0;
}
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
long NavlibInterface::SetCameraMatrix(const navlib::matrix_t& matrix)
{
if (is2DView()) {
QMatrix4x4 data;
std::copy(&matrix.m00, &matrix.m33, data.data());
currentView.pView2d->centerOn(data(0, 3), -data(1, 3));
return 0;
}
if (is3DView()) {
auto pCamera = getCamera<SoCamera*>();
if (pCamera == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
SbMatrix cameraMatrix(matrix(0, 0), matrix(0, 1), matrix(0, 2), matrix(0, 3),
matrix(1, 0), matrix(1, 1), matrix(1, 2), matrix(1, 3),
matrix(2, 0), matrix(2, 1), matrix(2, 2), matrix(2, 3),
matrix(3, 0), matrix(3, 1), matrix(3, 2), matrix(3, 3));
pCamera->orientation = SbRotation(cameraMatrix);
pCamera->position.setValue(matrix(3, 0), matrix(3, 1), matrix(3, 2));
const Gui::View3DInventorViewer* inventorViewer = currentView.pView3d->getViewer();
SoGetBoundingBoxAction action(inventorViewer->getSoRenderManager()->getViewportRegion());
action.apply(inventorViewer->getSceneGraph());
const SbBox3f boundingBox = action.getBoundingBox();
SbVec3f modelCenter = boundingBox.getCenter();
const float modelRadius = (boundingBox.getMin() - modelCenter).length();
navlib::bool_t isPerspective;
GetIsViewPerspective(isPerspective);
if (!isPerspective) {
cameraMatrix.inverse().multVecMatrix(modelCenter, modelCenter);
const float nearDist = -(modelRadius + modelCenter.getValue()[2]);
const float farDist = nearDist + 2.0f * modelRadius;
if (nearDist < 0.0f) {
pCamera->nearDistance.setValue(nearDist);
pCamera->farDistance.setValue(-nearDist);
}
else {
pCamera->nearDistance.setValue(-farDist);
pCamera->farDistance.setValue(farDist);
}
}
pCamera->touch();
return 0;
}
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::GetViewFrustum(navlib::frustum_t& frustum) const
{
const auto pCamera = getCamera<SoPerspectiveCamera* const>();
if (pCamera == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
const SbViewVolume viewVolume = pCamera->getViewVolume(pCamera->aspectRatio.getValue());
float halfHeight = viewVolume.getHeight() / 2.0f;
float halfWidth = viewVolume.getWidth() / 2.0f;
frustum = {-halfWidth,
halfWidth,
-halfHeight,
halfHeight,
viewVolume.getNearDist(),
10.0f * (viewVolume.getNearDist() + viewVolume.nearToFar)};
return 0;
}
long NavlibInterface::SetViewFrustum(const navlib::frustum_t& frustum)
{
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::GetViewExtents(navlib::box_t& extents) const
{
if (is2DView()) {
const QRectF viewRectangle = currentView.pView2d->mapToScene(
currentView.pView2d->viewport()->geometry()).boundingRect();
extents.min.x = viewRectangle.topLeft().x();
extents.min.y = viewRectangle.topLeft().y();
extents.max.x = viewRectangle.bottomRight().x();
extents.max.y = viewRectangle.bottomRight().y();
extents.min.z = -1;
extents.max.z = 0;
return 0;
}
const auto pCamera = getCamera<SoOrthographicCamera* const>();
if (pCamera == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
const SbViewVolume viewVolume = pCamera->getViewVolume(pCamera->aspectRatio.getValue());
const float halfHeight = viewVolume.getHeight() / 2.0f;
const float halfWidth = viewVolume.getWidth() / 2.0f;
const float farDistance = viewVolume.nearToFar + viewVolume.nearDist;
extents = {-halfWidth, -halfHeight, -farDistance, halfWidth, halfHeight, farDistance};
return 0;
}
long NavlibInterface::SetViewExtents(const navlib::box_t& extents)
{
if (is2DView()) {
const QRectF viewRectangle = currentView.pView2d->mapToScene(
currentView.pView2d->viewport()->geometry()).boundingRect();
const float scaling = viewRectangle.height() / (extents.max.y - extents.min.y);
QTransform transform = currentView.pView2d->transform();
transform.setMatrix(transform.m11() * scaling,
transform.m12(),
transform.m13(),
transform.m21(),
transform.m22() * scaling,
transform.m23(),
transform.m31(),
transform.m32(),
transform.m33());
currentView.pView2d->setTransform(transform);
return 0;
}
if (is3DView()) {
auto pCamera = getCamera<SoOrthographicCamera* const>();
if (pCamera == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
navlib::box_t oldExtents;
GetViewExtents(oldExtents);
pCamera->scaleHeight(extents.max.x / oldExtents.max.x);
return 0;
}
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::GetViewFOV(double& fov) const
{
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::SetViewFOV(double fov)
{
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::GetIsViewPerspective(navlib::bool_t& perspective) const
{
auto pPerspectiveCamera = getCamera<SoPerspectiveCamera* const>();
if (pPerspectiveCamera != nullptr) {
perspective = true;
return 0;
}
auto pOrthographicCamera = getCamera<SoOrthographicCamera* const>();
if (pOrthographicCamera != nullptr || is2DView()) {
perspective = false;
return 0;
}
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::GetModelExtents(navlib::box_t& extents) const
{
if (is3DView()) {
const Gui::View3DInventorViewer* const inventorViewer = currentView.pView3d->getViewer();
if (inventorViewer == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
SoGetBoundingBoxAction action(inventorViewer->getSoRenderManager()->getViewportRegion());
action.apply(inventorViewer->getSceneGraph());
const SbBox3f boundingBox = action.getBoundingBox();
std::copy(
boundingBox.getMin().getValue(), boundingBox.getMin().getValue() + 3, &extents.min.x);
std::copy(
boundingBox.getMax().getValue(), boundingBox.getMax().getValue() + 3, &extents.max.x);
return 0;
}
if (is2DView()) {
const QRectF sceneExtents = currentView.pView2d->scene()->itemsBoundingRect();
extents.min.x = sceneExtents.topLeft().x();
extents.min.y = -sceneExtents.bottomRight().y();
extents.max.x = sceneExtents.bottomRight().x();
extents.max.y = -sceneExtents.topLeft().y();
extents.max.z = 0;
extents.min.z = -1;
return 0;
}
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::SetTransaction(long value)
{
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::GetFrontView(navlib::matrix_t& matrix) const
{
matrix = {1., 0., 0., 0.,
0., 0., 1., 0.,
0., -1., 0., 0.,
0., 0., 0., 1.};
return 0;
}
long NavlibInterface::GetCoordinateSystem(navlib::matrix_t& matrix) const
{
matrix = {1., 0., 0., 0.,
0., 0., -1., 0.,
0., 1., 0., 0.,
0., 0., 0., 1.};
return 0;
}
long NavlibInterface::GetIsViewRotatable(navlib::bool_t& isRotatable) const
{
isRotatable = is3DView();
return 0;
}
long NavlibInterface::GetUnitsToMeters(double &units) const
{
units = 0.001;
return 0;
}
bool NavlibInterface::is3DView() const
{
return currentView.pView3d != nullptr;
}
bool NavlibInterface::is2DView() const
{
return currentView.pView2d != nullptr;
}

View File

@@ -0,0 +1,254 @@
/***************************************************************************
* Copyright (c) 2014-2023 3Dconnexion. *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include <PreCompiled.h>
#include <QImage>
#include <QScreen>
#include <QString>
#include <QWindow>
#include "NavlibInterface.h"
#include <Inventor/SbMatrix.h>
#include <Inventor/SbViewVolume.h>
#include <Inventor/SoPickedPoint.h>
#include <Inventor/SoRenderManager.h>
#include <Inventor/fields/SoSFVec3f.h>
#include <Inventor/nodes/SoCamera.h>
#include <Inventor/nodes/SoDepthBuffer.h>
#include <Inventor/nodes/SoImage.h>
#include <Inventor/nodes/SoResetTransform.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoSwitch.h>
#include <Inventor/nodes/SoTransform.h>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Selection.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Gui/ViewProvider.h>
constexpr float MAX_FLOAT = std::numeric_limits<float>::max();
long NavlibInterface::GetSelectionTransform(navlib::matrix_t&) const
{
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::GetIsSelectionEmpty(navlib::bool_t& empty) const
{
empty = !Gui::SelectionSingleton::instance().hasSelection();
return 0;
}
long NavlibInterface::SetSelectionTransform(const navlib::matrix_t&)
{
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::GetPivotPosition(navlib::point_t& position) const
{
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::SetPivotPosition(const navlib::point_t& position)
{
if (pivot.pTransform == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
pivot.pTransform->translation.setValue(position.x, position.y, position.z);
return 0;
}
long NavlibInterface::IsUserPivot(navlib::bool_t& userPivot) const
{
userPivot = false;
return 0;
}
long NavlibInterface::GetPivotVisible(navlib::bool_t& visible) const
{
if (pivot.pVisibility == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
visible = pivot.pVisibility->whichChild.getValue() == SO_SWITCH_ALL;
return 0;
}
long NavlibInterface::SetPivotVisible(bool visible)
{
if (pivot.pVisibility == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
if (visible)
pivot.pVisibility->whichChild = SO_SWITCH_ALL;
else
pivot.pVisibility->whichChild = SO_SWITCH_NONE;
return 0;
}
long NavlibInterface::GetHitLookAt(navlib::point_t& position) const
{
if (is2DView())
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
const Gui::View3DInventorViewer* const inventorViewer = currentView.pView3d->getViewer();
if (inventorViewer == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
SoNode* pSceneGraph = inventorViewer->getSceneGraph();
if (pSceneGraph == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
// Prepare the ray-picking object
SoRayPickAction rayPickAction(inventorViewer->getSoRenderManager()->getViewportRegion());
SbMatrix cameraMatrix;
SbVec3f closestHitPoint;
float minLength = MAX_FLOAT;
// Get the camera rotation
SoCamera* pCamera = getCamera<SoCamera*>();
if (pCamera == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
pCamera->orientation.getValue().getValue(cameraMatrix);
// Initialize the samples array if it wasn't done before
initializePattern();
for (uint32_t i = 0; i < hitTestingResolution; i++) {
// Scale the sample like it was defined in camera space (placed on XY plane)
SbVec3f transform(
hitTestPattern[i][0] * ray.radius, hitTestPattern[i][1] * ray.radius, 0.0f);
// Apply the model-view transform to a sample (only the rotation)
cameraMatrix.multVecMatrix(transform, transform);
// Calculate origin of current hit-testing ray
SbVec3f newOrigin = ray.origin + transform;
// Perform the hit-test
rayPickAction.setRay(newOrigin, ray.direction);
rayPickAction.apply(pSceneGraph);
SoPickedPoint* pickedPoint = rayPickAction.getPickedPoint();
// Check if there was a hit
if (pickedPoint != nullptr) {
SbVec3f hitPoint = pickedPoint->getPoint();
float distance = (newOrigin - hitPoint).length();
// Save hit of the lowest depth
if (distance < minLength) {
minLength = distance;
closestHitPoint = hitPoint;
}
}
}
if (minLength < MAX_FLOAT) {
std::copy(closestHitPoint.getValue(), closestHitPoint.getValue() + 3, &position.x);
return 0;
}
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
long NavlibInterface::GetSelectionExtents(navlib::box_t& extents) const
{
Base::BoundBox3d boundingBox;
auto selectionVector = Gui::Selection().getSelection();
std::for_each(selectionVector.begin(),
selectionVector.end(),
[&boundingBox](Gui::SelectionSingleton::SelObj& selection) {
Gui::ViewProvider* pViewProvider =
Gui::Application::Instance->getViewProvider(selection.pObject);
if (pViewProvider == nullptr)
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
boundingBox.Add(pViewProvider->getBoundingBox(selection.SubName, true));
return 0l;
});
extents = {boundingBox.MinX,
boundingBox.MinY,
boundingBox.MinZ,
boundingBox.MaxX,
boundingBox.MaxY,
boundingBox.MaxZ};
return 0;
}
long NavlibInterface::SetHitAperture(double aperture)
{
ray.radius = aperture;
return 0;
}
long NavlibInterface::SetHitDirection(const navlib::vector_t& direction)
{
ray.direction.setValue(direction.x, direction.y, direction.z);
return 0;
}
long NavlibInterface::SetHitLookFrom(const navlib::point_t& eye)
{
ray.origin.setValue(eye.x, eye.y, eye.z);
return 0;
}
long NavlibInterface::SetHitSelectionOnly(bool hitSelection)
{
ray.selectionOnly = hitSelection;
return 0;
}
void NavlibInterface::initializePivot()
{
pivot.pVisibility = new SoSwitch;
pivot.pTransform = new SoTransform;
pivot.pResetTransform = new SoResetTransform;
pivot.pImage = new SoImage;
pivot.pDepthTestAlways = new SoDepthBuffer;
pivot.pDepthTestLess = new SoDepthBuffer;
pivot.pDepthTestAlways->function.setValue(SoDepthBufferElement::ALWAYS);
pivot.pDepthTestLess->function.setValue(SoDepthBufferElement::LESS);
pivot.pivotImage = QImage(QString::fromStdString(":/icons/3dx_pivot.png"));
Gui::BitmapFactory().convert(pivot.pivotImage, pivot.pImage->image);
pivot.pVisibility->ref();
pivot.pVisibility->whichChild = SO_SWITCH_NONE;
pivot.pVisibility->addChild(pivot.pDepthTestAlways);
pivot.pVisibility->addChild(pivot.pTransform);
pivot.pVisibility->addChild(pivot.pImage);
pivot.pVisibility->addChild(pivot.pResetTransform);
pivot.pVisibility->addChild(pivot.pDepthTestLess);
}

View File

@@ -128,6 +128,7 @@
#include "WorkbenchManager.h"
#include "WorkbenchManipulator.h"
#include "WidgetFactory.h"
#include "3Dconnexion/navlib/NavlibInterface.h"
using namespace Gui;
@@ -512,6 +513,11 @@ Application::Application(bool GUIenabled)
// instantiate the workbench dictionary
_pcWorkbenchDictionary = PyDict_New();
#ifdef USE_3DCONNEXION_NAVLIB
// Instantiate the 3Dconnexion controller
pNavlibInterface = new NavlibInterface();
#endif
if (GUIenabled) {
createStandardOperations();
MacroCommand::load();
@@ -521,6 +527,9 @@ Application::Application(bool GUIenabled)
Application::~Application()
{
Base::Console().Log("Destruct Gui::Application\n");
#ifdef USE_3DCONNEXION_NAVLIB
delete pNavlibInterface;
#endif
WorkbenchManager::destruct();
WorkbenchManipulator::removeAll();
SelectionSingleton::destruct();
@@ -2120,6 +2129,10 @@ void Application::runApplication()
// https://forum.freecad.org/viewtopic.php?f=10&t=21665
Gui::getMainWindow()->setProperty("eventLoop", true);
#ifdef USE_3DCONNEXION_NAVLIB
Instance->pNavlibInterface->enableNavigation();
#endif
runEventLoop(mainApp);
Base::Console().Log("Finish: Event loop left\n");

View File

@@ -34,6 +34,7 @@
class QCloseEvent;
class SoNode;
class NavlibInterface;
namespace Gui{
class BaseView;
@@ -361,6 +362,7 @@ private:
struct ApplicationP* d;
/// workbench python dictionary
PyObject* _pcWorkbenchDictionary;
NavlibInterface* pNavlibInterface;
};
} //namespace Gui

View File

@@ -20,6 +20,14 @@ if (FREECAD_USE_3DCONNEXION)
endif(APPLE)
endif(FREECAD_USE_3DCONNEXION)
if(FREECAD_USE_3DCONNEXION_NAVLIB AND (MSVC OR APPLE))
add_definitions(-DUSE_3DCONNEXION_NAVLIB)
if(APPLE)
add_definitions(-D__APPLE__)
endif(APPLE)
set(3DCONNEXION_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src/3rdParty/3Dconnexion/inc)
endif(FREECAD_USE_3DCONNEXION_NAVLIB AND (MSVC OR APPLE))
if (BUILD_VR)
add_definitions(-DBUILD_VR )
endif(BUILD_VR)
@@ -276,6 +284,21 @@ SET(FreeCADGui_SDK_MOC_HDRS
)
endif(FREECAD_USE_3DCONNEXION AND APPLE)
if(FREECAD_USE_3DCONNEXION_NAVLIB AND (MSVC OR APPLE))
SET(NAVLIB_STUB_DIR ${CMAKE_SOURCE_DIR}/src/3rdParty/3Dconnexion/src)
SET(FreeCADGui_SDK_SRCS
3Dconnexion/navlib/NavlibCmds.cpp
3Dconnexion/navlib/NavlibNavigation.cpp
3Dconnexion/navlib/NavlibPivot.cpp
${NAVLIB_STUB_DIR}/navlib_load.cpp
${NAVLIB_STUB_DIR}/navlib_stub.c
)
SOURCE_GROUP("3Dconnexion Navlib" FILES ${FreeCADGui_SDK_SRCS})
SET(FreeCADGui_SDK_MOC_HDRS
3Dconnexion/navlib/NavlibInterface.h
)
endif(FREECAD_USE_3DCONNEXION_NAVLIB AND (MSVC OR APPLE))
set_property(SOURCE GraphvizView.h GraphvizView.cpp PROPERTY SKIP_AUTOMOC ON)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/moc_GraphvizView-internal.cpp
COMMAND ${QtCore_MOC_EXECUTABLE} -o ${CMAKE_CURRENT_BINARY_DIR}/moc_GraphvizView-internal.cpp ${CMAKE_CURRENT_SOURCE_DIR}/GraphvizView.cpp

BIN
src/Gui/Icons/3dx_pivot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -275,6 +275,7 @@
<file>image-scaling.svg</file>
<file>VarSet.svg</file>
<file>Std_ToggleFreeze.svg</file>
<file>3dx_pivot.png</file>
<file>overlay_recompute.svg</file>
<file>overlay_error.svg</file>
<file>feature_suppressed.svg</file>