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