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-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
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>
24 using namespace std::placeholders;
25 
26 #include <eda_item.h>
27 #include <id.h>
28 #include <view/view.h>
29 #include <view/view_controls.h>
30 #include <pcb_painter.h>
31 #include <pcbnew_settings.h>
32 #include <bitmaps.h>
33 
34 #include <tools/grid_helper.h>
35 #include <tools/pcb_actions.h>
36 #include <tool/tool_manager.h>
37 
38 #include "pns_arc.h"
39 #include "pns_kicad_iface.h"
40 #include "pns_tool_base.h"
41 #include "pns_segment.h"
42 #include "pns_solid.h"
43 #include "pns_via.h"
44 #include "pns_router.h"
45 #include "pns_meander_placer.h" // fixme: move settings to separate header
46 #include "pns_topology.h"
47 
48 
49 using namespace KIGFX;
50 
51 namespace PNS {
52 
53 
54 TOOL_BASE::TOOL_BASE( const std::string& aToolName ) :
55  PCB_TOOL_BASE( aToolName )
56 {
57  m_gridHelper = nullptr;
58  m_iface = nullptr;
59  m_router = nullptr;
60  m_cancelled = false;
61 
62  m_startItem = nullptr;
63  m_startLayer = 0;
64  m_startHighlight = false;
65 
66  m_endItem = nullptr;
67  m_gridHelper = nullptr;
68 
69  m_cancelled = false;
70 }
71 
72 
74 {
75  delete m_gridHelper;
76  delete m_iface;
77  delete m_router;
78 }
79 
80 
82 {
83  delete m_gridHelper;
84  delete m_iface;
85  delete m_router;
86 
88  m_iface->SetBoard( board() );
89  m_iface->SetView( getView() );
90  m_iface->SetHostTool( this );
91  m_iface->SetDisplayOptions( &( frame()->GetDisplayOptions() ) );
92 
93  m_router = new ROUTER;
97 
99 
100  PCBNEW_SETTINGS* settings = frame()->GetPcbNewSettings();
101 
102  if( !settings->m_PnsSettings )
103  settings->m_PnsSettings = std::make_unique<ROUTING_SETTINGS>( settings, "tools.pns" );
104 
105  m_router->LoadSettings( settings->m_PnsSettings.get() );
106 
107  m_gridHelper = new GRID_HELPER( m_toolMgr, frame()->GetMagneticItemsSettings() );
108 }
109 
110 
111 ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer, bool aIgnorePads,
112  const std::vector<ITEM*> aAvoidItems )
113 {
114  int tl = getView()->GetTopLayer();
115 
116  if( aLayer > 0 )
117  tl = aLayer;
118 
119  static const int candidateCount = 5;
120  ITEM* prioritized[candidateCount];
121  SEG::ecoord dist[candidateCount];
122 
123  for( int i = 0; i < candidateCount; i++ )
124  {
125  prioritized[i] = nullptr;
126  dist[i] = VECTOR2I::ECOORD_MAX;
127  }
128 
129  ITEM_SET candidates = m_router->QueryHoverItems( aWhere );
130 
131  for( ITEM* item : candidates.Items() )
132  {
133  if( !item->IsRoutable() )
134  continue;
135 
136  if( !IsCopperLayer( item->Layers().Start() ) )
137  continue;
138 
139  if( !m_iface->IsAnyLayerVisible( item->Layers() ) )
140  continue;
141 
142  if( alg::contains( aAvoidItems, item ) )
143  continue;
144 
145  // fixme: this causes flicker with live loop removal...
146  //if( item->Parent() && !item->Parent()->ViewIsVisible() )
147  // continue;
148 
149  if( aNet <= 0 || item->Net() == aNet )
150  {
151  if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) )
152  {
153  if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
154  continue;
155 
156  SEG::ecoord itemDist = ( item->Shape()->Centre() - aWhere ).SquaredEuclideanNorm();
157 
158  if( !prioritized[2] || itemDist < dist[2] )
159  {
160  prioritized[2] = item;
161  dist[2] = itemDist;
162  }
163  if( item->Layers().Overlaps( tl ) && itemDist < dist[0] )
164  {
165  prioritized[0] = item;
166  dist[0] = itemDist;
167  }
168  }
169  else
170  {
171  if( !prioritized[3] )
172  prioritized[3] = item;
173  if( item->Layers().Overlaps( tl ) )
174  prioritized[1] = item;
175  }
176  }
177  // Allow unconnected items as last resort in RM_MarkObstacles mode
178  else if ( item->Net() == 0 && m_router->Settings().Mode() == RM_MarkObstacles )
179  {
180  if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
181  continue;
182 
183  if( item->Layers().Overlaps( tl ) )
184  prioritized[4] = item;
185  }
186  }
187 
188  ITEM* rv = NULL;
189 
190  bool highContrast = ( displayOptions().m_ContrastModeDisplay !=
192 
193  for( int i = 0; i < candidateCount; i++ )
194  {
195  ITEM* item = prioritized[i];
196 
197  if( highContrast && item && !item->Layers().Overlaps( tl ) )
198  item = nullptr;
199 
200  if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
201  {
202  rv = item;
203  break;
204  }
205  }
206 
207  if( rv )
208  {
209  wxLogTrace( "PNS", "%s, layer : %d, tl: %d", rv->KindStr().c_str(), rv->Layers().Start(), tl );
210  }
211 
212  return rv;
213 }
214 
215 
216 void TOOL_BASE::highlightNet( bool aEnabled, int aNetcode )
217 {
219 
220  if( aNetcode >= 0 && aEnabled )
221  {
222  // If the user has previously set the current net to be highlighted,
223  // we assume they want to keep it highlighted after routing
225  ( rs->IsHighlightEnabled() && rs->GetHighlightNetCodes().count( aNetcode ) );
226 
227  rs->SetHighlight( true, aNetcode );
228  }
229  else
230  {
231  if( !m_startHighlight )
232  rs->SetHighlight( false );
233 
234  m_startHighlight = false;
235  }
236 
238 }
239 
241 {
242  // Sync PNS engine settings with the general PCB editor options.
243  auto& pnss = m_router->Settings();
244 
245  pnss.SetSnapToPads(
246  frame()->GetMagneticItemsSettings()->pads == MAGNETIC_OPTIONS::CAPTURE_CURSOR_IN_TRACK_TOOL ||
247  frame()->GetMagneticItemsSettings()->pads == MAGNETIC_OPTIONS::CAPTURE_ALWAYS );
248 
249  pnss.SetSnapToTracks(
250  frame()->GetMagneticItemsSettings()->tracks == MAGNETIC_OPTIONS::CAPTURE_CURSOR_IN_TRACK_TOOL
251  || frame()->GetMagneticItemsSettings()->tracks == MAGNETIC_OPTIONS::CAPTURE_ALWAYS );
252 
253  if( aItem )
254  {
255  if( aItem->OfKind( ITEM::VIA_T | ITEM::SEGMENT_T | ITEM::ARC_T ) )
256  return pnss.GetSnapToTracks();
257  else if( aItem->OfKind( ITEM::SOLID_T ) )
258  return pnss.GetSnapToPads();
259  }
260 
261  return false;
262 }
263 
264 void TOOL_BASE::updateStartItem( const TOOL_EVENT& aEvent, bool aIgnorePads )
265 {
266  int tl = getView()->GetTopLayer();
267  VECTOR2I cp = controls()->GetCursorPosition( !aEvent.Modifier( MD_SHIFT ) );
268  VECTOR2I p;
269 
270  controls()->ForceCursorPosition( false );
272  m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
273 
274  bool snapEnabled = true;
275 
276  if( aEvent.IsMotion() || aEvent.IsClick() )
277  {
278  snapEnabled = !aEvent.Modifier( MD_SHIFT );
279  p = aEvent.Position();
280  }
281  else
282  {
283  p = cp;
284  }
285 
286  m_startItem = pickSingleItem( p, -1, -1, aIgnorePads );
287 
288  if( !snapEnabled && m_startItem && !m_startItem->Layers().Overlaps( tl ) )
289  m_startItem = nullptr;
290 
291  m_startSnapPoint = snapToItem( snapEnabled, m_startItem, p );
292 
293  if( checkSnap( m_startItem ) )
294  {
296  }
297 }
298 
299 
301 {
302  int layer;
303  bool snapEnabled = !aEvent.Modifier( MD_SHIFT );
305  m_gridHelper->SetSnap( snapEnabled );
306 
307  controls()->ForceCursorPosition( false );
308  VECTOR2I mousePos = controls()->GetMousePosition();
309 
310  if( m_router->Settings().Mode() != RM_MarkObstacles &&
311  ( m_router->GetCurrentNets().empty() || m_router->GetCurrentNets().front() < 0 ) )
312  {
313  m_endSnapPoint = snapToItem( snapEnabled, nullptr, mousePos );
315  m_endItem = nullptr;
316 
317  return;
318  }
319 
320  if( m_router->IsPlacingVia() )
321  layer = -1;
322  else
323  layer = m_router->GetCurrentLayer();
324 
325  ITEM* endItem = nullptr;
326 
327  std::vector<int> nets = m_router->GetCurrentNets();
328 
329  for( int net : nets )
330  {
331  endItem = pickSingleItem( mousePos, net, layer, false, { m_startItem } );
332 
333  if( endItem )
334  break;
335  }
336 
337  if( checkSnap( endItem ) )
338  {
339  m_endItem = endItem;
340  m_endSnapPoint = snapToItem( snapEnabled, endItem, mousePos );
341  } else {
342  m_endItem = nullptr;
343  m_endSnapPoint = m_gridHelper->Align( mousePos );
344  }
345 
347 
348  if( m_endItem )
349  {
350  wxLogTrace( "PNS", "%s, layer : %d", m_endItem->KindStr().c_str(), m_endItem->Layers().Start() );
351  }
352 }
353 
354 
355 void TOOL_BASE::deleteTraces( ITEM* aStartItem, bool aWholeTrack )
356 {
357  NODE *node = m_router->GetWorld()->Branch();
358 
359  if( !aStartItem )
360  return;
361 
362  if( !aWholeTrack )
363  {
364  node->Remove( aStartItem );
365  }
366  else
367  {
368  TOPOLOGY topo( node );
369  ITEM_SET path = topo.AssembleTrivialPath( aStartItem );
370 
371  for( const auto& ent : path.Items() )
372  node->Remove( ent.item );
373  }
374 
375  m_router->CommitRouting( node );
376 }
377 
378 
380 {
381  return m_router;
382 }
383 
384 
385 const VECTOR2I TOOL_BASE::snapToItem( bool aEnabled, ITEM* aItem, VECTOR2I aP)
386 {
387  VECTOR2I anchor;
388 
389  if( !aItem || !aEnabled || !m_iface->IsItemVisible( aItem ) )
390  {
391  return m_gridHelper->Align( aP );
392  }
393 
394  switch( aItem->Kind() )
395  {
396  case ITEM::SOLID_T:
397  anchor = static_cast<SOLID*>( aItem )->Pos();
398  break;
399 
400  case ITEM::VIA_T:
401  anchor = static_cast<VIA*>( aItem )->Pos();
402  break;
403 
404  case ITEM::SEGMENT_T:
405  case ITEM::ARC_T:
406  {
407  LINKED_ITEM* li = static_cast<LINKED_ITEM*>( aItem );
408  int w = li->Width();
409  auto A = li->Anchor( 0 );
410  auto B = li->Anchor( 1 );
411 
412  if( ( aP - A ).EuclideanNorm() < w / 2 )
413  anchor = A;
414  else if( ( aP - B ).EuclideanNorm() < w / 2 )
415  anchor = B;
416  else // TODO(snh): Clean this up
417  if( aItem->Kind() == ITEM::SEGMENT_T )
418  anchor = m_gridHelper->AlignToSegment( aP, static_cast<SEGMENT*>( li )->Seg() );
419  else if( aItem->Kind() == ITEM::ARC_T )
420  anchor = m_gridHelper->AlignToArc( aP,
421  *static_cast<const SHAPE_ARC*>( static_cast<ARC*>( li )->Shape() ) );
422 
423  break;
424  }
425 
426  default:
427  break;
428  }
429 
430  return anchor;
431 }
432 
433 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:134
void SetHostTool(PCB_TOOL_BASE *aTool)
ITEM.
Definition: pns_item.h:54
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:290
void SetView(KIGFX::VIEW *aView)
NODE.
Definition: pns_node.h:170
GRID_HELPER * m_gridHelper
Definition: pns_tool_base.h:75
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Function GetMousePosition() Returns the current mouse pointer position.
BOARD * board() const
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:175
RENDER_SETTINGS Contains all the knowledge about how graphical objects are drawn on any output surfac...
VIEW_CONTROLS class definition.
VECTOR2I m_startSnapPoint
Definition: pns_tool_base.h:69
const ITEM_SET QueryHoverItems(const VECTOR2I &aP)
Definition: pns_router.cpp:120
bool IsClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:178
void CommitRouting()
Definition: pns_router.cpp:437
ENTRIES & Items()
Definition: pns_itemset.h:140
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
VECTOR2I::extended_type ecoord
Definition: seg.h:42
bool m_startHighlight
Keeps track of whether the net was highlighted before routing.
Definition: pns_tool_base.h:70
SIZES_SETTINGS m_savedSizes
Stores sizes settings between router invocations.
Definition: pns_tool_base.h:66
void SyncWorld()
Definition: pns_router.cpp:93
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
bool IsPlacingVia() const
Definition: pns_router.cpp:529
bool IsMotion() const
Definition: tool_event.h:306
bool Overlaps(const LAYER_RANGE &aOther) const
Definition: pns_layerset.h:68
const std::vector< int > GetCurrentNets() const
Definition: pns_router.cpp:506
GAL * GetGAL() const
Function GetGAL() Returns the GAL this view is using to draw graphical primitives.
Definition: view.h:182
PCBNEW_SETTINGS * GetPcbNewSettings()
bool IsHighlightEnabled() const
Function IsHighlightEnabled Returns current highlight setting.
NODE * Branch()
Function Branch()
Definition: pns_node.cpp:106
const VECTOR2I snapToItem(bool aEnabled, ITEM *aItem, VECTOR2I aP)
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:201
void ClearWorld()
Definition: pns_router.cpp:102
void Remove(ARC *aArc)
Function Remove()
Definition: pns_node.cpp:800
int Start() const
Definition: pns_layerset.h:83
virtual int Width() const
PCB_BASE_EDIT_FRAME * frame() const
virtual void updateStartItem(const TOOL_EVENT &aEvent, bool aIgnorePads=false)
std::string KindStr() const
Function KindStr()
Definition: pns_item.cpp:108
virtual void updateEndItem(const TOOL_EVENT &aEvent)
bool GetGridSnapping() const
static constexpr extended_type ECOORD_MAX
Definition: vector2d.h:80
virtual void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
bool checkSnap(ITEM *aItem)
const ITEM_SET AssembleTrivialPath(ITEM *aStart)
#define NULL
virtual ~TOOL_BASE()
bool IsItemVisible(const PNS::ITEM *aItem) const override
virtual int GetTopLayer() const
Definition: view.cpp:829
TOOL_EVENT.
Definition: tool_event.h:171
ITEM * m_startItem
Definition: pns_tool_base.h:67
ROUTER * m_router
Definition: pns_tool_base.h:77
PNS_MODE Mode() const
Returns the routing mode.
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Function ForceCursorPosition() Places the cursor immediately at a given point.
void SetSnapToPads(bool aSnap)
std::unique_ptr< PNS::ROUTING_SETTINGS > m_PnsSettings
VECTOR2I AlignToArc(const VECTOR2I &aPoint, const SHAPE_ARC &aSeg)
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:81
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:36
void SetInterface(ROUTER_IFACE *aIface)
Definition: pns_router.cpp:559
const PCB_DISPLAY_OPTIONS & displayOptions() const
void SetBoard(BOARD *aBoard)
void SetSnap(bool aSnap)
Definition: grid_helper.h:82
virtual void highlightNet(bool aEnabled, int aNetcode=-1)
int Modifier(int aMask=MD_MODIFIER_MASK) const
Returns information about key modifiers state (Ctrl, Alt, etc.)
Definition: tool_event.h:342
virtual VECTOR2I Anchor(int n) const
Definition: pns_item.h:232
VECTOR2I Align(const VECTOR2I &aPoint) const
virtual RENDER_SETTINGS * GetSettings()=0
Function GetAdapter Returns pointer to current settings that are going to be used when drawing items.
void UpdateSizes(const SIZES_SETTINGS &aSizes)
Applies stored settings.
Definition: pns_router.cpp:342
KIGFX::VIEW_CONTROLS * controls() const
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aMulti=false)
Function SetHighlight Turns on/off highlighting - it may be done for the active layer or the specifie...
VECTOR2I m_endSnapPoint
Definition: pns_tool_base.h:73
void deleteTraces(ITEM *aStartItem, bool aWholeTrack)
bool OfKind(int aKindMask) const
Function OfKind()
Definition: pns_item.h:134
virtual ITEM * pickSingleItem(const VECTOR2I &aWhere, int aNet=-1, int aLayer=-1, bool aIgnorePads=false, const std::vector< ITEM * > aAvoidItems={})
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:79
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
PnsKind Kind() const
Function Kind()
Definition: pns_item.h:124
void LoadSettings(ROUTING_SETTINGS *aSettings)
Changes routing settings to ones passed in the parameter.
Definition: pns_router.h:219
void SetUseGrid(bool aGrid=true)
Definition: grid_helper.h:92
const std::set< int > & GetHighlightNetCodes() const
Function GetHighlightNetCode Returns netcode of currently highlighted net.
ROUTER * Router() const
void UpdateAllLayersColor()
Function UpdateAllLayersColor() Applies the new coloring scheme to all layers.
Definition: view.cpp:776
Push and Shove diff pair dimensions (gap) settings dialog.
NODE * GetWorld() const
Definition: pns_router.h:157
void SetDisplayOptions(const PCB_DISPLAY_OPTIONS *aDispOptions)
PNS_KICAD_IFACE * m_iface
Definition: pns_tool_base.h:76
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:205
const VECTOR2D Position() const
Returns mouse cursor position in world coordinates.
Definition: tool_event.h:274
const LAYER_RANGE & Layers() const
Definition: pns_item.h:152
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
TOOL_BASE(TOOL_TYPE aType, TOOL_ID aId, const std::string &aName=std::string(""))
Definition: tool_base.h:70
bool IsAnyLayerVisible(const LAYER_RANGE &aLayer) const override
int GetCurrentLayer() const
Definition: pns_router.cpp:515