KiCad PCB EDA Suite
Loading...
Searching...
No Matches
nl_gerbview_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) 2024 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 <gerbview_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_GERBVIEW_PLUGIN_IMPL::m_logTrace = wxT( "KI_TRACE_NL_GERBVIEW_PLUGIN" );
54
55
56NL_GERBVIEW_PLUGIN_IMPL::NL_GERBVIEW_PLUGIN_IMPL() : CNavigation3D( false, false )
57{
58 PutProfileHint( "KiCAD Gerbview" );
59}
60
61
63{
64 std::error_code m_errCode;
65 EnableNavigation( false, m_errCode );
66
67 if( m_errCode.value() != 0 )
68 {
69 wxLogTrace( wxT( "KI_TRACE_NAVLIB" ),
70 wxT( "Error occured when calling EnableNavigation. Error code: %d" ),
71 m_errCode.value() );
72 }
73}
74
75
77{
78 m_viewport2D = aViewport;
79
80 if( m_viewport2D == nullptr )
81 return;
82
84
85 if( m_view == nullptr )
86 return;
87
89
90 if( !IsEnabled() )
91 {
92 // Use the default settings for the connexion to the 3DMouse navigation
93 // They are use a single-threaded threading model and row vectors.
94 EnableNavigation( true );
95
96 // Use the SpaceMouse internal timing source for the frame rate.
97 PutFrameTimingSource( TimingSource::SpaceMouse );
98
100 }
101}
102
103
105{
106 wxLogTrace( m_logTrace, wxT( "NL_GERBVIEW_PLUGIN_IMPL::SetFocus %d" ), aFocus );
107 NAV_3D::Write( navlib::focus_k, aFocus );
108}
109
110// temporary store for the command categories
111using CATEGORY_STORE = std::map<std::string, TDx::CCommandTreeNode*, std::less<>>;
112
113
122static void add_category( const std::string& aCategoryPath, CATEGORY_STORE& aCategoryStore )
123{
124 using TDx::SpaceMouse::CCategory;
125
126 auto parent_iter = aCategoryStore.begin();
127 std::string::size_type pos = aCategoryPath.find_last_of( '.' );
128
129 if( pos != std::string::npos )
130 {
131 std::string parentPath = aCategoryPath.substr( 0, pos );
132
133 if( !aCategoryStore.contains( parentPath ) )
134 {
135 add_category( parentPath, aCategoryStore );
136 parent_iter = aCategoryStore.find( parentPath );
137 }
138 }
139
140 std::string name = aCategoryPath.substr( pos + 1 );
141 auto categoryNode = std::make_unique<CCategory>( aCategoryPath.c_str(), name.c_str() );
142
143 aCategoryStore.try_emplace( aCategoryStore.end(), aCategoryPath, categoryNode.get() );
144
145 if( parent_iter != aCategoryStore.end() )
146 parent_iter->second->push_back( std::move( categoryNode ) );
147}
148
149
158static void try_add_category( const std::string& aCategoryPath, CATEGORY_STORE& aCategoryStore )
159{
160 if( !aCategoryStore.contains( aCategoryPath ) )
161 add_category( aCategoryPath, aCategoryStore );
162}
163
164
166{
167 wxLogTrace( m_logTrace, wxT( "NL_GERBVIEW_PLUGIN_IMPL::exportCommandsAndImages" ) );
168
169 std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList();
170
171 if( actions.empty() )
172 return;
173
174 using TDx::SpaceMouse::CCommand;
175 using TDx::SpaceMouse::CCommandSet;
176
177 // The root action set node
178 CCommandSet commandSet( "GERBER_EDITOR", "Gerber Viewer" );
179
180 // Activate the command set
181 NAV_3D::PutActiveCommands( commandSet.GetId() );
182
183 // temporary store for the categories initialized with action set
184 CATEGORY_STORE categoryStore{ CATEGORY_STORE::value_type( ".", &commandSet ) };
185
186 std::vector<TDx::CImage> vImages;
187
188 for( const auto action : actions )
189 {
190 std::string label = action->GetMenuLabel().ToStdString();
191
192 if( label.empty() )
193 continue;
194
195 std::string name = action->GetName();
196
197 // Do no export commands for the 3DViewer app.
198
199 if( name.rfind( "3DViewer.", 0 ) == 0 )
200 continue;
201
202 std::string strCategory = action->GetToolName();
203 std::string description = action->GetDescription().ToStdString();
204
205 try_add_category( strCategory, categoryStore );
206 CATEGORY_STORE::iterator iter = categoryStore.find( strCategory );
207
208 // Arbitrary 8-bit data stream
209 wxMemoryOutputStream imageStream;
210
211 if( action->GetIcon() != BITMAPS::INVALID_BITMAP )
212 {
213 wxImage image = KiBitmap( action->GetIcon() ).ConvertToImage();
214 image.SaveFile( imageStream, wxBitmapType::wxBITMAP_TYPE_PNG );
215 image.Destroy();
216
217 if( imageStream.GetSize() )
218 {
219 const wxStreamBuffer* streamBuffer = imageStream.GetOutputStreamBuffer();
220 TDx::CImage tdxImage = TDx::CImage::FromData( "", 0, name.c_str() );
221 tdxImage.AssignImage(
222 std::string( std::bit_cast<const char*>( streamBuffer->GetBufferStart() ),
223 streamBuffer->GetBufferSize() ),
224 0 );
225
226 wxLogTrace( m_logTrace, wxT( "Adding image for : %s" ), name );
227 vImages.push_back( std::move( tdxImage ) );
228 }
229 }
230
231 if( iter != categoryStore.end() )
232 {
233 wxLogTrace( m_logTrace, wxT( "Inserting command: %s, description: %s, in category: %s" ),
234 name, description, iter->first );
235
236 iter->second->push_back( CCommand( name, label, description ) );
237 }
238 }
239
240 NAV_3D::AddCommandSet( commandSet );
241 NAV_3D::AddImages( vImages );
242}
243
244
245long NL_GERBVIEW_PLUGIN_IMPL::GetCameraMatrix( navlib::matrix_t& matrix ) const
246{
247 if( m_view == nullptr )
248 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
249
251
252 double x = m_view->IsMirroredX() ? -1 : 1;
253 double y = m_view->IsMirroredY() ? 1 : -1;
254
255 // x * y * z = 1 for a right-handed coordinate system.
256 double z = x * y;
257
258 // Note: the connexion has been configured as row vectors, the coordinate system is defined in
259 // NL_GERBVIEW_PLUGIN_IMPL::GetCoordinateSystem and the front view in NL_GERBVIEW_PLUGIN_IMPL::GetFrontView.
260 matrix = { { { x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, m_viewPosition.x, m_viewPosition.y, 0, 1 } } };
261 return 0;
262}
263
264
265long NL_GERBVIEW_PLUGIN_IMPL::GetPointerPosition( navlib::point_t& position ) const
266{
267 if( m_view == nullptr )
268 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
269
271
272 position.x = mouse_pointer.x;
273 position.y = mouse_pointer.y;
274 position.z = 0;
275
276 return 0;
277}
278
279
280long NL_GERBVIEW_PLUGIN_IMPL::GetViewExtents( navlib::box_t& extents ) const
281{
282 if( m_view == nullptr )
283 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
284
285 double scale = m_viewport2D->GetGAL()->GetWorldScale();
286 BOX2D box = m_view->GetViewport();
287
289
290 extents.min_x = -box.GetWidth() / 2.0;
291 extents.min_y = -box.GetHeight() / 2.0;
292 extents.min_z = m_viewport2D->GetGAL()->GetMinDepth() / scale;
293 extents.max_x = box.GetWidth() / 2.0;
294 extents.max_y = box.GetHeight() / 2.0;
295 extents.max_z = m_viewport2D->GetGAL()->GetMaxDepth() / scale;
296 return 0;
297}
298
299
300long NL_GERBVIEW_PLUGIN_IMPL::GetIsViewPerspective( navlib::bool_t& perspective ) const
301{
302 perspective = false;
303
304 return 0;
305}
306
307
308long NL_GERBVIEW_PLUGIN_IMPL::SetCameraMatrix( const navlib::matrix_t& matrix )
309{
310 if( m_view == nullptr )
311 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
312
313 long result = 0;
314 VECTOR2D viewPos( matrix.m4x4[3][0], matrix.m4x4[3][1] );
315
316 if( !equals( m_view->GetCenter(), m_viewPosition, static_cast<VECTOR2D::coord_type>( FLT_EPSILON ) ) )
317 {
319 result = navlib::make_result_code( navlib::navlib_errc::error );
320 }
321 else
322 {
323 m_view->SetCenter( viewPos );
324 }
325
326 m_viewPosition = viewPos;
327
328 return result;
329}
330
331
332long NL_GERBVIEW_PLUGIN_IMPL::SetViewExtents( const navlib::box_t& extents )
333{
334 if( m_view == nullptr )
335 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
336
337 long result = 0;
338
340 result = navlib::make_result_code( navlib::navlib_errc::error );
341
342 double width = m_viewportWidth;
343 m_viewportWidth = extents.max_x - extents.min_x;
344
345 double scale = width / m_viewportWidth * m_view->GetScale();
347
348 if( !equals( m_view->GetScale(), scale, static_cast<double>( FLT_EPSILON ) ) )
349 result = navlib::make_result_code( navlib::navlib_errc::error );
350
351 return result;
352}
353
354
356{
357 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
358}
359
360
361long NL_GERBVIEW_PLUGIN_IMPL::SetViewFrustum( const navlib::frustum_t& frustum )
362{
363 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
364}
365
366
367long NL_GERBVIEW_PLUGIN_IMPL::GetModelExtents( navlib::box_t& extents ) const
368{
369 if( m_view == nullptr )
370 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
371
372 BOX2I box = static_cast<GERBVIEW_FRAME*>( m_viewport2D->GetParent() )->GetDocumentExtents();
373 box.Normalize();
374
375 double half_depth = 0.1 / m_viewport2D->GetGAL()->GetWorldScale();
376
377 if( box.GetWidth() == 0 && box.GetHeight() == 0 )
378 half_depth = 0;
379
380 extents.min_x = static_cast<double>( box.GetOrigin().x );
381 extents.min_y = static_cast<double>( box.GetOrigin().y );
382 extents.min_z = -half_depth;
383 extents.max_x = static_cast<double>( box.GetEnd().x );
384 extents.max_y = static_cast<double>( box.GetEnd().y );
385 extents.max_z = half_depth;
386
387 return 0;
388}
389
390
391long NL_GERBVIEW_PLUGIN_IMPL::GetCoordinateSystem( navlib::matrix_t& matrix ) const
392{
393 // The coordinate system is defined as x to the right, y down and z into the screen.
394 matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
395 return 0;
396}
397
398
399long NL_GERBVIEW_PLUGIN_IMPL::GetFrontView( navlib::matrix_t& matrix ) const
400{
401 matrix = { { { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 } } };
402 return 0;
403}
404
405
407{
408 empty = true;
409 return 0;
410}
411
412
413long NL_GERBVIEW_PLUGIN_IMPL::GetIsViewRotatable( navlib::bool_t& isRotatable ) const
414{
415 isRotatable = false;
416 return 0;
417}
418
419
420long NL_GERBVIEW_PLUGIN_IMPL::SetActiveCommand( std::string commandId )
421{
422 if( commandId.empty() )
423 return 0;
424
425 if( !m_viewport2D )
426 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
427
428 wxWindow* parent = m_viewport2D->GetParent();
429
430 // Only allow command execution if the window is enabled. i.e. there is not a modal dialog
431 // currently active.
432 if( !parent || !parent->IsEnabled() )
433 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
434
435 TOOLS_HOLDER* tools_holder = dynamic_cast<TOOLS_HOLDER*>( parent );
436 TOOL_MANAGER* tool_manager = tools_holder ? tools_holder->GetToolManager() : nullptr;
437
438 // Only allow for command execution if the tool manager is accessible.
439 if( !tool_manager )
440 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
441
442 for( std::list<TOOL_ACTION*> actions = ACTION_MANAGER::GetActionList(); const auto action : actions )
443 {
444 if( !action )
445 continue;
446
447 if( commandId == action->GetName() )
448 {
449 // Get the selection to use to test if the action is enabled
450 const SELECTION& sel = tool_manager->GetToolHolder()->GetCurrentSelection();
451
452 const ACTION_CONDITIONS* aCond = tool_manager->GetActionManager()->GetCondition( *action );
453
454 if( !aCond )
455 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
456
457 aCond->enableCondition( sel );
458 tool_manager->RunAction( *action );
459 break;
460 }
461 }
462
463 return 0;
464}
465
466
468{
469 return 0;
470}
471
472
474{
475 m_isMoving = value;
476
477 return 0;
478}
479
480
482{
483 if( value == 0L )
485
486 return 0;
487}
488
489
490long NL_GERBVIEW_PLUGIN_IMPL::GetViewFOV( double& fov ) const
491{
492 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
493}
494
495
496long NL_GERBVIEW_PLUGIN_IMPL::GetViewFrustum( navlib::frustum_t& frustum ) const
497{
498 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
499}
500
501
502long NL_GERBVIEW_PLUGIN_IMPL::GetSelectionExtents( navlib::box_t& extents ) const
503{
504 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
505}
506
507
508long NL_GERBVIEW_PLUGIN_IMPL::GetSelectionTransform( navlib::matrix_t& transform ) const
509{
510 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
511}
512
513
514long NL_GERBVIEW_PLUGIN_IMPL::SetSelectionTransform( const navlib::matrix_t& matrix )
515{
516 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
517}
518
519
520long NL_GERBVIEW_PLUGIN_IMPL::GetPivotPosition( navlib::point_t& position ) const
521{
522 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
523}
524
525
526long NL_GERBVIEW_PLUGIN_IMPL::IsUserPivot( navlib::bool_t& userPivot ) const
527{
528 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
529}
530
531
532long NL_GERBVIEW_PLUGIN_IMPL::SetPivotPosition( const navlib::point_t& position )
533{
534 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
535}
536
537
538long NL_GERBVIEW_PLUGIN_IMPL::GetPivotVisible( navlib::bool_t& visible ) const
539{
540 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
541}
542
543
545{
546 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
547}
548
549
550long NL_GERBVIEW_PLUGIN_IMPL::GetHitLookAt( navlib::point_t& position ) const
551{
552 return navlib::make_result_code( navlib::navlib_errc::no_data_available );
553}
554
555
557{
558 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
559}
560
561
562long NL_GERBVIEW_PLUGIN_IMPL::SetHitDirection( const navlib::vector_t& direction )
563{
564 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
565}
566
567
568long NL_GERBVIEW_PLUGIN_IMPL::SetHitLookFrom( const navlib::point_t& eye )
569{
570 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
571}
572
573
575{
576 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
577}
578
579
580long NL_GERBVIEW_PLUGIN_IMPL::SetCameraTarget( const navlib::point_t& position )
581{
582 return navlib::make_result_code( navlib::navlib_errc::invalid_operation );
583}
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.
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.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
double GetScale() const
Definition: view.h:276
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:530
const VECTOR2D & GetCenter() const
Return the center point of this VIEW (in world space coordinates).
Definition: view.h:346
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:570
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:250
bool IsMirroredY() const
Return true if view is flipped across the Y axis.
Definition: view.h:258
const BOX2D & GetBoundary() const
Definition: view.h:305
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:596
long GetCoordinateSystem(navlib::matrix_t &aMatrix) const override
long GetHitLookAt(navlib::point_t &aPosition) const override
long SetSettingsChanged(long aChangeNumber) override
long GetIsViewPerspective(navlib::bool_t &aPerspective) const override
long SetCameraMatrix(const navlib::matrix_t &aMatrix) override
long GetPivotPosition(navlib::point_t &aPosition) const override
long GetViewFOV(double &aFov) const override
long SetPivotVisible(bool aVisible) override
long SetSelectionTransform(const navlib::matrix_t &aMatrix) override
long GetViewFrustum(navlib::frustum_t &aFrustum) const override
long SetTransaction(long aValue) override
long GetIsViewRotatable(navlib::bool_t &isRotatable) const override
long SetHitLookFrom(const navlib::point_t &aPosition) override
long GetIsSelectionEmpty(navlib::bool_t &aEmpty) const override
long SetMotionFlag(bool aValue) override
long GetCameraMatrix(navlib::matrix_t &aMatrix) const override
long SetViewExtents(const navlib::box_t &aExtents) override
long SetCameraTarget(const navlib::point_t &aPosition) override
long GetFrontView(navlib::matrix_t &aMatrix) const override
long SetHitSelectionOnly(bool aSelectionOnly) override
long GetSelectionExtents(navlib::box_t &aExtents) const override
long SetHitDirection(const navlib::vector_t &aDirection) override
long SetViewFOV(double aFov) override
NL_GERBVIEW_PLUGIN_IMPL()
Initializes a new instance of the NL_GERBVIEW_PLUGIN_IMPL.
long GetPointerPosition(navlib::point_t &aPosition) const override
long SetPivotPosition(const navlib::point_t &aPosition) override
void exportCommandsAndImages()
Export the invocable actions and images to the 3Dconnexion UI.
void SetCanvas(EDA_DRAW_PANEL_GAL *aViewport)
Sets the viewport controlled by the SpaceMouse.
void SetFocus(bool aFocus)
Set the connection to the 3Dconnexion driver to the focus state so that 3DMouse data is routed here.
long SetViewFrustum(const navlib::frustum_t &aFrustum) override
long SetActiveCommand(std::string aCommandId) override
long SetHitAperture(double aAperture) override
long GetViewExtents(navlib::box_t &aExtents) const override
long IsUserPivot(navlib::bool_t &aUserPivot) const override
long GetPivotVisible(navlib::bool_t &aVisible) const override
long GetModelExtents(navlib::box_t &aExtents) const override
long GetSelectionTransform(navlib::matrix_t &aTransform) const override
EDA_DRAW_PANEL_GAL * m_viewport2D
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
virtual SELECTION & GetCurrentSelection()
Get the current selection from the canvas area.
Definition: tools_holder.h:98
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.
std::map< std::string, TDx::CCommandTreeNode * > CATEGORY_STORE
static void try_add_category(const std::string &aCategoryPath, CATEGORY_STORE &aCategoryStore)
add_category wrapper.
static void add_category(const std::string &aCategoryPath, CATEGORY_STORE &aCategoryStore)
Add a category to the store.
Declaration of the NL_GERBVIEW_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 ...
SELECTION_CONDITION enableCondition
Returns true if the UI control should be enabled.
WX_VIEW_CONTROLS class definition.