KiCad PCB EDA Suite
Loading...
Searching...
No Matches
nl_pcbnew_plugin_impl.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2021 3Dconnexion
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
22
23// KiCAD includes
24#include <board.h>
25#include <pcb_base_frame.h>
26#include <bitmaps.h>
29#include <view/view.h>
31#include <tool/action_manager.h>
32#include <tool/tool_action.h>
33#include <tool/tool_manager.h>
34
35// stdlib
36#include <list>
37#include <map>
38#include <memory>
39#include <utility>
40#include <vector>
41#include <cfloat>
42
43#include <wx/log.h>
44#include <wx/mstream.h>
45
46
54const wxChar* NL_PCBNEW_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_PCBNEW_PLUGIN" );
55
56
58 CNavigation3D( false, false ),
59 m_viewport2D( aViewport ),
60 m_isMoving( false )
61{
64
65 PutProfileHint( "KiCAD PCB" );
66
67 // Use the default settings for the connexion to the 3DMouse navigation
68 // They are use a single-threaded threading model and row vectors.
69 EnableNavigation( true );
70
71 // Use the SpaceMouse internal timing source for the frame rate.
72 PutFrameTimingSource( TimingSource::SpaceMouse );
73
75}
76
77
79{
80 EnableNavigation( false );
81}
82
83
85{
86 wxLogTrace( m_logTrace, wxT( "NL_PCBNEW_PLUGIN_IMPL::SetFocus %d" ), aFocus );
87 NAV_3D::Write( navlib::focus_k, aFocus );
88}
89
90// temporary store for the command categories
91typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE;
92
101static void add_category( const std::string& aCategoryPath, CATEGORY_STORE& aCategoryStore )
102{
103 using TDx::SpaceMouse::CCategory;
104
105 CATEGORY_STORE::iterator parent_iter = aCategoryStore.begin();
106 std::string::size_type pos = aCategoryPath.find_last_of( '.' );
107
108 if( pos != std::string::npos )
109 {
110 std::string parentPath = aCategoryPath.substr( 0, pos );
111 parent_iter = aCategoryStore.find( parentPath );
112
113 if( parent_iter == aCategoryStore.end() )
114 {
115 add_category( parentPath, aCategoryStore );
116 parent_iter = aCategoryStore.find( parentPath );
117 }
118 }
119
120 std::string name = aCategoryPath.substr( pos + 1 );
121 auto categoryNode = std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
122
123 aCategoryStore.insert( aCategoryStore.end(), { aCategoryPath, categoryNode.get() } );
124
125 if( parent_iter != aCategoryStore.end() )
126 parent_iter->second->push_back( std::move( categoryNode ) );
127}
128
129
131{
132 wxLogTrace( m_logTrace, wxT( "NL_PCBNEW_PLUGIN_IMPL::exportCommandsAndImages" ) );
133
134 std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
135
136 if( actions.size() == 0 )
137 return;
138
139 using TDx::SpaceMouse::CCommand;
140 using TDx::SpaceMouse::CCommandSet;
141
142 // The root action set node
143 CCommandSet commandSet( "PCB_DRAW_PANEL_GAL", "PCB Viewer" );
144
145 // Activate the command set
146 NAV_3D::PutActiveCommands( commandSet.GetId() );
147
148 // temporary store for the categories
149 CATEGORY_STORE categoryStore;
150
151 std::vector<TDx::CImage> vImages;
152
153 // add the action set to the category_store
154 categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) );
155
156 std::list<TOOL_ACTION*>::const_iterator it;
157
158 for( it = actions.begin(); it != actions.end(); ++it )
159 {
160 const TOOL_ACTION* action = *it;
161 std::string label = action->GetMenuLabel().ToStdString();
162
163 if( label.empty() )
164 continue;
165
166 std::string name = action->GetName();
167
168 // Do no export commands for the 3DViewer app.
169
170 if( name.rfind( "3DViewer.", 0 ) == 0 )
171 continue;
172
173 std::string strCategory = action->GetToolName();
174 CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
175
176 if( iter == categoryStore.end() )
177 {
178 add_category( strCategory, categoryStore );
179 iter = categoryStore.find( strCategory );
180 }
181
182 std::string description = action->GetDescription().ToStdString();
183
184 // Arbitrary 8-bit data stream
185 wxMemoryOutputStream imageStream;
186
187 if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
188 {
189 wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
190 image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
191 image.Destroy();
192
193 if( imageStream.GetSize() )
194 {
195 wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
196 TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
197 tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
198 streamBuffer->GetBufferStart() ),
199 streamBuffer->GetBufferSize() ),
200 0 );
201
202 wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
203 vImages.push_back( std::move( tdxImage ) );
204 }
205 }
206
207 if( iter != categoryStore.end() )
208 {
209 wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
210 name, description, iter->first );
211
212 iter->second->push_back( CCommand( name, label, description ) );
213 }
214 }
215
216 NAV_3D::AddCommandSet( commandSet );
217 NAV_3D::AddImages( vImages );
218}
219
220
221long NL_PCBNEW_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
222{
223 if( !m_view )
224 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
225
227
228 double x = m_view->IsMirroredX() ? -1 : 1;
229 double y = m_view->IsMirroredY() ? 1 : -1;
230
231 // x * y * z = 1 for a right-handed coordinate system.
232 double z = x * y;
233
234 // Note: the connexion has been configured as row vectors, the coordinate system is defined in
235 // NL_PCBNEW_PLUGIN_IMPL::GetCoordinateSystem and the front view in NL_PCBNEW_PLUGIN_IMPL::GetFrontView.
236 matrix = { { { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, m_viewPosition.x, m_viewPosition.y, 0, 1 } } };
237 return 0;
238}
239
240
241long NL_PCBNEW_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
242{
243 if( !m_view )
244 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
245
247
248 position.x = mouse_pointer.x;
249 position.y = mouse_pointer.y;
250 position.z = 0;
251
252 return 0;
253}
254
255
256long NL_PCBNEW_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
257{
258 if( !m_view )
259 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
260
261 double scale = m_viewport2D->GetGAL()->GetWorldScale();
262 BOX2D box = m_view->GetViewport();
263
265
266 extents.min_x = -box.GetWidth() / 2.0;
267 extents.min_y = -box.GetHeight() / 2.0;
268 extents.min_z = m_viewport2D->GetGAL()->GetMinDepth() / scale;
269 extents.max_x = box.GetWidth() / 2.0;
270 extents.max_y = box.GetHeight() / 2.0;
271 extents.max_z = m_viewport2D->GetGAL()->GetMaxDepth() / scale;
272
273 return 0;
274}
275
276
277long NL_PCBNEW_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
278{
279 perspective = false;
280
281 return 0;
282}
283
284
285long NL_PCBNEW_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& matrix )
286{
287 if( !m_view )
288 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
289
290 long result = 0;
291 VECTOR2D viewPos( matrix.m4x4[3][0], matrix.m4x4[3][1] );
292
293 if( !equals( m_view->GetCenter(), m_viewPosition, static_cast<VECTOR2D::coord_type>( FLT_EPSILON ) ) )
294 {
296 result = navlib::make_result_code( navlib::navlib_errc::error );
297 }
298 else
299 {
300 m_view->SetCenter( viewPos );
301 }
302
303 m_viewPosition = viewPos;
304
305 return result;
306}
307
308
309long NL_PCBNEW_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
310{
311 if( !m_view )
312 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
313
314 long result = 0;
315
317 result = navlib::make_result_code( navlib::navlib_errc::error );
318
319 double width = m_viewportWidth;
320 m_viewportWidth = extents.max_x - extents.min_x;
321
322 double scale = width / m_viewportWidth * m_view->GetScale();
324
325 if( !equals( m_view->GetScale(), scale, static_cast<double>( FLT_EPSILON ) ) )
326 result = navlib::make_result_code( navlib::navlib_errc::error );
327
328 return result;
329}
330
331
333{
334 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
335}
336
337
338long NL_PCBNEW_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
339{
340 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
341}
342
343
344long NL_PCBNEW_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
345{
346 if( !m_view )
347 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
348
349 BOX2I box = static_cast<PCB_BASE_FRAME*>( m_viewport2D->GetParent() )->GetDocumentExtents();
350 box.Normalize();
351
352 double half_depth = 0.1 / m_viewport2D->GetGAL()->GetWorldScale();
353
354 if( box.GetWidth() == 0 && box.GetHeight() == 0 )
355 half_depth = 0;
356
357 extents.min_x = static_cast<double>( box.GetOrigin().x );
358 extents.min_y = static_cast<double>( box.GetOrigin().y );
359 extents.min_z = -half_depth;
360 extents.max_x = static_cast<double>( box.GetEnd().x );
361 extents.max_y = static_cast<double>( box.GetEnd().y );
362 extents.max_z = half_depth;
363
364 return 0;
365}
366
367
368long NL_PCBNEW_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
369{
370 // The coordinate system is defined as x to the right, y down and z into the screen.
371 matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
372 return 0;
373}
374
375
376long NL_PCBNEW_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
377{
378 matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
379 return 0;
380}
381
382
384{
385 empty = true;
386 return 0;
387}
388
389
390long NL_PCBNEW_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
391{
392 isRotatable = false;
393 return 0;
394}
395
396
397long NL_PCBNEW_PLUGIN_IMPL::SetActiveCommand( std::string commandId )
398{
399 if( commandId.empty() )
400 return 0;
401
402 std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
403 TOOL_ACTION* context = nullptr;
404
405 for( std::list<TOOL_ACTION*>::const_iterator it = actions.begin(); it != actions.end(); it++ )
406 {
407 TOOL_ACTION* action = *it;
408 std::string nm = action->GetName();
409
410 if( commandId == nm )
411 context = action;
412 }
413
414 if( context )
415 {
416 wxWindow* parent = m_viewport2D->GetParent();
417
418 // Only allow command execution if the window is enabled. i.e. there is not a modal dialog
419 // currently active.
420 if( parent && parent->IsEnabled() )
421 {
422 TOOLS_HOLDER* tools_holder = dynamic_cast<TOOLS_HOLDER*>( parent );
423 TOOL_MANAGER* tool_manager = tools_holder ? tools_holder->GetToolManager() : nullptr;
424
425 // Only allow for command execution if the tool manager is accessible.
426 if( !tool_manager )
427 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
428
429 // Get the selection to use to test if the action is enabled
430 SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
431
432 bool runAction = true;
433
434 if( const ACTION_CONDITIONS* aCond = tool_manager->GetActionManager()->GetCondition( *context ) )
435 runAction = aCond->enableCondition( sel );
436
437 if( runAction )
438 tool_manager->RunAction( *context );
439 }
440 else
441 {
442 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
443 }
444 }
445
446 return 0;
447}
448
449
451{
452 return 0;
453}
454
455
457{
458 m_isMoving = value;
459
460 return 0;
461}
462
463
465{
466 if( value == 0L )
468
469 return 0;
470}
471
472
473long NL_PCBNEW_PLUGIN_IMPL::GetViewFOV( double& fov ) const
474{
475 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
476}
477
478
479long NL_PCBNEW_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& frustum ) const
480{
481 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
482}
483
484
485long NL_PCBNEW_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
486{
487 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
488}
489
490
491long NL_PCBNEW_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
492{
493 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
494}
495
496
497long NL_PCBNEW_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
498{
499 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
500}
501
502
503long NL_PCBNEW_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
504{
505 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
506}
507
508
509long NL_PCBNEW_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
510{
511 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
512}
513
514
515long NL_PCBNEW_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
516{
517 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
518}
519
520
521long NL_PCBNEW_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
522{
523 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
524}
525
526
528{
529 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
530}
531
532
533long NL_PCBNEW_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
534{
535 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
536}
537
538
540{
541 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
542}
543
544
545long NL_PCBNEW_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
546{
547 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
548}
549
550
551long NL_PCBNEW_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
552{
553 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
554}
555
556
558{
559 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
560}
561
562
563long NL_PCBNEW_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
564{
565 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
566}
const char * name
Definition: DXF_plotter.cpp:62
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:104
const ACTION_CONDITIONS * GetCondition(const TOOL_ACTION &aAction) const
Get the conditions to use for a specific tool action.
static std::list< TOOL_ACTION * > & GetActionList()
Return list of TOOL_ACTIONs.
constexpr const Vec GetEnd() const
Definition: box2.h:212
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:146
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr const Vec & GetOrigin() const
Definition: box2.h:210
KIGFX::VIEW_CONTROLS * GetViewControls() const
Return a pointer to the #VIEW_CONTROLS instance used in the panel.
void ForceRefresh()
Force a redraw.
KIGFX::GAL * GetGAL() const
Return a pointer to the GAL instance used in the panel.
double GetMaxDepth() const
double GetMinDepth() const
double GetWorldScale() const
Get the world scale.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
double GetScale() const
Definition: view.h:276
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:530
const VECTOR2D & GetCenter() const
Return the center point of this VIEW (in world space coordinates).
Definition: view.h:346
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:570
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:250
bool IsMirroredY() const
Return true if view is flipped across the Y axis.
Definition: view.h:258
const BOX2D & GetBoundary() const
Definition: view.h:305
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:596
long GetIsViewRotatable(navlib::bool_t &isRotatable) const override
long SetCameraMatrix(const navlib::matrix_t &aMatrix) override
long GetPivotVisible(navlib::bool_t &aVisible) const override
long GetPointerPosition(navlib::point_t &aPosition) const override
long SetHitLookFrom(const navlib::point_t &aPosition) override
long GetFrontView(navlib::matrix_t &aMatrix) const override
long SetHitSelectionOnly(bool aSelectionOnly) override
long SetViewFOV(double aFov) override
long GetViewFOV(double &aFov) const override
long IsUserPivot(navlib::bool_t &aUserPivot) const override
long SetSettingsChanged(long aChangeNumber) override
void SetFocus(bool aFocus)
Set the connection to the 3Dconnexion driver to the focus state so that 3DMouse data is routed here.
long SetTransaction(long aValue) override
long GetViewExtents(navlib::box_t &aExtents) const override
long GetPivotPosition(navlib::point_t &aPosition) const override
long GetCoordinateSystem(navlib::matrix_t &aMatrix) const override
long SetPivotVisible(bool aVisible) override
long SetPivotPosition(const navlib::point_t &aPosition) override
long GetIsViewPerspective(navlib::bool_t &aPerspective) const override
NL_PCBNEW_PLUGIN_IMPL(PCB_DRAW_PANEL_GAL *aViewport)
Initializes a new instance of the NL_PCBNEW_PLUGIN_IMPL.
long GetHitLookAt(navlib::point_t &aPosition) const override
long GetSelectionTransform(navlib::matrix_t &aTransform) const override
long SetViewExtents(const navlib::box_t &aExtents) override
void exportCommandsAndImages()
Export the invocable actions and images to the 3Dconnexion UI.
long SetCameraTarget(const navlib::point_t &aPosition) override
long GetCameraMatrix(navlib::matrix_t &aMatrix) const override
long SetMotionFlag(bool aValue) override
long GetViewFrustum(navlib::frustum_t &aFrustum) const override
long GetModelExtents(navlib::box_t &aExtents) const override
long SetViewFrustum(const navlib::frustum_t &aFrustum) override
long GetSelectionExtents(navlib::box_t &aExtents) const override
long SetSelectionTransform(const navlib::matrix_t &aMatrix) override
PCB_DRAW_PANEL_GAL * m_viewport2D
long SetHitAperture(double aAperture) override
long SetHitDirection(const navlib::vector_t &aDirection) override
long GetIsSelectionEmpty(navlib::bool_t &aEmpty) const override
long SetActiveCommand(std::string aCommandId) override
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
virtual SELECTION & GetCurrentSelection()
Get the current selection from the canvas area.
Definition: tools_holder.h:98
Represent a single user action.
Definition: tool_action.h:304
wxString GetMenuLabel() const
Return the translated label for the action.
BITMAPS GetIcon() const
Return an icon associated with the action.
Definition: tool_action.h:459
std::string GetToolName() const
Return name of the tool associated with the action.
const std::string & GetName() const
Return name of the action.
Definition: tool_action.h:337
wxString GetDescription() const
Master controller class:
Definition: tool_manager.h:62
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:406
ACTION_MANAGER * GetActionManager() const
Definition: tool_manager.h:306
double coord_type
Definition: vector2d.h:74
static bool empty(const wxTextEntryBase *aCtrl)
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
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))
Template to compare two glm::mat<T> values for equality within a required epsilon.
CATEGORY_STORE::iterator add_category(std::string aCategoryPath, CATEGORY_STORE &aCategoryStore)
Add a category to the store.
std::map< std::string, TDx::CCommandTreeNode * > CATEGORY_STORE
std::map< std::string, TDx::CCommandTreeNode * > CATEGORY_STORE
static void add_category(const std::string &aCategoryPath, CATEGORY_STORE &aCategoryStore)
Add a category to the store.
Declaration of the NL_PCBNEW_PLUGIN_IMPL class.
const int scale
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
WX_VIEW_CONTROLS class definition.