KiCad PCB EDA Suite
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 (C) 2021 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>
28#include <view/view.h>
30#include <tool/action_manager.h>
31#include <tool/tool_action.h>
32#include <tool/tool_manager.h>
33
34// stdlib
35#include <list>
36#include <map>
37#include <memory>
38#include <utility>
39#include <vector>
40#include <cfloat>
41
42#include <wx/log.h>
43#include <wx/mstream.h>
44
45
53const wxChar* NL_PCBNEW_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_PCBNEW_PLUGIN" );
54
55
57 CNavigation3D( false, false ), m_viewport2D( aViewport ), m_isMoving( false )
58{
61
62 PutProfileHint( "KiCAD PCB" );
63
64 // Use the default settings for the connexion to the 3DMouse navigation
65 // They are use a single-threaded threading model and row vectors.
66 EnableNavigation( true );
67
68 // Use the SpaceMouse internal timing source for the frame rate.
69 PutFrameTimingSource( TimingSource::SpaceMouse );
70
72}
73
74
76{
77 EnableNavigation( false );
78}
79
80
82{
83 wxLogTrace( m_logTrace, wxT( "NL_PCBNEW_PLUGIN_IMPL::SetFocus %d" ), aFocus );
84 NAV_3D::Write( navlib::focus_k, aFocus );
85}
86
87// temporary store for the command categories
88typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE;
89
99static CATEGORY_STORE::iterator add_category( std::string aCategoryPath,
100 CATEGORY_STORE& aCategoryStore )
101{
102 using TDx::SpaceMouse::CCategory;
103
104 CATEGORY_STORE::iterator parent_iter = aCategoryStore.begin();
105 std::string::size_type pos = aCategoryPath.find_last_of( '.' );
106
107 if( pos != std::string::npos )
108 {
109 std::string parentPath = aCategoryPath.substr( 0, pos );
110 parent_iter = aCategoryStore.find( parentPath );
111
112 if( parent_iter == aCategoryStore.end() )
113 {
114 parent_iter = add_category( parentPath, aCategoryStore );
115 }
116 }
117
118 std::string name = aCategoryPath.substr( pos + 1 );
119 std::unique_ptr<CCategory> categoryNode =
120 std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
121
122 CATEGORY_STORE::iterator iter = aCategoryStore.insert(
123 aCategoryStore.end(), CATEGORY_STORE::value_type( aCategoryPath, categoryNode.get() ) );
124
125 parent_iter->second->push_back( std::move( categoryNode ) );
126 return iter;
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 {
138 return;
139 }
140
141 using TDx::SpaceMouse::CCommand;
142 using TDx::SpaceMouse::CCommandSet;
143
144 // The root action set node
145 CCommandSet commandSet( "PCB_DRAW_PANEL_GAL", "PCB Viewer" );
146
147 // Activate the command set
148 NAV_3D::PutActiveCommands( commandSet.GetId() );
149
150 // temporary store for the categories
151 CATEGORY_STORE categoryStore;
152
153 std::vector<TDx::CImage> vImages;
154
155 // add the action set to the category_store
156 categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) );
157
158 std::list<TOOL_ACTION*>::const_iterator it;
159
160 for( it = actions.begin(); it != actions.end(); ++it )
161 {
162 const TOOL_ACTION* action = *it;
163 std::string label = action->GetLabel().ToStdString();
164
165 if( label.empty() )
166 {
167 continue;
168 }
169
170 std::string name = action->GetName();
171
172 // Do no export commands for the 3DViewer app.
173
174 if( name.rfind( "3DViewer.", 0 ) == 0 )
175 {
176 continue;
177 }
178
179 std::string strCategory = action->GetToolName();
180 CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
181
182 if( iter == categoryStore.end() )
183 {
184 iter = add_category( std::move( strCategory ), categoryStore );
185 }
186
187 std::string description = action->GetDescription().ToStdString();
188
189 // Arbitrary 8-bit data stream
190 wxMemoryOutputStream imageStream;
191
192 if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
193 {
194 wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
195 image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
196 image.Destroy();
197
198 if( imageStream.GetSize() )
199 {
200 wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
201 TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
202 tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
203 streamBuffer->GetBufferStart() ),
204 streamBuffer->GetBufferSize() ),
205 0 );
206
207 wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
208 vImages.push_back( std::move( tdxImage ) );
209 }
210 }
211
212 wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
213 name, description, iter->first );
214
215 iter->second->push_back(
216 CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
217 }
218
219 NAV_3D::AddCommandSet( commandSet );
220 NAV_3D::AddImages( vImages );
221}
222
223
224long NL_PCBNEW_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
225{
226 if( m_view == nullptr )
227 {
228 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
229 }
230
232
233 double x = m_view->IsMirroredX() ? -1 : 1;
234 double y = m_view->IsMirroredY() ? 1 : -1;
235
236 // x * y * z = 1 for a right-handed coordinate system.
237 double z = x * y;
238
239 // Note: the connexion has been configured as row vectors, the coordinate system is defined in
240 // NL_PCBNEW_PLUGIN_IMPL::GetCoordinateSystem and the front view in NL_PCBNEW_PLUGIN_IMPL::GetFrontView.
241 matrix = { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, m_viewPosition.x, m_viewPosition.y, 0, 1 };
242 return 0;
243}
244
245
246long NL_PCBNEW_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
247{
248 if( m_view == nullptr )
249 {
250 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
251 }
252
254
255 position.x = mouse_pointer.x;
256 position.y = mouse_pointer.y;
257 position.z = 0;
258
259 return 0;
260}
261
262
263long NL_PCBNEW_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
264{
265 if( m_view == nullptr )
266 {
267 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
268 }
269
270 double scale = m_viewport2D->GetGAL()->GetWorldScale();
271 BOX2D box = m_view->GetViewport();
272
274
275 extents = navlib::box_t{ -box.GetWidth() / 2.0,
276 -box.GetHeight() / 2.0,
278 box.GetWidth() / 2.0,
279 box.GetHeight() / 2.0,
281 return 0;
282}
283
284
285long NL_PCBNEW_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
286{
287 perspective = false;
288
289 return 0;
290}
291
292
293long NL_PCBNEW_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& matrix )
294{
295 if( m_view == nullptr )
296 {
297 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
298 }
299
300 long result = 0;
301 VECTOR2D viewPos( matrix.m4x4[3][0], matrix.m4x4[3][1] );
302
304 static_cast<VECTOR2D::coord_type>( FLT_EPSILON ) ) )
305 {
307 result = navlib::make_result_code( navlib::navlib_errc::error );
308 }
309 else
310 {
311 m_view->SetCenter( viewPos );
312 }
313
314 m_viewPosition = viewPos;
315
316 return result;
317}
318
319
320long NL_PCBNEW_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
321{
322 if( m_view == nullptr )
323 {
324 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
325 }
326
327 long result = 0;
328
330 {
331 result = navlib::make_result_code( navlib::navlib_errc::error );
332 }
333
334 double width = m_viewportWidth;
335 m_viewportWidth = extents.max_x - extents.min_x;
336
337 double scale = width / m_viewportWidth * m_view->GetScale();
339
340 if( !equals( m_view->GetScale(), scale, static_cast<double>( FLT_EPSILON ) ) )
341 {
342 result = navlib::make_result_code( navlib::navlib_errc::error );
343 }
344
345 return result;
346}
347
348
350{
351 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
352}
353
354
355long NL_PCBNEW_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
356{
357 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
358}
359
360
361long NL_PCBNEW_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
362{
363 if( m_view == nullptr )
364 {
365 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
366 }
367
368 BOX2I box = static_cast<PCB_BASE_FRAME*>( m_viewport2D->GetParent() )->GetDocumentExtents();
369 box.Normalize();
370
371 double half_depth = 0.1 / m_viewport2D->GetGAL()->GetWorldScale();
372
373 if( box.GetWidth() == 0 && box.GetHeight() == 0 )
374 {
375 half_depth = 0;
376 }
377
378 extents = { static_cast<double>( box.GetOrigin().x ),
379 static_cast<double>( box.GetOrigin().y ),
380 -half_depth,
381 static_cast<double>( box.GetEnd().x ),
382 static_cast<double>( box.GetEnd().y ),
383 half_depth };
384
385 return 0;
386}
387
388
389long NL_PCBNEW_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
390{
391 // The coordinate system is defined as x to the right, y down and z into the screen.
392 matrix = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 };
393 return 0;
394}
395
396
397long NL_PCBNEW_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
398{
399 matrix = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 };
400 return 0;
401}
402
403
405{
406 empty = true;
407 return 0;
408}
409
410
411long NL_PCBNEW_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
412{
413 isRotatable = false;
414 return 0;
415}
416
417
418long NL_PCBNEW_PLUGIN_IMPL::SetActiveCommand( std::string commandId )
419{
420 if( commandId.empty() )
421 {
422 return 0;
423 }
424
425 std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
426 TOOL_ACTION* context = nullptr;
427
428 for( std::list<TOOL_ACTION*>::const_iterator it = actions.begin(); it != actions.end(); it++ )
429 {
430 TOOL_ACTION* action = *it;
431 std::string nm = action->GetName();
432
433 if( commandId == nm )
434 {
435 context = action;
436 }
437 }
438
439 if( context != nullptr )
440 {
441 wxWindow* parent = m_viewport2D->GetParent();
442
443 // Only allow command execution if the window is enabled. i.e. there is not a modal dialog
444 // currently active.
445
446 if( parent->IsEnabled() )
447 {
448 TOOL_MANAGER* tool_manager = static_cast<PCB_BASE_FRAME*>( parent )->GetToolManager();
449
450 // Get the selection to use to test if the action is enabled
451 SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
452
453 bool runAction = true;
454
455 if( const ACTION_CONDITIONS* aCond =
456 tool_manager->GetActionManager()->GetCondition( *context ) )
457 {
458 runAction = aCond->enableCondition( sel );
459 }
460
461 if( runAction )
462 {
463 tool_manager->RunAction( *context, true );
464 }
465 }
466 else
467 {
468 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
469 }
470 }
471
472 return 0;
473}
474
475
477{
478 return 0;
479}
480
481
483{
484 m_isMoving = value;
485
486 return 0;
487}
488
489
491{
492 if( value == 0L )
493 {
495 }
496
497 return 0;
498}
499
500
501long NL_PCBNEW_PLUGIN_IMPL::GetViewFOV( double& fov ) const
502{
503 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
504}
505
506
507long NL_PCBNEW_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& frustum ) const
508{
509 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
510}
511
512
513long NL_PCBNEW_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
514{
515 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
516}
517
518
519long NL_PCBNEW_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
520{
521 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
522}
523
524
525long NL_PCBNEW_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
526{
527 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
528}
529
530
531long NL_PCBNEW_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
532{
533 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
534}
535
536
537long NL_PCBNEW_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
538{
539 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
540}
541
542
543long NL_PCBNEW_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
544{
545 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
546}
547
548
549long NL_PCBNEW_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
550{
551 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
552}
553
554
556{
557 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
558}
559
560
561long NL_PCBNEW_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
562{
563 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
564}
565
566
568{
569 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
570}
571
572
573long NL_PCBNEW_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
574{
575 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
576}
577
578
579long NL_PCBNEW_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
580{
581 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
582}
583
584
586{
587 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
588}
589
590
591long NL_PCBNEW_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
592{
593 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
594}
const char * name
Definition: DXF_plotter.cpp:56
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:105
@ INVALID_BITMAP
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.
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:119
const Vec & GetOrigin() const
Definition: box2.h:183
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
const Vec GetEnd() const
Definition: box2.h:185
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:269
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:508
const VECTOR2D & GetCenter() const
Return the center point of this VIEW (in world space coordinates).
Definition: view.h:339
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:548
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:243
bool IsMirroredY() const
Return true if view is flipped across the Y axis.
Definition: view.h:251
const BOX2D & GetBoundary() const
Definition: view.h:298
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:574
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.
virtual SELECTION & GetCurrentSelection()
Get the current selection from the canvas area.
Definition: tools_holder.h:101
Represent a single user action.
Definition: tool_action.h:68
wxString GetLabel() const
Definition: tool_action.cpp:83
std::string GetToolName() const
Return name of the tool associated with the action.
const BITMAPS GetIcon() const
Return an icon associated with the action.
Definition: tool_action.h:192
wxString GetDescription(bool aIncludeHotkey=true) const
Definition: tool_action.cpp:97
const std::string & GetName() const
Return name of the action.
Definition: tool_action.h:101
Master controller class:
Definition: tool_manager.h:55
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:296
ACTION_MANAGER * GetActionManager() const
Definition: tool_manager.h:196
double coord_type
Definition: vector2d.h:77
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.
std::map< std::string, TDx::CCommandTreeNode * > CATEGORY_STORE
std::map< std::string, TDx::CCommandTreeNode * > CATEGORY_STORE
static CATEGORY_STORE::iterator add_category(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.