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
421 if( parent->IsEnabled() )
422 {
423 TOOL_MANAGER* tool_manager = static_cast<PCB_BASE_FRAME*>( parent )->GetToolManager();
424
425 // Get the selection to use to test if the action is enabled
426 SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
427
428 bool runAction = true;
429
430 if( const ACTION_CONDITIONS* aCond =
431 tool_manager->GetActionManager()->GetCondition( *context ) )
432 {
433 runAction = aCond->enableCondition( sel );
434 }
435
436 if( runAction )
437 tool_manager->RunAction( *context );
438 }
439 else
440 {
441 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
442 }
443 }
444
445 return 0;
446}
447
448
450{
451 return 0;
452}
453
454
456{
457 m_isMoving = value;
458
459 return 0;
460}
461
462
464{
465 if( value == 0L )
467
468 return 0;
469}
470
471
472long NL_PCBNEW_PLUGIN_IMPL::GetViewFOV( double& fov ) const
473{
474 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
475}
476
477
478long NL_PCBNEW_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& frustum ) const
479{
480 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
481}
482
483
484long NL_PCBNEW_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
485{
486 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
487}
488
489
490long NL_PCBNEW_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
491{
492 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
493}
494
495
496long NL_PCBNEW_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
497{
498 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
499}
500
501
502long NL_PCBNEW_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
503{
504 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
505}
506
507
508long NL_PCBNEW_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
509{
510 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
511}
512
513
514long NL_PCBNEW_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
515{
516 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
517}
518
519
520long NL_PCBNEW_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
521{
522 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
523}
524
525
527{
528 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
529}
530
531
532long NL_PCBNEW_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
533{
534 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
535}
536
537
539{
540 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
541}
542
543
544long NL_PCBNEW_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
545{
546 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
547}
548
549
550long NL_PCBNEW_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
551{
552 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
553}
554
555
557{
558 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
559}
560
561
562long NL_PCBNEW_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
563{
564 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
565}
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:272
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:520
const VECTOR2D & GetCenter() const
Return the center point of this VIEW (in world space coordinates).
Definition: view.h:342
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:560
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:246
bool IsMirroredY() const
Return true if view is flipped across the Y axis.
Definition: view.h:254
const BOX2D & GetBoundary() const
Definition: view.h:301
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:586
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: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.