KiCad PCB EDA Suite
nl_schematic_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) 2022 3Dconnexion
5 * Copyright (C) 2022 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 <sch_base_frame.h>
25#include <bitmaps.h>
27#include <view/view.h>
29#include <tool/action_manager.h>
30#include <tool/tool_action.h>
31#include <tool/tool_manager.h>
32
33// stdlib
34#include <list>
35#include <map>
36#include <memory>
37#include <utility>
38#include <vector>
39#include <cfloat>
40
41#include <wx/log.h>
42#include <wx/mstream.h>
43
44
52const wxChar* NL_SCHEMATIC_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_SCHEMATIC_PLUGIN" );
53
54
56 CNavigation3D( false, false ), m_viewport2D( nullptr ), m_isMoving( false )
57{
58 PutProfileHint( "KiCAD Eeschema" );
59}
60
61
63{
64 EnableNavigation( false );
65}
66
67
69{
70 bool init = m_viewport2D == nullptr;
71
72 m_viewport2D = aViewport;
73
74 if( m_viewport2D != nullptr )
75 {
76 m_view = static_cast<KIGFX::SCH_VIEW*>( m_viewport2D->GetView() );
78
79 if( init )
80 {
81 // Use the default settings for the connexion to the 3DMouse navigation
82 // They are use a single-threaded threading model and row vectors.
83 EnableNavigation( true );
84
85 // Use the SpaceMouse internal timing source for the frame rate.
86 PutFrameTimingSource( TimingSource::SpaceMouse );
87
89 }
90 }
91}
92
93
95{
96 wxLogTrace( m_logTrace, wxT( "NL_SCHEMATIC_PLUGIN_IMPL::SetFocus %d" ), aFocus );
97 NAV_3D::Write( navlib::focus_k, aFocus );
98}
99
100// temporary store for the command categories
101typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE;
102
103
113static CATEGORY_STORE::iterator add_category( std::string aCategoryPath,
114 CATEGORY_STORE& aCategoryStore )
115{
116 using TDx::SpaceMouse::CCategory;
117
118 CATEGORY_STORE::iterator parent_iter = aCategoryStore.begin();
119 std::string::size_type pos = aCategoryPath.find_last_of( '.' );
120
121 if( pos != std::string::npos )
122 {
123 std::string parentPath = aCategoryPath.substr( 0, pos );
124 parent_iter = aCategoryStore.find( parentPath );
125
126 if( parent_iter == aCategoryStore.end() )
127 {
128 parent_iter = add_category( parentPath, aCategoryStore );
129 }
130 }
131
132 std::string name = aCategoryPath.substr( pos + 1 );
133 std::unique_ptr<CCategory> categoryNode =
134 std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
135
136 CATEGORY_STORE::iterator iter = aCategoryStore.insert(
137 aCategoryStore.end(), CATEGORY_STORE::value_type( aCategoryPath, categoryNode.get() ) );
138
139 parent_iter->second->push_back( std::move( categoryNode ) );
140 return iter;
141}
142
143
145{
146 wxLogTrace( m_logTrace, wxT( "NL_SCHEMATIC_PLUGIN_IMPL::exportCommandsAndImages" ) );
147
148 std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
149
150 if( actions.size() == 0 )
151 {
152 return;
153 }
154
155 using TDx::SpaceMouse::CCommand;
156 using TDx::SpaceMouse::CCommandSet;
157
158 // The root action set node
159 CCommandSet commandSet( "SCHEMATIC_EDITOR", "Schematic Editor" );
160
161 // Activate the command set
162 NAV_3D::PutActiveCommands( commandSet.GetId() );
163
164 // temporary store for the categories
165 CATEGORY_STORE categoryStore;
166
167 std::vector<TDx::CImage> vImages;
168
169 // add the action set to the category_store
170 categoryStore.insert( categoryStore.end(), CATEGORY_STORE::value_type( ".", &commandSet ) );
171
172 std::list<TOOL_ACTION*>::const_iterator it;
173
174 for( it = actions.begin(); it != actions.end(); ++it )
175 {
176 const TOOL_ACTION* action = *it;
177 std::string label = action->GetLabel().ToStdString();
178
179 if( label.empty() )
180 {
181 continue;
182 }
183
184 std::string name = action->GetName();
185
186 // Do no export commands for the 3DViewer app.
187
188 if( name.rfind( "3DViewer.", 0 ) == 0 )
189 {
190 continue;
191 }
192
193 std::string strCategory = action->GetToolName();
194 CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
195
196 if( iter == categoryStore.end() )
197 {
198 iter = add_category( std::move( strCategory ), categoryStore );
199 }
200
201 std::string description = action->GetDescription().ToStdString();
202
203 // Arbitrary 8-bit data stream
204 wxMemoryOutputStream imageStream;
205
206 if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
207 {
208 wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
209 image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
210 image.Destroy();
211
212 if( imageStream.GetSize() )
213 {
214 wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
215 TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
216 tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
217 streamBuffer->GetBufferStart() ),
218 streamBuffer->GetBufferSize() ),
219 0 );
220
221 wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
222 vImages.push_back( std::move( tdxImage ) );
223 }
224 }
225
226 wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
227 name, description, iter->first );
228
229 iter->second->push_back(
230 CCommand( std::move( name ), std::move( label ), std::move( description ) ) );
231 }
232
233 NAV_3D::AddCommandSet( commandSet );
234 NAV_3D::AddImages( vImages );
235}
236
237
238long NL_SCHEMATIC_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
239{
240 if( m_view == nullptr )
241 {
242 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
243 }
244
246
247 double x = m_view->IsMirroredX() ? -1 : 1;
248 double y = m_view->IsMirroredY() ? 1 : -1;
249
250 // x * y * z = 1 for a right-handed coordinate system.
251 double z = x * y;
252
253 // Note: the connexion has been configured as row vectors, the coordinate system is defined in
254 // NL_SCHEMATIC_PLUGIN_IMPL::GetCoordinateSystem and the front view in NL_SCHEMATIC_PLUGIN_IMPL::GetFrontView.
255 matrix = { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, m_viewPosition.x, m_viewPosition.y, 0, 1 };
256 return 0;
257}
258
259
260long NL_SCHEMATIC_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
261{
262 if( m_view == nullptr )
263 {
264 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
265 }
266
268
269 position.x = mouse_pointer.x;
270 position.y = mouse_pointer.y;
271 position.z = 0;
272
273 return 0;
274}
275
276
277long NL_SCHEMATIC_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
278{
279 if( m_view == nullptr )
280 {
281 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
282 }
283
284 double scale = m_viewport2D->GetGAL()->GetWorldScale();
285 BOX2D box = m_view->GetViewport();
286
288
289 extents = navlib::box_t{ -box.GetWidth() / 2.0,
290 -box.GetHeight() / 2.0,
292 box.GetWidth() / 2.0,
293 box.GetHeight() / 2.0,
295 return 0;
296}
297
298
299long NL_SCHEMATIC_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
300{
301 perspective = false;
302
303 return 0;
304}
305
306
307long NL_SCHEMATIC_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& matrix )
308{
309 if( m_view == nullptr )
310 {
311 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
312 }
313
314 long result = 0;
315 VECTOR2D viewPos( matrix.m4x4[3][0], matrix.m4x4[3][1] );
316
318 static_cast<VECTOR2D::coord_type>( FLT_EPSILON ) ) )
319 {
321 result = navlib::make_result_code( navlib::navlib_errc::error );
322 }
323 else
324 {
325 m_view->SetCenter( viewPos );
326 }
327
328 m_viewPosition = viewPos;
329
330 return result;
331}
332
333
334long NL_SCHEMATIC_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
335{
336 if( m_view == nullptr )
337 {
338 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
339 }
340
341 long result = 0;
342
344 {
345 result = navlib::make_result_code( navlib::navlib_errc::error );
346 }
347
348 double width = m_viewportWidth;
349 m_viewportWidth = extents.max_x - extents.min_x;
350
351 double scale = width / m_viewportWidth * m_view->GetScale();
353
354 if( !equals( m_view->GetScale(), scale, static_cast<double>( FLT_EPSILON ) ) )
355 {
356 result = navlib::make_result_code( navlib::navlib_errc::error );
357 }
358
359 return result;
360}
361
362
364{
365 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
366}
367
368
369long NL_SCHEMATIC_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
370{
371 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
372}
373
374
375long NL_SCHEMATIC_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
376{
377 if( m_view == nullptr )
378 {
379 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
380 }
381
382 BOX2I box = static_cast<SCH_BASE_FRAME*>( m_viewport2D->GetParent() )->GetDocumentExtents();
383 box.Normalize();
384
385 double half_depth = 0.1 / m_viewport2D->GetGAL()->GetWorldScale();
386
387 if( box.GetWidth() == 0 && box.GetHeight() == 0 )
388 {
389 half_depth = 0;
390 }
391
392 extents = { static_cast<double>( box.GetOrigin().x ),
393 static_cast<double>( box.GetOrigin().y ),
394 -half_depth,
395 static_cast<double>( box.GetEnd().x ),
396 static_cast<double>( box.GetEnd().y ),
397 half_depth };
398
399 return 0;
400}
401
402
403long NL_SCHEMATIC_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
404{
405 // The coordinate system is defined as x to the right, y down and z into the screen.
406 matrix = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 };
407 return 0;
408}
409
410
411long NL_SCHEMATIC_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
412{
413 matrix = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 };
414 return 0;
415}
416
417
419{
420 empty = true;
421 return 0;
422}
423
424
425long NL_SCHEMATIC_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
426{
427 isRotatable = false;
428 return 0;
429}
430
431
433{
434 if( commandId.empty() )
435 {
436 return 0;
437 }
438
439 std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
440 TOOL_ACTION* context = nullptr;
441
442 for( std::list<TOOL_ACTION*>::const_iterator it = actions.begin(); it != actions.end(); it++ )
443 {
444 TOOL_ACTION* action = *it;
445 std::string nm = action->GetName();
446
447 if( commandId == nm )
448 {
449 context = action;
450 }
451 }
452
453 if( context != nullptr )
454 {
455 wxWindow* parent = m_viewport2D->GetParent();
456
457 // Only allow command execution if the window is enabled. i.e. there is not a modal dialog
458 // currently active.
459
460 if( parent->IsEnabled() )
461 {
462 TOOL_MANAGER* tool_manager = static_cast<SCH_BASE_FRAME*>( parent )->GetToolManager();
463
464 // Get the selection to use to test if the action is enabled
465 SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
466
467 bool runAction = true;
468
469 if( const ACTION_CONDITIONS* aCond =
470 tool_manager->GetActionManager()->GetCondition( *context ) )
471 {
472 runAction = aCond->enableCondition( sel );
473 }
474
475 if( runAction )
476 {
477 tool_manager->RunAction( *context, true );
478 }
479 }
480 else
481 {
482 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
483 }
484 }
485
486 return 0;
487}
488
489
491{
492 return 0;
493}
494
495
497{
498 m_isMoving = value;
499
500 return 0;
501}
502
503
505{
506 if( value == 0L )
507 {
509 }
510
511 return 0;
512}
513
514
516{
517 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
518}
519
520
521long NL_SCHEMATIC_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& frustum ) const
522{
523 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
524}
525
526
527long NL_SCHEMATIC_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
528{
529 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
530}
531
532
533long NL_SCHEMATIC_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
534{
535 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
536}
537
538
539long NL_SCHEMATIC_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
540{
541 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
542}
543
544
545long NL_SCHEMATIC_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
546{
547 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
548}
549
550
551long NL_SCHEMATIC_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
552{
553 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
554}
555
556
557long NL_SCHEMATIC_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
558{
559 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
560}
561
562
563long NL_SCHEMATIC_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
564{
565 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
566}
567
568
570{
571 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
572}
573
574
575long NL_SCHEMATIC_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
576{
577 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
578}
579
580
582{
583 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
584}
585
586
587long NL_SCHEMATIC_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
588{
589 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
590}
591
592
593long NL_SCHEMATIC_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
594{
595 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
596}
597
598
600{
601 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
602}
603
604
605long NL_SCHEMATIC_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
606{
607 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
608}
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.
virtual KIGFX::VIEW * GetView() const
Return a pointer to the #VIEW 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.
void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 }) override
Set the scaling factor, zooming around a given anchor point.
Definition: sch_view.cpp:73
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
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 GetHitLookAt(navlib::point_t &aPosition) const override
long GetSelectionExtents(navlib::box_t &aExtents) const override
long GetCoordinateSystem(navlib::matrix_t &aMatrix) const override
long SetViewFOV(double aFov) override
long GetSelectionTransform(navlib::matrix_t &aTransform) const override
long GetPivotPosition(navlib::point_t &aPosition) const override
long SetPivotPosition(const navlib::point_t &aPosition) override
long SetViewFrustum(const navlib::frustum_t &aFrustum) override
long GetFrontView(navlib::matrix_t &aMatrix) const override
long GetViewFOV(double &aFov) const override
long SetHitAperture(double aAperture) override
long SetSelectionTransform(const navlib::matrix_t &aMatrix) override
void SetFocus(bool aFocus)
Set the connection to the 3Dconnexion driver to the focus state so that 3DMouse data is routed here.
long SetViewExtents(const navlib::box_t &aExtents) override
void SetCanvas(EDA_DRAW_PANEL_GAL *aViewport)
Sets the viewport controlled by the SpaceMouse.
long GetCameraMatrix(navlib::matrix_t &aMatrix) const override
long GetPointerPosition(navlib::point_t &aPosition) const override
long GetPivotVisible(navlib::bool_t &aVisible) const override
void exportCommandsAndImages()
Export the invocable actions and images to the 3Dconnexion UI.
long SetTransaction(long aValue) override
long GetIsViewPerspective(navlib::bool_t &aPerspective) const override
long SetHitSelectionOnly(bool aSelectionOnly) override
NL_SCHEMATIC_PLUGIN_IMPL()
Initializes a new instance of the NL_SCHEMATIC_PLUGIN_IMPL.
long SetHitLookFrom(const navlib::point_t &aPosition) override
long SetActiveCommand(std::string aCommandId) override
long GetViewExtents(navlib::box_t &aExtents) const override
long SetCameraTarget(const navlib::point_t &aPosition) override
long GetIsSelectionEmpty(navlib::bool_t &aEmpty) const override
long SetCameraMatrix(const navlib::matrix_t &aMatrix) override
long GetIsViewRotatable(navlib::bool_t &isRotatable) const override
long SetMotionFlag(bool aValue) override
long SetHitDirection(const navlib::vector_t &aDirection) override
long GetModelExtents(navlib::box_t &aExtents) const override
long IsUserPivot(navlib::bool_t &aUserPivot) const override
long SetSettingsChanged(long aChangeNumber) override
long GetViewFrustum(navlib::frustum_t &aFrustum) const override
long SetPivotVisible(bool aVisible) override
A shim class between EDA_DRAW_FRAME and several derived classes: SYMBOL_EDIT_FRAME,...
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_SCHEMATIC_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.