Browse Source
EDA_3D_VIEWER_FRAME: Implement SpaceMouse navigation and command export for 3D-viewer.
EDA_3D_VIEWER_FRAME: Implement SpaceMouse navigation and command export for 3D-viewer.
Full support for using a 3Dconnexion device in the 3D viewer has been added. Full 3D navigation is available for both the orthographic and perspective projections. Commands are exported and can be assigned to 3D mouse buttons. Any limitations to the functionality are limitations of the installed 3Dconnexion driver for the device and OS. ADDED: A build option KICAD_USE_3DCONNEXION (default = ON) has been added to the main CMakeLists.txt. The option controls whether the SpaceMouse support is compiled into the solution.7.0
committed by
Wayne Stambaugh
14 changed files with 1081 additions and 15 deletions
-
223d-viewer/3d_canvas/eda_3d_canvas.h
-
283d-viewer/3d_navlib/CMakeLists.txt
-
523d-viewer/3d_navlib/nl_3d_viewer_plugin.cpp
-
593d-viewer/3d_navlib/nl_3d_viewer_plugin.h
-
6563d-viewer/3d_navlib/nl_3d_viewer_plugin_impl.cpp
-
1333d-viewer/3d_navlib/nl_3d_viewer_plugin_impl.h
-
683d-viewer/3d_rendering/camera.cpp
-
253d-viewer/3d_rendering/camera.h
-
323d-viewer/3d_viewer/eda_3d_viewer_frame.cpp
-
43d-viewer/3d_viewer/eda_3d_viewer_frame.h
-
63d-viewer/CMakeLists.txt
-
8CMakeLists.txt
-
2thirdparty/3dxware_sdk/inc/SpaceMouse/CImage.hpp
-
1thirdparty/3dxware_sdk/inc/navlib/navlib_types.h
@ -0,0 +1,28 @@ |
|||
if( KICAD_USE_3DCONNEXION ) |
|||
add_library(3d-viewer_navlib STATIC |
|||
"nl_3d_viewer_plugin.cpp" |
|||
"nl_3d_viewer_plugin_impl.cpp" |
|||
) |
|||
|
|||
# Find the 3DxWare SDK component 3DxWare::NlClient |
|||
# find_package(TDxWare_SDK 4.0 REQUIRED COMPONENTS 3DxWare::Navlib) |
|||
target_compile_definitions(3d-viewer_navlib PRIVATE |
|||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_COMPILE_DEFINITIONS> |
|||
) |
|||
target_compile_options(3d-viewer_navlib PRIVATE |
|||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_COMPILE_OPTIONS> |
|||
) |
|||
target_include_directories(3d-viewer_navlib PRIVATE |
|||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_INCLUDE_DIRECTORIES> |
|||
$<TARGET_PROPERTY:pcbnew_kiface_objects,INCLUDE_DIRECTORIES> |
|||
) |
|||
target_link_libraries(3d-viewer_navlib |
|||
$<TARGET_PROPERTY:3DxWare::Navlib,INTERFACE_LINK_LIBRARIES> |
|||
3DxWare::Navlib |
|||
) |
|||
else() |
|||
add_library(3d-viewer_navlib STATIC |
|||
"nl_3d_viewer_plugin.cpp" |
|||
) |
|||
endif(KICAD_USE_3DCONNEXION) |
|||
|
|||
@ -0,0 +1,52 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2021 3Dconnexion |
|||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#include "nl_3d_viewer_plugin.h"
|
|||
|
|||
#if defined( KICAD_USE_3DCONNEXION )
|
|||
#include "nl_3d_viewer_plugin_impl.h"
|
|||
|
|||
NL_3D_VIEWER_PLUGIN::NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport ) : |
|||
m_impl( new NL_3D_VIEWER_PLUGIN_IMPL( aViewport ) ) |
|||
{ |
|||
} |
|||
|
|||
NL_3D_VIEWER_PLUGIN::~NL_3D_VIEWER_PLUGIN() |
|||
{ |
|||
delete m_impl; |
|||
} |
|||
|
|||
void NL_3D_VIEWER_PLUGIN::SetFocus( bool focus ) |
|||
{ |
|||
m_impl->SetFocus( focus ); |
|||
} |
|||
#else
|
|||
NL_3DVIEWER_PLUGIN::NL_3DVIEWER_PLUGIN( EDA_3D_CANVAS* aViewport ) |
|||
{ |
|||
} |
|||
|
|||
void NL_3DVIEWER_PLUGIN::SetFocus( bool focus ) |
|||
{ |
|||
} |
|||
|
|||
NL_3DVIEWER_PLUGIN::~NL_3DVIEWER_PLUGIN() |
|||
{ |
|||
} |
|||
#endif
|
|||
@ -0,0 +1,59 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2021 3Dconnexion |
|||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* 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 <http://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
/** |
|||
* @file nl_3d_viewer_plugin.h |
|||
* @brief Declaration of the NL_3D_VIEWER_PLUGIN class |
|||
*/ |
|||
|
|||
#ifndef NL_3D_VIEWER_PLUGIN_H_ |
|||
#define NL_3D_VIEWER_PLUGIN_H_ |
|||
|
|||
// Forward declarations. |
|||
class EDA_3D_CANVAS; |
|||
class NL_3D_VIEWER_PLUGIN_IMPL; |
|||
/** |
|||
* The class that implements the public interface to the SpaceMouse plug-in. |
|||
*/ |
|||
class NL_3D_VIEWER_PLUGIN |
|||
{ |
|||
public: |
|||
/** |
|||
* Initializes a new instance of the NL_3D_VIEWER_PLUGIN. |
|||
* |
|||
* @param aViewport is the viewport to be navigated. |
|||
*/ |
|||
NL_3D_VIEWER_PLUGIN( EDA_3D_CANVAS* aViewport ); |
|||
|
|||
virtual ~NL_3D_VIEWER_PLUGIN(); |
|||
|
|||
/** |
|||
* Set the connection to the 3Dconnexion driver to the focus state so that |
|||
* 3DMouse data is routed here. |
|||
* |
|||
* @param aFocus is true to set the connection active. |
|||
*/ |
|||
void SetFocus( bool aFocus = true ); |
|||
|
|||
private: |
|||
NL_3D_VIEWER_PLUGIN_IMPL* m_impl; |
|||
}; |
|||
|
|||
#endif // NL_3D_VIEWER_PLUGIN_H_ |
|||
@ -0,0 +1,656 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2021 3Dconnexion |
|||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* 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 <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#include "nl_3d_viewer_plugin_impl.h"
|
|||
|
|||
// 3d-viewer
|
|||
#include <3d-viewer/3d_rendering/track_ball.h>
|
|||
#include <3d-viewer/3d_canvas/eda_3d_canvas.h>
|
|||
|
|||
// KiCAD includes
|
|||
#include <board.h>
|
|||
#include <pcb_base_frame.h>
|
|||
#include <bitmaps.h>
|
|||
#include <board_adapter.h>
|
|||
#include <class_draw_panel_gal.h>
|
|||
#include <pcb_base_frame.h>
|
|||
#include <view/wx_view_controls.h>
|
|||
#include <tool/action_manager.h>
|
|||
#include <tool/tool_action.h>
|
|||
#include <tool/tool_manager.h>
|
|||
|
|||
// stdlib
|
|||
#include <map>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
|
|||
#include <wx/mstream.h>
|
|||
/**
|
|||
* Flag to enable the NL_3D_VIEWER_PLUGIN debug tracing. |
|||
* |
|||
* Use "KI_TRACE_NL_3D_VIEWER_PLUGIN" to enable. |
|||
* |
|||
* @ingroup trace_env_vars |
|||
*/ |
|||
const wxChar* NL_3D_VIEWER_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_3D_VIEWER_PLUGIN" ); |
|||
|
|||
/**
|
|||
* Template to compare two floating point values for equality within a required epsilon. |
|||
* |
|||
* @param aFirst value to compare. |
|||
* @param aSecond value to compare. |
|||
* @param aEpsilon allowed error. |
|||
* @return true if the values considered equal within the specified epsilon, otherwise false. |
|||
*/ |
|||
template <class T> |
|||
bool equals( T aFirst, T aSecond, T aEpsilon = static_cast<T>( FLT_EPSILON ) ) |
|||
{ |
|||
T diff = fabs( aFirst - aSecond ); |
|||
if( diff < aEpsilon ) |
|||
{ |
|||
return true; |
|||
} |
|||
aFirst = fabs( aFirst ); |
|||
aSecond = fabs( aSecond ); |
|||
T largest = aFirst > aSecond ? aFirst : aSecond; |
|||
if( diff <= largest * aEpsilon ) |
|||
{ |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/**
|
|||
* Template to compare two glm::mat<T> values for equality within a required epsilon. |
|||
* |
|||
* @param aFirst value to compare. |
|||
* @param aSecond value to compare. |
|||
* @param aEpsilon allowed error. |
|||
* @return true if the values considered equal within the specified epsilon, otherwise false. |
|||
*/ |
|||
template <glm::length_t L, glm::length_t C, class T, glm::qualifier Q> |
|||
bool equals( glm::mat<L, C, T, Q> const& aFirst, glm::mat<L, C, T, Q> const& aSecond, |
|||
T aEpsilon = static_cast<T>( FLT_EPSILON * 10 ) ) |
|||
{ |
|||
T const* first = glm::value_ptr( aFirst ); |
|||
T const* second = glm::value_ptr( aSecond ); |
|||
|
|||
for( glm::length_t j = 0; j < L * C; ++j ) |
|||
{ |
|||
if( !equals( first[j], second[j], aEpsilon ) ) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
NL_3D_VIEWER_PLUGIN_IMPL::NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas ) : |
|||
NAV_3D( false, false ), m_canvas( aCanvas ), m_capIsMoving( false ) |
|||
{ |
|||
m_camera = dynamic_cast<TRACK_BALL*>( m_canvas->GetCamera() ); |
|||
|
|||
PutProfileHint( "KiCAD 3D" ); |
|||
|
|||
EnableNavigation( true ); |
|||
PutFrameTimingSource( TimingSource::SpaceMouse ); |
|||
|
|||
exportCommandsAndImages(); |
|||
} |
|||
|
|||
NL_3D_VIEWER_PLUGIN_IMPL::~NL_3D_VIEWER_PLUGIN_IMPL() |
|||
{ |
|||
EnableNavigation( false ); |
|||
} |
|||
|
|||
void NL_3D_VIEWER_PLUGIN_IMPL::SetFocus( bool aFocus ) |
|||
{ |
|||
wxLogTrace( m_logTrace, wxT( "NL_3D_VIEWER_PLUGIN_IMPL::SetFocus %d" ), aFocus ); |
|||
NAV_3D::Write( navlib::focus_k, aFocus ); |
|||
} |
|||
|
|||
// temporary store for the categories
|
|||
typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE; |
|||
|
|||
/**
|
|||
* Add a category to the store. |
|||
* |
|||
* The function adds category paths of the format "A.B" where B is a sub-category of A. |
|||
* |
|||
* @param aCategoryPath is the std::string representation of the category. |
|||
* @param aCategoryStore is the CATEGORY_STORE instance to add to. |
|||
* @return a CATEGORY_STORE::iterator where the category was added. |
|||
*/ |
|||
CATEGORY_STORE::iterator add_category( std::string aCategoryPath, CATEGORY_STORE& aCategoryStore ) |
|||
{ |
|||
using TDx::SpaceMouse::CCategory; |
|||
|
|||
CATEGORY_STORE::iterator parent_iter = aCategoryStore.begin(); |
|||
std::string::size_type pos = aCategoryPath.find_last_of( '.' ); |
|||
|
|||
if( pos != std::string::npos ) |
|||
{ |
|||
std::string parentPath = aCategoryPath.substr( 0, pos ); |
|||
parent_iter = aCategoryStore.find( parentPath ); |
|||
if( parent_iter == aCategoryStore.end() ) |
|||
{ |
|||
parent_iter = add_category( parentPath, aCategoryStore ); |
|||
} |
|||
} |
|||
|
|||
std::string name = aCategoryPath.substr( pos + 1 ); |
|||
std::unique_ptr<CCategory> categoryNode = |
|||
std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() ); |
|||
|
|||
CATEGORY_STORE::iterator iter = aCategoryStore.insert( |
|||
aCategoryStore.end(), CATEGORY_STORE::value_type( aCategoryPath, categoryNode.get() ) ); |
|||
|
|||
parent_iter->second->push_back( std::move( categoryNode ) ); |
|||
return iter; |
|||
} |
|||
|
|||
/**
|
|||
* Export the invocable actions and images to the 3Dconnexion UI. |
|||
*/ |
|||
void NL_3D_VIEWER_PLUGIN_IMPL::exportCommandsAndImages() |
|||
{ |
|||
wxLogTrace( m_logTrace, wxT( "NL_3D_VIEWER_PLUGIN_IMPL::exportCommandsAndImages" ) ); |
|||
|
|||
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList(); |
|||
|
|||
if( actions.size() == 0 ) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
using TDx::SpaceMouse::CCommand; |
|||
using TDx::SpaceMouse::CCommandSet; |
|||
|
|||
// The root action set node
|
|||
CCommandSet commandSet( "EDA_3D_CANVAS", "3D Viewer" ); |
|||
|
|||
// Activate the command set
|
|||
NAV_3D::PutActiveCommands( commandSet.GetId() ); |
|||
|
|||
// temporary store for the categories
|
|||
CATEGORY_STORE categoryStore; |
|||
|
|||
std::vector<TDx::CImage> vImages; |
|||
|
|||
// add the action set to the category_store
|
|||
CATEGORY_STORE::iterator iter = categoryStore.insert( |
|||
categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) ); |
|||
|
|||
std::list<TOOL_ACTION*>::const_iterator it; |
|||
|
|||
for( it = actions.begin(); it != actions.end(); ++it ) |
|||
{ |
|||
const TOOL_ACTION* action = *it; |
|||
std::string label = action->GetLabel().ToStdString(); |
|||
if( label.empty() ) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
std::string name = action->GetName(); |
|||
|
|||
// Do no export commands for the pcbnew app.
|
|||
if( name.rfind( "pcbnew.", 0 ) == 0 ) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
std::string strCategory = action->GetToolName(); |
|||
CATEGORY_STORE::iterator iter = categoryStore.find( strCategory ); |
|||
if( iter == categoryStore.end() ) |
|||
{ |
|||
iter = add_category( std::move( strCategory ), categoryStore ); |
|||
} |
|||
|
|||
std::string description = action->GetDescription().ToStdString(); |
|||
|
|||
// Arbitrary 8-bit data stream
|
|||
wxMemoryOutputStream imageStream; |
|||
if( action->GetIcon() != BITMAPS::INVALID_BITMAP ) |
|||
{ |
|||
wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage(); |
|||
image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG ); |
|||
image.Destroy(); |
|||
|
|||
if( imageStream.GetSize() ) |
|||
{ |
|||
wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer(); |
|||
TDx::CImage image = TDx::CImage::FromData( "", 0, name.c_str() ); |
|||
image.AssignImage( std::string( reinterpret_cast<const char*>( |
|||
streamBuffer->GetBufferStart() ), |
|||
streamBuffer->GetBufferSize() ), |
|||
0 ); |
|||
|
|||
wxLogTrace( m_logTrace, "Adding image for : %s", name ); |
|||
vImages.push_back( std::move( image ) ); |
|||
} |
|||
} |
|||
|
|||
wxLogTrace( m_logTrace, "Inserting command: %s, description: %s, in category: %s", name, |
|||
description, iter->first ); |
|||
|
|||
iter->second->push_back( |
|||
CCommand( std::move( name ), std::move( label ), std::move( description ) ) ); |
|||
} |
|||
|
|||
NAV_3D::AddCommandSet( commandSet ); |
|||
NAV_3D::AddImages( vImages ); |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const |
|||
{ |
|||
// cache the camera matrix so that we can tell if the view has been moved and
|
|||
// calculate a delta transform if required.
|
|||
m_cameraMatrix = m_camera->GetViewMatrix(); |
|||
|
|||
std::copy_n( glm::value_ptr( glm::inverse( m_cameraMatrix ) ), 16, matrix.m ); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const |
|||
{ |
|||
SFVEC3F origin, direction; |
|||
m_camera->MakeRayAtCurrentMousePosition( origin, direction ); |
|||
|
|||
position = { origin.x, origin.y, origin.z }; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const |
|||
{ |
|||
if( m_camera->GetProjection() == PROJECTION_TYPE::PERSPECTIVE ) |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation ); |
|||
} |
|||
|
|||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum(); |
|||
|
|||
double half_width = f.fw / 2.; |
|||
double half_height = f.fh / 2.; |
|||
extents = { -half_width, -half_height, f.nearD, half_width, half_height, f.farD }; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewFOV( double& aFov ) const |
|||
{ |
|||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum(); |
|||
|
|||
aFov = glm::radians( f.angle ); |
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& aFrustum ) const |
|||
{ |
|||
if( m_camera->GetProjection() != PROJECTION_TYPE::PERSPECTIVE ) |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation ); |
|||
} |
|||
|
|||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum(); |
|||
double half_width = f.nw / 2.; |
|||
double half_height = f.nh / 2.; |
|||
aFrustum = { -half_width, half_width, -half_height, half_height, f.nearD, f.farD }; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const |
|||
{ |
|||
perspective = m_camera->GetProjection() == PROJECTION_TYPE::PERSPECTIVE ? 1 : 0; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& aCameraMatrix ) |
|||
{ |
|||
long result = 0; |
|||
|
|||
glm::mat4 cam, viewMatrix; |
|||
std::copy_n( aCameraMatrix.m, 16, glm::value_ptr( cam ) ); |
|||
viewMatrix = glm::inverse( cam ); |
|||
|
|||
|
|||
glm::mat4 camera = m_camera->GetViewMatrix(); |
|||
|
|||
// The navlib does not move the camera in its z-axis in an orthographic projection
|
|||
// as this does not change the viewed object size. However ...
|
|||
if( m_camera->GetProjection() == PROJECTION_TYPE::ORTHO ) |
|||
{ |
|||
// ... the CAMERA class couples zoom and distance to the object: we need to
|
|||
// ensure that The CAMERA's z position relative to the lookat_pos is not changed
|
|||
// in an orthographic projection.
|
|||
glm::vec4 lookat( m_camera->GetLookAtPos(), 1.0f ); |
|||
glm::vec4 lookat_new = viewMatrix * lookat; |
|||
glm::vec4 lookat_old = camera * lookat; |
|||
|
|||
viewMatrix[3].z += lookat_old.z - lookat_new.z; |
|||
} |
|||
|
|||
if( !equals( camera, m_cameraMatrix ) ) |
|||
{ |
|||
// Some other input device has moved the camera. Apply only the intended delta
|
|||
// transform ...
|
|||
m_camera->SetViewMatrix( viewMatrix * glm::inverse( m_cameraMatrix ) * camera ); |
|||
m_camera->Update(); |
|||
|
|||
// .., cache the intended camera matrix so that we can calculate the delta
|
|||
// transform when needed ...
|
|||
m_cameraMatrix = viewMatrix; |
|||
|
|||
// ... and let the 3DMouse controller know, that something is amiss.
|
|||
return navlib::make_result_code( navlib::navlib_errc::error ); |
|||
} |
|||
|
|||
m_camera->SetViewMatrix( viewMatrix ); |
|||
m_camera->Update(); |
|||
|
|||
// cache the view matrix so that we know when it has changed.
|
|||
m_cameraMatrix = m_camera->GetViewMatrix(); |
|||
|
|||
// The camera has a constraint on the z position so we need to check that ...
|
|||
if( !equals( m_cameraMatrix[3].z, viewMatrix[3].z ) ) |
|||
{ |
|||
// ... and let the 3DMouse controller know, when something is amiss.
|
|||
return navlib::make_result_code( navlib::navlib_errc::error ); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents ) |
|||
{ |
|||
const CAMERA_FRUSTUM& f = m_camera->GetFrustum(); |
|||
|
|||
float factor = 2 * f.nw / ( extents.max_x - extents.min_x ); |
|||
float zoom = m_camera->GetZoom() / factor; |
|||
|
|||
m_camera->Zoom( factor ); |
|||
|
|||
// The camera auto positions the camera to match the zoom values. We need to
|
|||
// update our cached camera matrix to match the new z value
|
|||
m_cameraMatrix[3].z = m_camera->GetViewMatrix()[3].z; |
|||
|
|||
// The camera has a constraint on the zoom factor so we need to check that ...
|
|||
if( zoom != m_camera->GetZoom() ) |
|||
{ |
|||
// ... and let the 3DMouse controller know, when something is amiss.
|
|||
return navlib::make_result_code( navlib::navlib_errc::error ); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewFOV( double fov ) |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported ); |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum ) |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::permission_denied ); |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const |
|||
{ |
|||
SFVEC3F min = m_canvas->GetBoardAdapter().GetBBox().Min(); |
|||
SFVEC3F max = m_canvas->GetBoardAdapter().GetBBox().Max(); |
|||
|
|||
extents = { min.x, min.y, min.z, max.x, max.y, max.z }; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::no_data_available ); |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::no_data_available ); |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsSelectionEmpty( navlib::bool_t& empty ) const |
|||
{ |
|||
empty = true; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix ) |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation ); |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const |
|||
{ |
|||
SFVEC3F lap = m_camera->GetLookAtPos(); |
|||
|
|||
position = { lap.x, lap.y, lap.z }; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const |
|||
{ |
|||
userPivot = false; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position ) |
|||
{ |
|||
SFVEC3F pivotPos = SFVEC3F( position.x, position.y, position.z ); |
|||
|
|||
// Set the pivot icon position .
|
|||
m_camera->SetLookAtPos_T1( pivotPos ); |
|||
|
|||
#if 0
|
|||
// Set the trackball pivot to the same position as the 3DMouse pivot.
|
|||
glm::mat4 m = m_camera->GetViewMatrix(); |
|||
m_camera->SetLookAtPos( pivotPos ); |
|||
m_camera->SetViewMatrix( std::move( m ) ); |
|||
m_camera->Update(); |
|||
#endif
|
|||
|
|||
m_canvas->Request_refresh(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const |
|||
{ |
|||
visible = m_canvas->GetRenderPivot(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetPivotVisible( bool visible ) |
|||
{ |
|||
m_canvas->SetRenderPivot( visible ); |
|||
|
|||
m_canvas->Request_refresh(); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const |
|||
{ |
|||
RAY mouseRay; |
|||
mouseRay.Init( m_rayOrigin, m_rayDirection ); |
|||
|
|||
float hit; |
|||
glm::vec3 vec; |
|||
|
|||
// Test it with the board bounding box
|
|||
if( m_canvas->GetBoardAdapter().GetBBox().Intersect( mouseRay, &hit ) ) |
|||
{ |
|||
vec = mouseRay.at( hit ); |
|||
position = { vec.x, vec.y, vec.z }; |
|||
return 0; |
|||
} |
|||
|
|||
return navlib::make_result_code( navlib::navlib_errc::no_data_available ); |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitAperture( double aperture ) |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported ); |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction ) |
|||
{ |
|||
m_rayDirection = { direction.x, direction.y, direction.z }; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye ) |
|||
{ |
|||
m_rayOrigin = { eye.x, eye.y, eye.z }; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetHitSelectionOnly( bool onlySelection ) |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported ); |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetActiveCommand( std::string commandId ) |
|||
{ |
|||
if( commandId.empty() ) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList(); |
|||
TOOL_ACTION* context = nullptr; |
|||
|
|||
for( std::list<TOOL_ACTION*>::const_iterator it = actions.begin(); it != actions.end(); it++ ) |
|||
{ |
|||
TOOL_ACTION* action = *it; |
|||
std::string nm = action->GetName(); |
|||
|
|||
if( commandId == nm ) |
|||
{ |
|||
context = action; |
|||
} |
|||
} |
|||
|
|||
if( context != nullptr ) |
|||
{ |
|||
wxWindow* parent = m_canvas->GetParent(); |
|||
|
|||
// Only allow command execution if the window is enabled. i.e. there is not a modal dialog
|
|||
// currently active.
|
|||
if( parent->IsEnabled() ) |
|||
{ |
|||
TOOL_MANAGER* tool_manager = static_cast<PCB_BASE_FRAME*>( parent )->GetToolManager(); |
|||
|
|||
if( tool_manager == nullptr ) |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation ); |
|||
} |
|||
|
|||
// Get the selection to use to test if the action is enabled
|
|||
SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection(); |
|||
|
|||
bool runAction = true; |
|||
|
|||
if( const ACTION_CONDITIONS* aCond = |
|||
tool_manager->GetActionManager()->GetCondition( *context ) ) |
|||
{ |
|||
runAction = aCond->enableCondition( sel ); |
|||
} |
|||
|
|||
if( runAction ) |
|||
{ |
|||
tool_manager->RunAction( *context, true ); |
|||
m_canvas->Request_refresh(); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::invalid_operation ); |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetSettingsChanged( long change ) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetMotionFlag( bool value ) |
|||
{ |
|||
m_capIsMoving = value; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetTransaction( long value ) |
|||
{ |
|||
if( value != 0L ) |
|||
{ |
|||
} |
|||
else |
|||
{ |
|||
m_canvas->Request_refresh( true ); |
|||
wxLogTrace( m_logTrace, wxT( "End of transaction" ) ); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position ) |
|||
{ |
|||
return navlib::make_result_code( navlib::navlib_errc::function_not_supported ); |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::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 NL_3D_VIEWER_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const |
|||
{ |
|||
// Use the right-handed coordinate system X-right, Z-up, Y-in (row vectors)
|
|||
matrix = { 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1 }; |
|||
return 0; |
|||
} |
|||
|
|||
long NL_3D_VIEWER_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const |
|||
{ |
|||
isRotatable = true; |
|||
return 0; |
|||
} |
|||
@ -0,0 +1,133 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2021 3Dconnexion |
|||
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* |
|||
* 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 <http://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
/** |
|||
* @file nl_3d_viewer_plugin_impl.h |
|||
* @brief Declaration of the NL_3D_VIEWER_PLUGIN_IMPL class |
|||
*/ |
|||
|
|||
#ifndef NL_3D_VIEWER_PLUGIN_IMPL_H_ |
|||
#define NL_3D_VIEWER_PLUGIN_IMPL_H_ |
|||
|
|||
// TDxWare SDK. |
|||
#include <SpaceMouse/CNavigation3D.hpp> |
|||
|
|||
// KiCAD |
|||
#include <include/plugins/3dapi/xv3d_types.h> |
|||
|
|||
// wx |
|||
#include <wx/chartype.h> |
|||
|
|||
// glm |
|||
#include <glm/glm.hpp> |
|||
|
|||
// Forward declarations. |
|||
class EDA_3D_CANVAS; |
|||
class TRACK_BALL; |
|||
|
|||
// Convenience typedef. |
|||
typedef TDx::SpaceMouse::Navigation3D::CNavigation3D NAV_3D; |
|||
|
|||
/** |
|||
* The class that implements the accessors and mutators required for |
|||
* 3D navigation in an EDA_3D_CANVAS using a SpaceMouse. |
|||
*/ |
|||
class NL_3D_VIEWER_PLUGIN_IMPL : public NAV_3D |
|||
{ |
|||
public: |
|||
/** |
|||
* Initializes a new instance of the NL_3DVIEWER_PLUGIN. |
|||
* |
|||
* @param aCanvas is the viewport to be navigated. |
|||
*/ |
|||
NL_3D_VIEWER_PLUGIN_IMPL( EDA_3D_CANVAS* aCanvas ); |
|||
|
|||
virtual ~NL_3D_VIEWER_PLUGIN_IMPL(); |
|||
|
|||
/** |
|||
* Set the connection to the 3Dconnexion driver to the focus state so that |
|||
* 3DMouse data is routed here. |
|||
* |
|||
* @param aFocus is true to set the connection active. |
|||
*/ |
|||
void SetFocus( bool aFocus = true ); |
|||
|
|||
private: |
|||
void exportCommandsAndImages(); |
|||
|
|||
long GetCameraMatrix( navlib::matrix_t& aMatrix ) const override; |
|||
long GetPointerPosition( navlib::point_t& aPosition ) const override; |
|||
long GetViewExtents( navlib::box_t& aExtents ) const override; |
|||
long GetViewFOV( double& aFov ) const override; |
|||
long GetViewFrustum( navlib::frustum_t& aFrustum ) const override; |
|||
long GetIsViewPerspective( navlib::bool_t& aPerspective ) const override; |
|||
long SetCameraMatrix( const navlib::matrix_t& aMatrix ) override; |
|||
long SetViewExtents( const navlib::box_t& aExtents ) override; |
|||
long SetViewFOV( double aFov ) override; |
|||
long SetViewFrustum( const navlib::frustum_t& aFrustum ) override; |
|||
long GetModelExtents( navlib::box_t& aExtents ) const override; |
|||
long GetSelectionExtents( navlib::box_t& aExtents ) const override; |
|||
long GetSelectionTransform( navlib::matrix_t& aTransform ) const override; |
|||
long GetIsSelectionEmpty( navlib::bool_t& aEmpty ) const override; |
|||
long SetSelectionTransform( const navlib::matrix_t& aMatrix ) override; |
|||
long GetPivotPosition( navlib::point_t& aPosition ) const override; |
|||
long IsUserPivot( navlib::bool_t& aUserPivot ) const override; |
|||
long SetPivotPosition( const navlib::point_t& aPosition ) override; |
|||
long GetPivotVisible( navlib::bool_t& aVisible ) const override; |
|||
long SetPivotVisible( bool aVisible ) override; |
|||
long GetHitLookAt( navlib::point_t& aPosition ) const override; |
|||
long SetHitAperture( double aAperture ) override; |
|||
long SetHitDirection( const navlib::vector_t& aDirection ) override; |
|||
long SetHitLookFrom( const navlib::point_t& aPosition ) override; |
|||
long SetHitSelectionOnly( bool aSelectionOnly ) override; |
|||
long SetActiveCommand( std::string aCommandId ) override; |
|||
|
|||
long SetSettingsChanged( long aChangeNumber ) override; |
|||
long SetMotionFlag( bool aValue ) override; |
|||
long SetTransaction( long aValue ) override; |
|||
long SetCameraTarget( const navlib::point_t& aPosition ) override; |
|||
|
|||
long GetFrontView( navlib::matrix_t& aMatrix ) const override; |
|||
long GetCoordinateSystem( navlib::matrix_t& aMatrix ) const override; |
|||
long GetIsViewRotatable( navlib::bool_t& isRotatable ) const override; |
|||
|
|||
private: |
|||
EDA_3D_CANVAS* m_canvas; |
|||
TRACK_BALL* m_camera; |
|||
bool m_capIsMoving; |
|||
double m_newWidth; |
|||
SFVEC3F m_rayOrigin; |
|||
SFVEC3F m_rayDirection; |
|||
|
|||
// The cached CAMERA affine matrix. This is used to determine if the camera has been |
|||
// moved. The camera matrix is the world to camera affine. |
|||
mutable glm::mat4 m_cameraMatrix; |
|||
|
|||
|
|||
/** |
|||
* Trace mask used to enable or disable the trace output of this class. |
|||
* The debug output can be turned on by setting the WXTRACE environment variable to |
|||
* "KI_TRACE_NL_3DVIEWER_PLUGIN". See the wxWidgets documentation on wxLogTrace for |
|||
* more information. |
|||
*/ |
|||
static const wxChar* m_logTrace; |
|||
}; |
|||
|
|||
#endif // NL_3D_VIEWER_PLUGIN_IMPL_H_ |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue