#ifndef CNavigation3D_HPP_INCLUDED
#define CNavigation3D_HPP_INCLUDED
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (c) 2018-2021 3Dconnexion.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
/**
* @file CNavigation3D.hpp
* @brief base class for 3D navigation.
*/
// SpaceMouse
#include
#include
#include
#include
#include
#include
#include
#include
// stdlib
#include
#include
#include
#if (!defined(_MSC_VER) || (_MSC_VER > 1600))
#include
#else
#include
namespace std {
namespace chrono = boost::chrono;
using boost::milli;
} // namespace std
#endif
// navlib
#include
#include
namespace TDx {
namespace SpaceMouse {
///
/// Contains types that support 3DMouse navigation.
///
namespace Navigation3D {
///
/// The base class for 3D navigation implements defaults for the interface.
///
/// This class can be used as the base class for the application specific implementation of
/// the accessors.
class CNavigation3D : public INavlibProperty, protected IAccessors {
public:
///
/// The timing source for the frame time.
///
enum TimingSource {
///
/// The space mouse is the source of the frame timing.
///
SpaceMouse = 0,
///
/// The application is the source of the frame timing.
///
Application = 1,
};
public:
///
/// Initializes a new instance of the CNavigation3D class.
///
/// true to use multi-threading, false for single-threaded.
/// true for row-major ordered matrices, false for column-major.
/// The default is single-threaded, column major matrices
explicit CNavigation3D(bool multiThreaded = false, bool rowMajor = false)
: m_enabled(false), m_pImpl(CNavlibImpl::CreateInstance(this, multiThreaded, rowMajor)) {
}
///
/// Initializes a new instance of the CNavigation3D class.
///
/// true to use multi-threading, false for single-threaded.
/// A combination of the values.
explicit CNavigation3D(bool multiThreaded, navlib::nlOptions_t options)
: m_enabled(false), m_pImpl(CNavlibImpl::CreateInstance(this, multiThreaded, options)) {
}
///
/// Clean up the resources
///
virtual ~CNavigation3D() {
}
#if USE_DECLSPEC_PROPERTY
///
/// Gets or sets a value indicating whether the 3DMouse navigation is enabled.
///
__declspec(property(get = IsEnabled, put = EnableNavigation)) bool Enable;
///
/// Gets or sets the animation frame time.
///
__declspec(property(get = GetFrameTime,
put = PutFrameTime)) std::chrono::high_resolution_clock::time_point FrameTime;
///
/// Gets or sets the frame timing source.
///
__declspec(property(get = GetFrameTimingSource,
put = PutFrameTimingSource)) TimingSource FrameTiming;
///
/// Gets or sets the text to pass to the 3Dconnexion driver to use in Properties Utility.
///
/// If the connection to the navlib is already open, the connection is closed and
/// reopened.
__declspec(property(get = GetProfileHint, put = PutProfileHint)) std::string Profile;
///
/// Gets or sets a value representing the active command set.
///
///
__declspec(property(get = GetActiveCommands, put = PutActiveCommands)) std::string ActiveCommands;
#endif
///
/// Gets a value indicating whether 3DMouse navigation is enabled.
///
/// true if enabled, otherwise false.
bool IsEnabled() const {
return m_enabled;
}
///
/// Sets a value indicating whether 3DMouse navigation is enabled.
///
/// true to enable, false to disable.
/// The text for the '3Dconnexion Properties' is
/// empty.
/// Cannot create a connection to the library.
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;
}
}
///
/// Sets a value indicating whether 3DMouse navigation is enabled.
///
/// true to enable, false to disable.
/// The contains the error if something goes
/// wrong.
/// The text for the '3Dconnexion Properties' is
/// empty.
/// Cannot create a connection to the library.
void EnableNavigation(bool value, std::error_code &ec) NOEXCEPT {
try {
EnableNavigation(value);
}
#if _DEBUG && 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
}
///
/// Gets or sets the animation frame time.
///
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>(
m_frameTime.time_since_epoch());
m_pImpl->Write(navlib::frame_time_k, elapsed.count());
}
}
///
/// Gets or sets the frame timing source.
///
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(value));
}
}
///
/// Gets or sets the text to pass to the 3Dconnexion driver to use in Properties Utility.
///
/// If the connection to the navlib is already open, the connection is closed and
/// reopened.
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);
}
}
}
///
/// Gets or sets a value representing the active command set.
///
///
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));
}
}
///
/// Add commands to the sets of commands.
///
/// The to add.
///
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));
}
}
///
/// Add a set of commands to the sets of commands.
///
/// The to add.
///
void AddCommandSet(const CCommandSet &commands) {
AddCommands(commands);
}
///
/// Add to the images available to the 3Dconnexion properties utility.
///
/// The container containing the images to
/// add.
///
template
void AddImages(const std::vector &images,
typename std::enable_if::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));
}
}
///
/// Add to the images available to the 3Dconnexion properties utility.
///
/// The container containing the images to
/// add.
///
template
void
AddImages(const std::vector &images,
typename std::enable_if::value>::type * = nullptr) {
std::vector siImages;
for (auto iter = images.begin(); iter != images.end(); ++iter) {
siImages.push_back(static_cast(*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));
}
}
///
/// Writes the value of a property to the navlib.
///
/// The name of the navlib property to
/// write.
/// The to write.
/// 0 =no error, otherwise a value from .
/// No connection to the navlib / 3D Mouse.
long Write(const std::string &propertyName, const navlib::value &value) override {
return m_pImpl->Write(propertyName, value);
}
///
/// Reads the value of a navlib property.
///
/// The name of the navlib property to
/// read.
/// The to read.
/// 0 =no error, otherwise a value from .
/// No connection to the navlib / 3D Mouse.
long Read(const std::string &propertyName, navlib::value &value) const override {
return m_pImpl->Read(propertyName, value);
}
///
/// Reads the value of a navlib string property.
///
/// The name of the navlib property to
/// read.
/// The value of the property.
/// 0 =no error, otherwise a value from .
/// No connection to the navlib.
long Read(const std::string &propertyName, std::string &string) const override {
return m_pImpl->Read(propertyName, string);
}
protected:
// IEvents overrides
///
/// Default for SetSettingsChanged.
///
/// The change count.
/// navlib::navlib_errc::function_not_supported error.
long SetSettingsChanged(long count) override {
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
///
/// Default for SetKeyPress.
///
/// The virtual key code of the key pressed.
/// navlib::navlib_errc::function_not_supported error.
long SetKeyPress(long vkey) override {
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
///
/// Default for SetKeyRelease.
///
/// The virtual key code of the key pressed.
/// navlib::navlib_errc::function_not_supported error.
long SetKeyRelease(long vkey) override {
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
/// ISpace3D overrides
///
/// Gets the coordinate system used by the client.
///
/// The coordinate system .
/// 0 = no error, otherwise <0.
/// 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)
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)
// navlib::matrix_t cs = {1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1};
matrix = cs;
return 0;
}
///
/// Gets the orientation of the front view.
///
/// The front view transform .
/// 0 = no error, otherwise <0.
/// The default is the same as the coordinate system tripod, i.e. the identity
/// matrix.
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;
}
// IState overrides
long SetTransaction(long transaction) override {
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
long SetMotionFlag(bool motion) override {
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
///
/// Gets the camera's target
///
/// The position of the camera target in world coordinates.
/// 0 = no error, otherwise <0.
/// Free cameras do not have a target.
long GetCameraTarget(navlib::point_t &target) const override {
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
///
/// Gets the view's construction plane.
///
/// The plane equation of the construction plane.
/// 0 = no error, otherwise <0.
/// Required to disable rotations when constructing.
long GetViewConstructionPlane(navlib::plane_t &plane) const override {
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
}
///
/// Gets a value indicating whether the view can be rotated.
///
/// true if the view can be rotated, false otherwise.
/// 0 = no error, otherwise <0.
/// For paper space return false.
long GetIsViewRotatable(navlib::bool_t &isRotatable) const override {
isRotatable = true;
return 0;
}
///
/// Sets the camera's target position.
///
/// The position of the camera target in world coordinates.
/// 0 = no error, otherwise <0.
/// Free cameras do not have a target.
long SetCameraTarget(const navlib::point_t &target) override {
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
}
///
/// Sets the position of the pointer on the projection plane.
///
/// The in world coordinates of the
/// pointer.
/// 0 = no error, otherwise <0.
long SetPointerPosition(const navlib::point_t &position) override {
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 m_pImpl;
};
} // namespace Navigation3D
} // namespace SpaceMouse
} // namespace TDx
#endif // CNavigationModelImpl_HPP_INCLUDED