KiCad PCB EDA Suite
pns_tool_base.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013 CERN
5 * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
6 * Author: Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23#include <functional>
24using namespace std::placeholders;
25
26#include <pcb_painter.h>
27#include <pcbnew_settings.h>
28
30#include <wx/log.h>
31
32#include "pns_kicad_iface.h"
33#include "pns_tool_base.h"
34#include "pns_arc.h"
35#include "pns_solid.h"
36#include "pns_dragger.h"
37
38
39using namespace KIGFX;
40
41namespace PNS {
42
43
44TOOL_BASE::TOOL_BASE( const std::string& aToolName ) :
45 PCB_TOOL_BASE( aToolName )
46{
47 m_gridHelper = nullptr;
48 m_iface = nullptr;
49 m_router = nullptr;
50 m_cancelled = false;
51
52 m_startItem = nullptr;
53
54 m_endItem = nullptr;
55 m_gridHelper = nullptr;
56
57 m_cancelled = false;
58}
59
60
62{
63 delete m_gridHelper;
64 delete m_iface;
65 delete m_router;
66}
67
68
70{
71 delete m_gridHelper;
72 delete m_iface;
73 delete m_router;
74
78 m_iface->SetHostTool( this );
79
80 m_router = new ROUTER;
84
86
88
89 if( !settings->m_PnsSettings )
90 settings->m_PnsSettings = std::make_unique<ROUTING_SETTINGS>( settings, "tools.pns" );
91
92 m_router->LoadSettings( settings->m_PnsSettings.get() );
93
94 m_gridHelper = new PCB_GRID_HELPER( m_toolMgr, frame()->GetMagneticItemsSettings() );
95}
96
97
98ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer, bool aIgnorePads,
99 const std::vector<ITEM*> aAvoidItems )
100{
101 int tl = aLayer > 0 ? aLayer : getView()->GetTopLayer();
102
103 static const int candidateCount = 5;
104 ITEM* prioritized[candidateCount];
105 SEG::ecoord dist[candidateCount];
106
107 for( int i = 0; i < candidateCount; i++ )
108 {
109 prioritized[i] = nullptr;
110 dist[i] = VECTOR2I::ECOORD_MAX;
111 }
112
113 ITEM_SET candidates = m_router->QueryHoverItems( aWhere );
114
115 if( candidates.Empty() )
116 candidates = m_router->QueryHoverItems( aWhere, true );
117
118 for( ITEM* item : candidates.Items() )
119 {
120 if( !item->IsRoutable() )
121 continue;
122
123 if( !IsCopperLayer( item->Layers().Start() ) )
124 continue;
125
126 if( !m_iface->IsAnyLayerVisible( item->Layers() ) )
127 continue;
128
129 if( alg::contains( aAvoidItems, item ) )
130 continue;
131
132 // fixme: this causes flicker with live loop removal...
133 //if( item->Parent() && !item->Parent()->ViewIsVisible() )
134 // continue;
135
136 if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
137 {
138 continue;
139 }
140 else if( aNet <= 0 || item->Net() == aNet )
141 {
142 if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) )
143 {
144 SEG::ecoord d = ( item->Shape()->Centre() - aWhere ).SquaredEuclideanNorm();
145
146 if( d < dist[2] )
147 {
148 prioritized[2] = item;
149 dist[2] = d;
150 }
151
152 if( item->Layers().Overlaps( tl ) && d < dist[0] )
153 {
154 prioritized[0] = item;
155 dist[0] = d;
156 }
157 }
158 else // ITEM::SEGMENT_T | ITEM::ARC_T
159 {
160 LINKED_ITEM* li = static_cast<LINKED_ITEM*>( item );
161 SEG::ecoord d = std::min( ( li->Anchor( 0 ) - aWhere ).SquaredEuclideanNorm(),
162 ( li->Anchor( 1 ) - aWhere ).SquaredEuclideanNorm() );
163
164 if( d < dist[3] )
165 {
166 prioritized[3] = item;
167 dist[3] = d;
168 }
169
170 if( item->Layers().Overlaps( tl ) && d < dist[1] )
171 {
172 prioritized[1] = item;
173 dist[1] = d;
174 }
175 }
176 }
177 else if( item->OfKind( ITEM::SOLID_T ) && item->IsFreePad() )
178 {
179 // Allow free pads only when already inside pad
180 if( item->Shape()->Collide( aWhere ) )
181 {
182 prioritized[0] = item;
183 dist[0] = 0;
184 }
185 }
186 else if ( item->Net() == 0 && m_router->Settings().Mode() == RM_MarkObstacles )
187 {
188 // Allow unconnected items as last resort in RM_MarkObstacles mode
189 if( item->Layers().Overlaps( tl ) )
190 prioritized[4] = item;
191 }
192 }
193
194 ITEM* rv = nullptr;
195
197
198 for( int i = 0; i < candidateCount; i++ )
199 {
200 ITEM* item = prioritized[i];
201
202 if( highContrast && item && !item->Layers().Overlaps( tl ) )
203 item = nullptr;
204
205 if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
206 {
207 rv = item;
208 break;
209 }
210 }
211
212 if( rv )
213 {
214 wxLogTrace( wxT( "PNS" ), wxT( "%s, layer : %d, tl: %d" ),
215 rv->KindStr().c_str(),
216 rv->Layers().Start(),
217 tl );
218 }
219
220 return rv;
221}
222
223
224void TOOL_BASE::highlightNets( bool aEnabled, std::set<int> aNetcodes )
225{
227
228 if( aNetcodes.size() > 0 && aEnabled )
229 {
230 // If the user has previously set some of the routed nets to be highlighted,
231 // we assume they want to keep them highlighted after routing
232
233 const std::set<int>& currentNetCodes = rs->GetHighlightNetCodes();
234 bool keep = false;
235
236 for( const int& netcode : aNetcodes )
237 {
238 if( currentNetCodes.find( netcode ) != currentNetCodes.end() )
239 {
240 keep = true;
241 break;
242 }
243 }
244
245 if( rs->IsHighlightEnabled() && keep )
246 m_startHighlightNetcodes = currentNetCodes;
247 else
249
250 rs->SetHighlight( aNetcodes, true );
251 }
252 else
253 {
255 }
256
257 // Do not remove this call. This is required to update the layers when we highlight a net.
258 // In this case, highlighting a net dims all other elements, so the colors need to update
260}
261
262
264{
265 // Sync PNS engine settings with the general PCB editor options.
266 auto& pnss = m_router->Settings();
267
268 // If we're dragging a track segment, don't try to snap to items that are part of the original line.
270 && m_router->GetDragger() )
271 {
272 DRAGGER* dragger = dynamic_cast<DRAGGER*>( m_router->GetDragger() );
273 LINKED_ITEM* liItem = dynamic_cast<LINKED_ITEM*>( aItem );
274
275 if( dragger && liItem && dragger->GetOriginalLine().ContainsLink( liItem ) )
276 {
277 return false;
278 }
279 }
280
281 pnss.SetSnapToPads(
284
285 pnss.SetSnapToTracks(
288
289 if( aItem )
290 {
292 return pnss.GetSnapToTracks();
293 else if( aItem->OfKind( ITEM::SOLID_T ) )
294 return pnss.GetSnapToPads();
295 }
296
297 return false;
298}
299
300
301void TOOL_BASE::updateStartItem( const TOOL_EVENT& aEvent, bool aIgnorePads )
302{
303 int tl = getView()->GetTopLayer();
304 VECTOR2I cp = aEvent.IsPrime() ? aEvent.Position()
305 : controls()->GetCursorPosition( !aEvent.Modifier( MD_SHIFT ) );
306 VECTOR2I p;
307 GAL* gal = m_toolMgr->GetView()->GetGAL();
308
309 controls()->ForceCursorPosition( false );
311 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
312
313 if( aEvent.IsMotion() || aEvent.IsClick() )
314 p = aEvent.Position();
315 else
316 p = cp;
317
318 m_startItem = pickSingleItem( aEvent.IsClick() ? cp : p, -1, -1, aIgnorePads );
319
321 m_startItem = nullptr;
322
325}
326
327
329{
330 int layer;
331 GAL* gal = m_toolMgr->GetView()->GetGAL();
332
334 m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
335
336 controls()->ForceCursorPosition( false );
337
338 VECTOR2I mousePos = controls()->GetMousePosition();
339
340 if( m_router->GetState() == ROUTER::ROUTE_TRACK && aEvent.IsDrag() )
341 {
342 // If the user is moving the mouse quickly while routing then clicks will come in as
343 // short drags. In this case we want to use the drag origin rather than the current
344 // mouse position.
345 mousePos = aEvent.DragOrigin();
346 }
347
349 ( m_router->GetCurrentNets().empty() || m_router->GetCurrentNets().front() < 0 ) )
350 {
351 m_endSnapPoint = snapToItem( nullptr, mousePos );
353 m_endItem = nullptr;
354
355 return;
356 }
357
358 if( m_router->IsPlacingVia() )
359 layer = -1;
360 else
361 layer = m_router->GetCurrentLayer();
362
363 ITEM* endItem = nullptr;
364
365 std::vector<int> nets = m_router->GetCurrentNets();
366
367 for( int net : nets )
368 {
369 endItem = pickSingleItem( mousePos, net, layer, false, { m_startItem } );
370
371 if( endItem )
372 break;
373 }
374
375 if( m_gridHelper->GetSnap() && checkSnap( endItem ) )
376 {
377 m_endItem = endItem;
378 m_endSnapPoint = snapToItem( endItem, mousePos );
379 }
380 else
381 {
382 m_endItem = nullptr;
383 m_endSnapPoint = m_gridHelper->Align( mousePos );
384 }
385
387
388 if( m_endItem )
389 {
390 wxLogTrace( wxT( "PNS" ), wxT( "%s, layer : %d" ),
391 m_endItem->KindStr().c_str(),
392 m_endItem->Layers().Start() );
393 }
394}
395
396
398{
399 return m_router;
400}
401
402
403const VECTOR2I TOOL_BASE::snapToItem( ITEM* aItem, const VECTOR2I& aP )
404{
405 if( !aItem || !m_iface->IsItemVisible( aItem ) )
406 {
407 return m_gridHelper->Align( aP );
408 }
409
410 switch( aItem->Kind() )
411 {
412 case ITEM::SOLID_T:
413 return static_cast<SOLID*>( aItem )->Pos();
414
415 case ITEM::VIA_T:
416 return static_cast<VIA*>( aItem )->Pos();
417
418 case ITEM::SEGMENT_T:
419 case ITEM::ARC_T:
420 {
421 LINKED_ITEM* li = static_cast<LINKED_ITEM*>( aItem );
422 VECTOR2I A = li->Anchor( 0 );
423 VECTOR2I B = li->Anchor( 1 );
424 SEG::ecoord w_sq = SEG::Square( li->Width() / 2 );
425 SEG::ecoord distA_sq = ( aP - A ).SquaredEuclideanNorm();
426 SEG::ecoord distB_sq = ( aP - B ).SquaredEuclideanNorm();
427
428 if( distA_sq < w_sq || distB_sq < w_sq )
429 {
430 return ( distA_sq < distB_sq ) ? A : B;
431 }
432 else if( aItem->Kind() == ITEM::SEGMENT_T )
433 {
434 // TODO(snh): Clean this up
435 SEGMENT* seg = static_cast<SEGMENT*>( li );
436 return m_gridHelper->AlignToSegment( aP, seg->Seg() );
437 }
438 else if( aItem->Kind() == ITEM::ARC_T )
439 {
440 ARC* arc = static_cast<ARC*>( li );
441 return m_gridHelper->AlignToArc( aP, *static_cast<const SHAPE_ARC*>( arc->Shape() ) );
442 }
443
444 break;
445 }
446
447 default:
448 break;
449 }
450
451 return m_gridHelper->Align( aP );
452}
453
454}
@ NORMAL
Inactive layers are shown normally (no high-contrast mode)
bool GetSnap() const
Definition: grid_helper.h:66
void SetSnap(bool aSnap)
Definition: grid_helper.h:65
bool GetUseGrid() const
Definition: grid_helper.h:69
virtual VECTOR2I Align(const VECTOR2I &aPoint) const
void SetUseGrid(bool aSnapToGrid)
Definition: grid_helper.h:68
Abstract interface for drawing on a 2D-surface.
bool GetGridSnapping() const
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
bool IsHighlightEnabled() const
Return current highlight setting.
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Turns on/off highlighting.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:761
virtual int GetTopLayer() const
Definition: view.cpp:816
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:195
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:213
int Start() const
Definition: pns_layerset.h:82
bool Overlaps(const LAYER_RANGE &aOther) const
Definition: pns_layerset.h:67
std::unique_ptr< PNS::ROUTING_SETTINGS > m_PnsSettings
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
PCBNEW_SETTINGS * GetPcbNewSettings() const
virtual MAGNETIC_SETTINGS * GetMagneticItemsSettings()
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
VECTOR2I AlignToArc(const VECTOR2I &aPoint, const SHAPE_ARC &aSeg)
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
PCB_BASE_EDIT_FRAME * frame() const
KIGFX::VIEW_CONTROLS * controls() const
BOARD * board() const
const SHAPE * Shape() const override
Return the geometrical shape of the item.
Definition: pns_arc.h:77
DRAGGER.
Definition: pns_dragger.h:48
const LINE & GetOriginalLine()
Definition: pns_dragger.h:103
bool Empty() const
Definition: pns_itemset.h:130
ENTRIES & Items()
Definition: pns_itemset.h:135
Base class for PNS router board items.
Definition: pns_item.h:56
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:132
@ SOLID_T
Definition: pns_item.h:63
@ SEGMENT_T
Definition: pns_item.h:66
const LAYER_RANGE & Layers() const
Definition: pns_item.h:156
bool OfKind(int aKindMask) const
Return true if the item's type matches the mask aKindMask.
Definition: pns_item.h:140
virtual VECTOR2I Anchor(int n) const
Definition: pns_item.h:219
std::string KindStr() const
Returns the kind of the item, as string.
Definition: pns_item.cpp:198
virtual int Width() const
void ClearWorld()
Definition: pns_router.cpp:102
void UpdateSizes(const SIZES_SETTINGS &aSizes)
Applies stored settings.
Definition: pns_router.cpp:726
void LoadSettings(ROUTING_SETTINGS *aSettings)
Changes routing settings to ones passed in the parameter.
Definition: pns_router.h:202
const std::vector< int > GetCurrentNets() const
Definition: pns_router.cpp:971
void SetInterface(ROUTER_IFACE *aIface)
void SyncWorld()
Definition: pns_router.cpp:92
bool IsPlacingVia() const
Definition: pns_router.cpp:999
const ITEM_SET QueryHoverItems(const VECTOR2I &aP, bool aUseClearance=false)
Definition: pns_router.cpp:120
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:188
DRAG_ALGO * GetDragger()
Definition: pns_router.h:136
RouterState GetState() const
Definition: pns_router.h:134
int GetCurrentLayer() const
Definition: pns_router.cpp:982
PNS_MODE Mode() const
Set the routing mode.
const SEG & Seg() const
Definition: pns_segment.h:84
bool checkSnap(ITEM *aItem)
virtual void updateStartItem(const TOOL_EVENT &aEvent, bool aIgnorePads=false)
virtual void highlightNets(bool aEnabled, std::set< int > aNetcodes={})
virtual ITEM * pickSingleItem(const VECTOR2I &aWhere, int aNet=-1, int aLayer=-1, bool aIgnorePads=false, const std::vector< ITEM * > aAvoidItems={})
ROUTER * Router() const
std::set< int > m_startHighlightNetcodes
Definition: pns_tool_base.h:72
const VECTOR2I snapToItem(ITEM *aSnapToItem, const VECTOR2I &aP)
virtual void Reset(RESET_REASON aReason) override
Bring the tool to a known, initial state.
virtual ~TOOL_BASE()
SIZES_SETTINGS m_savedSizes
Definition: pns_tool_base.h:69
PNS_KICAD_IFACE * m_iface
Definition: pns_tool_base.h:78
ITEM * m_startItem
Definition: pns_tool_base.h:70
virtual void updateEndItem(const TOOL_EVENT &aEvent)
TOOL_BASE(const std::string &aToolName)
ROUTER * m_router
Definition: pns_tool_base.h:79
VECTOR2I m_endSnapPoint
Definition: pns_tool_base.h:75
PCB_GRID_HELPER * m_gridHelper
Definition: pns_tool_base.h:77
VECTOR2I m_startSnapPoint
Definition: pns_tool_base.h:71
void SetBoard(BOARD *aBoard)
void SetView(KIGFX::VIEW *aView)
void SetHostTool(PCB_TOOL_BASE *aTool)
bool IsItemVisible(const PNS::ITEM *aItem) const override
bool IsAnyLayerVisible(const LAYER_RANGE &aLayer) const override
VECTOR2I::extended_type ecoord
Definition: seg.h:44
static SEG::ecoord Square(int a)
Definition: seg.h:123
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:215
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
RESET_REASON
Determine the reason of reset for a tool.
Definition: tool_base.h:78
Generic, UI-independent tool event.
Definition: tool_event.h:156
bool DisableGridSnapping() const
Definition: tool_event.h:344
bool IsPrime() const
Returns information about key modifiers state (Ctrl, Alt, etc.)
Definition: tool_event.h:333
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:266
bool IsClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:200
bool IsDrag(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:288
int Modifier(int aMask=MD_MODIFIER_MASK) const
Definition: tool_event.h:339
const VECTOR2D DragOrigin() const
Returns information about mouse buttons state.
Definition: tool_event.h:272
bool IsMotion() const
Definition: tool_event.h:303
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:285
static constexpr extended_type ECOORD_MAX
Definition: vector2d.h:79
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:825
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:266
Push and Shove diff pair dimensions (gap) settings dialog.
@ RM_MarkObstacles
Ignore collisions, mark obstacles.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:99
MAGNETIC_OPTIONS tracks
MAGNETIC_OPTIONS pads
@ MD_SHIFT
Definition: tool_event.h:138