KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 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
25#include <sch_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_SCHEMATIC_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_SCHEMATIC_PLUGIN" );
54
55
57 CNavigation3D( false, false ),
58 m_viewport2D( nullptr ),
59 m_view( nullptr ),
60 m_isMoving( false ),
61 m_viewportWidth( 0.0 )
62{
63 PutProfileHint( "KiCAD Eeschema" );
64}
65
66
68{
69 EnableNavigation( false );
70}
71
72
74{
75 bool init = m_viewport2D == nullptr;
76
77 m_viewport2D = aViewport;
78
79 if( m_viewport2D != nullptr )
80 {
81 m_view = static_cast<KIGFX::SCH_VIEW*>( m_viewport2D->GetView() );
82 m_viewportWidth = m_view->GetBoundary().GetWidth();
83
84 if( init )
85 {
86 // Use the default settings for the connexion to the 3DMouse navigation
87 // They are use a single-threaded threading model and row vectors.
88 EnableNavigation( true );
89
90 // Use the SpaceMouse internal timing source for the frame rate.
91 PutFrameTimingSource( TimingSource::SpaceMouse );
92
94 }
95 }
96}
97
98
100{
101 wxLogTrace( m_logTrace, wxT( "NL_SCHEMATIC_PLUGIN_IMPL::SetFocus %d" ), aFocus );
102 NAV_3D::Write( navlib::focus_k, aFocus );
103}
104
105// temporary store for the command categories
106typedef std::map<std::string, TDx::CCommandTreeNode*> CATEGORY_STORE;
107
108
117static void add_category( const std::string& aCategoryPath, CATEGORY_STORE& aCategoryStore )
118{
119 using TDx::SpaceMouse::CCategory;
120
121 CATEGORY_STORE::iterator parent_iter = aCategoryStore.begin();
122 std::string::size_type pos = aCategoryPath.find_last_of( '.' );
123
124 if( pos != std::string::npos )
125 {
126 std::string parentPath = aCategoryPath.substr( 0, pos );
127 parent_iter = aCategoryStore.find( parentPath );
128
129 if( parent_iter == aCategoryStore.end() )
130 {
131 add_category( parentPath, aCategoryStore );
132 parent_iter = aCategoryStore.find( parentPath );
133 }
134 }
135
136 std::string name = aCategoryPath.substr( pos + 1 );
137 auto categoryNode = std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
138
139 aCategoryStore.insert( aCategoryStore.end(), { aCategoryPath, categoryNode.get() } );
140
141 if( parent_iter != aCategoryStore.end() )
142 parent_iter->second->push_back( std::move( categoryNode ) );
143}
144
145
147{
148 wxLogTrace( m_logTrace, wxT( "NL_SCHEMATIC_PLUGIN_IMPL::exportCommandsAndImages" ) );
149
150 std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
151
152 if( actions.size() == 0 )
153 return;
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->GetMenuLabel().ToStdString();
178
179 if( label.empty() )
180 continue;
181
182 std::string name = action->GetName();
183
184 // Do no export commands for the 3DViewer app.
185
186 if( name.rfind( "3DViewer.", 0 ) == 0 )
187 continue;
188
189 std::string strCategory = action->GetToolName();
190 CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
191
192 if( iter == categoryStore.end() )
193 {
194 add_category( strCategory, categoryStore );
195 iter = categoryStore.find( strCategory );
196 }
197
198 std::string description = action->GetDescription().ToStdString();
199
200 // Arbitrary 8-bit data stream
201 wxMemoryOutputStream imageStream;
202
203 if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
204 {
205 wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
206 image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
207 image.Destroy();
208
209 if( imageStream.GetSize() )
210 {
211 wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
212 TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
213 tdxImage.AssignImage( std::string( reinterpret_cast<const char*>(
214 streamBuffer->GetBufferStart() ),
215 streamBuffer->GetBufferSize() ),
216 0 );
217
218 wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
219 vImages.push_back( std::move( tdxImage ) );
220 }
221 }
222
223 if( iter != categoryStore.end() )
224 {
225 wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
226 name, description, iter->first );
227
228 iter->second->push_back( CCommand( name, label, description ) );
229 }
230 }
231
232 NAV_3D::AddCommandSet( commandSet );
233 NAV_3D::AddImages( vImages );
234}
235
236
237long NL_SCHEMATIC_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
238{
239 if( !m_view )
240 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
241
242 m_viewPosition = m_view->GetCenter();
243
244 double x = m_view->IsMirroredX() ? -1 : 1;
245 double y = m_view->IsMirroredY() ? 1 : -1;
246
247 // x * y * z = 1 for a right-handed coordinate system.
248 double z = x * y;
249
250 // Note: the connexion has been configured as row vectors, the coordinate system is defined in
251 // NL_SCHEMATIC_PLUGIN_IMPL::GetCoordinateSystem and the front view in NL_SCHEMATIC_PLUGIN_IMPL::GetFrontView.
252 matrix = { { { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, m_viewPosition.x, m_viewPosition.y, 0, 1 } } };
253 return 0;
254}
255
256
257long NL_SCHEMATIC_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
258{
259 if( !m_view )
260 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
261
262 VECTOR2D mouse_pointer = m_viewport2D->GetViewControls()->GetMousePosition();
263
264 position.x = mouse_pointer.x;
265 position.y = mouse_pointer.y;
266 position.z = 0;
267
268 return 0;
269}
270
271
272long NL_SCHEMATIC_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
273{
274 if( !m_view )
275 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
276
277 double scale = m_viewport2D->GetGAL()->GetWorldScale();
278 BOX2D box = m_view->GetViewport();
279
281
282 extents.min_x = -box.GetWidth() / 2.0;
283 extents.min_y = -box.GetHeight() / 2.0;
284 extents.min_z = m_viewport2D->GetGAL()->GetMinDepth() / scale;
285 extents.max_x = box.GetWidth() / 2.0;
286 extents.max_y = box.GetHeight() / 2.0;
287 extents.max_z = m_viewport2D->GetGAL()->GetMaxDepth() / scale;
288 return 0;
289}
290
291
292long NL_SCHEMATIC_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
293{
294 perspective = false;
295
296 return 0;
297}
298
299
300long NL_SCHEMATIC_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& matrix )
301{
302 if( !m_view )
303 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
304
305 long result = 0;
306 VECTOR2D viewPos( matrix.m4x4[3][0], matrix.m4x4[3][1] );
307
308 if( !equals( m_view->GetCenter(), m_viewPosition, static_cast<VECTOR2D::coord_type>( FLT_EPSILON ) ) )
309 {
310 m_view->SetCenter( viewPos + m_view->GetCenter() - m_viewPosition );
311 result = navlib::make_result_code( navlib::navlib_errc::error );
312 }
313 else
314 {
315 m_view->SetCenter( viewPos );
316 }
317
318 m_viewPosition = viewPos;
319
320 return result;
321}
322
323
324long NL_SCHEMATIC_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
325{
326 if( !m_view )
327 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
328
329 long result = 0;
330
331 if( m_viewportWidth != m_view->GetViewport().GetWidth() )
332 result = navlib::make_result_code( navlib::navlib_errc::error );
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();
338 m_view->SetScale( scale, m_view->GetCenter() );
339
340 if( !equals( m_view->GetScale(), scale, static_cast<double>( FLT_EPSILON ) ) )
341 result = navlib::make_result_code( navlib::navlib_errc::error );
342
343 return result;
344}
345
346
348{
349 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
350}
351
352
353long NL_SCHEMATIC_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
354{
355 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
356}
357
358
359long NL_SCHEMATIC_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
360{
361 if( !m_view )
362 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
363
364 BOX2I box = static_cast<SCH_BASE_FRAME*>( m_viewport2D->GetParent() )->GetDocumentExtents();
365 box.Normalize();
366
367 double half_depth = 0.1 / m_viewport2D->GetGAL()->GetWorldScale();
368
369 if( box.GetWidth() == 0 && box.GetHeight() == 0 )
370 half_depth = 0;
371
372 extents.min_x = static_cast<double>( box.GetOrigin().x );
373 extents.min_y = static_cast<double>( box.GetOrigin().y );
374 extents.min_z = -half_depth;
375 extents.max_x = static_cast<double>( box.GetEnd().x );
376 extents.max_y = static_cast<double>( box.GetEnd().y );
377 extents.max_z = half_depth;
378
379 return 0;
380}
381
382
383long NL_SCHEMATIC_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
384{
385 // The coordinate system is defined as x to the right, y down and z into the screen.
386 matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
387 return 0;
388}
389
390
391long NL_SCHEMATIC_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
392{
393 matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
394 return 0;
395}
396
397
399{
400 empty = true;
401 return 0;
402}
403
404
405long NL_SCHEMATIC_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
406{
407 isRotatable = false;
408 return 0;
409}
410
411
413{
414 if( commandId.empty() )
415 return 0;
416
417 std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
418 TOOL_ACTION* context = nullptr;
419
420 for( std::list<TOOL_ACTION*>::const_iterator it = actions.begin(); it != actions.end(); it++ )
421 {
422 TOOL_ACTION* action = *it;
423 std::string nm = action->GetName();
424
425 if( commandId == nm )
426 context = action;
427 }
428
429 if( context )
430 {
431 wxWindow* parent = m_viewport2D->GetParent();
432
433 // Only allow command execution if the window is enabled. i.e. there is not a modal dialog
434 // currently active.
435 if( parent && parent->IsEnabled() )
436 {
437 TOOLS_HOLDER* tools_holder = dynamic_cast<TOOLS_HOLDER*>( parent );
438 TOOL_MANAGER* tool_manager = tools_holder ? tools_holder->GetToolManager() : nullptr;
439
440 // Only allow for command execution if the tool manager is accessible.
441 if( !tool_manager )
442 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
443
444 // Get the selection to use to test if the action is enabled
445 SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
446
447 bool runAction = true;
448
449 if( const ACTION_CONDITIONS* aCond = tool_manager->GetActionManager()->GetCondition( *context ) )
450 runAction = aCond->enableCondition( sel );
451
452 if( runAction )
453 tool_manager->RunAction( *context );
454 }
455 else
456 {
457 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
458 }
459 }
460
461 return 0;
462}
463
464
466{
467 return 0;
468}
469
470
472{
473 m_isMoving = value;
474
475 return 0;
476}
477
478
480{
481 if( value == 0L )
482 m_viewport2D->ForceRefresh();
483
484 return 0;
485}
486
487
489{
490 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
491}
492
493
494long NL_SCHEMATIC_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& frustum ) const
495{
496 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
497}
498
499
500long NL_SCHEMATIC_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
501{
502 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
503}
504
505
506long NL_SCHEMATIC_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
507{
508 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
509}
510
511
512long NL_SCHEMATIC_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
513{
514 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
515}
516
517
518long NL_SCHEMATIC_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
519{
520 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
521}
522
523
524long NL_SCHEMATIC_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
525{
526 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
527}
528
529
530long NL_SCHEMATIC_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
531{
532 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
533}
534
535
536long NL_SCHEMATIC_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
537{
538 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
539}
540
541
543{
544 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
545}
546
547
548long NL_SCHEMATIC_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
549{
550 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
551}
552
553
555{
556 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
557}
558
559
560long NL_SCHEMATIC_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
561{
562 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
563}
564
565
566long NL_SCHEMATIC_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
567{
568 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
569}
570
571
573{
574 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
575}
576
577
578long NL_SCHEMATIC_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
579{
580 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
581}
const char * name
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
@ INVALID_BITMAP
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
BOX2< VECTOR2D > BOX2D
Definition box2.h:923
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
virtual const BOX2I GetDocumentExtents(bool aIncludeAllVisible=true) const
Return bounding box of document with option to not include some items.
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,...
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
virtual SELECTION & GetCurrentSelection()
Get the current selection from the canvas area.
Represent a single user action.
wxString GetMenuLabel() const
Return the translated label for the action.
BITMAPS GetIcon() const
Return an icon associated with the action.
std::string GetToolName() const
Return name of the tool associated with the action.
const std::string & GetName() const
Return name of the action.
wxString GetDescription() const
Master controller class:
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
TOOLS_HOLDER * GetToolHolder() const
ACTION_MANAGER * GetActionManager() const
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
static void add_category(const 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 ...
wxString result
Test unit parsing edge cases and error handling.
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
WX_VIEW_CONTROLS class definition.