#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