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