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 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 #include <wx/numdlg.h>
23 
24 #include <functional>
25 using namespace std::placeholders;
26 
27 #include "class_draw_panel_gal.h"
28 #include "class_board.h"
29 
30 #include <pcb_edit_frame.h>
31 #include <id.h>
32 #include <macros.h>
33 #include <view/view_controls.h>
34 #include <pcb_painter.h>
35 #include <pcbnew_settings.h>
40 #include <base_units.h>
41 #include <bitmaps.h>
42 
43 #include <tool/action_menu.h>
44 #include <tools/pcb_actions.h>
45 #include <tools/grid_helper.h>
46 
47 #include "pns_arc.h"
48 #include "pns_kicad_iface.h"
49 #include "pns_tool_base.h"
50 #include "pns_segment.h"
51 #include "pns_solid.h"
52 #include "pns_via.h"
53 #include "pns_router.h"
54 #include "pns_meander_placer.h" // fixme: move settings to separate header
55 #include "pns_tune_status_popup.h"
56 #include "pns_topology.h"
57 
58 #include <view/view.h>
59 
60 using namespace KIGFX;
61 
62 namespace PNS {
63 
64 
65 TOOL_BASE::TOOL_BASE( const std::string& aToolName ) :
66  PCB_TOOL_BASE( aToolName )
67 {
68  m_gridHelper = nullptr;
69  m_iface = nullptr;
70  m_router = nullptr;
71  m_cancelled = false;
72 
73  m_startItem = nullptr;
74  m_startLayer = 0;
75  m_startHighlight = false;
76 
77  m_endItem = nullptr;
78  m_gridHelper = nullptr;
79 
80  m_cancelled = false;
81 }
82 
83 
85 {
86  delete m_gridHelper;
87  delete m_iface;
88  delete m_router;
89 }
90 
91 
93 {
94  delete m_gridHelper;
95  delete m_iface;
96  delete m_router;
97 
99  m_iface->SetBoard( board() );
100  m_iface->SetView( getView() );
101  m_iface->SetHostTool( this );
102  m_iface->SetDisplayOptions( &( frame()->GetDisplayOptions() ) );
103 
104  m_router = new ROUTER;
106  m_router->ClearWorld();
107  m_router->SyncWorld();
108 
110 
111  PCBNEW_SETTINGS* settings = frame()->GetSettings();
112 
113  if( !settings->m_PnsSettings )
114  settings->m_PnsSettings = std::make_unique<ROUTING_SETTINGS>( settings, "tools.pns" );
115 
116  m_router->LoadSettings( settings->m_PnsSettings.get() );
117 
118  m_gridHelper = new GRID_HELPER( frame() );
119 }
120 
121 
122 ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer, bool aIgnorePads,
123  const std::vector<ITEM*> aAvoidItems)
124 {
125  int tl = getView()->GetTopLayer();
126 
127  if( aLayer > 0 )
128  tl = aLayer;
129 
130  static const int candidateCount = 5;
131  ITEM* prioritized[candidateCount];
132  int dist[candidateCount];
133 
134  for( int i = 0; i < candidateCount; i++ )
135  {
136  prioritized[i] = 0;
137  dist[i] = std::numeric_limits<int>::max();
138  }
139 
140  ITEM_SET candidates = m_router->QueryHoverItems( aWhere );
141 
142  for( ITEM* item : candidates.Items() )
143  {
144  if( !item->IsRoutable() )
145  continue;
146 
147  if( !IsCopperLayer( item->Layers().Start() ) )
148  continue;
149 
150  if( !m_iface->IsAnyLayerVisible( item->Layers() ) )
151  continue;
152 
153  if( std::find( aAvoidItems.begin(), aAvoidItems.end(), item ) != aAvoidItems.end() )
154  continue;
155 
156  // fixme: this causes flicker with live loop removal...
157  //if( item->Parent() && !item->Parent()->ViewIsVisible() )
158  // continue;
159 
160  if( aNet <= 0 || item->Net() == aNet )
161  {
162  if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) )
163  {
164  if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
165  continue;
166 
167  int itemDist = ( item->Shape()->Centre() - aWhere ).SquaredEuclideanNorm();
168 
169  if( !prioritized[2] || itemDist < dist[2] )
170  {
171  prioritized[2] = item;
172  dist[2] = itemDist;
173  }
174  if( item->Layers().Overlaps( tl ) && itemDist < dist[0] )
175  {
176  prioritized[0] = item;
177  dist[0] = itemDist;
178  }
179  }
180  else
181  {
182  if( !prioritized[3] )
183  prioritized[3] = item;
184  if( item->Layers().Overlaps( tl ) )
185  prioritized[1] = item;
186  }
187  }
188  // Allow unconnected items as last resort in RM_MarkObstacles mode
189  else if ( item->Net() == 0 && m_router->Settings().Mode() == RM_MarkObstacles )
190  {
191  if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
192  continue;
193 
194  if( item->Layers().Overlaps( tl ) )
195  prioritized[4] = item;
196  }
197  }
198 
199  ITEM* rv = NULL;
200 
201  for( int i = 0; i < candidateCount; i++ )
202  {
203  ITEM* item = prioritized[i];
204 
206  if( item && !item->Layers().Overlaps( tl ) )
207  item = NULL;
208 
209  if( item && ( aLayer < 0 || item->Layers().Overlaps( aLayer ) ) )
210  {
211  rv = item;
212  break;
213  }
214  }
215 
216  if( rv )
217  {
218  wxLogTrace( "PNS", "%s, layer : %d, tl: %d", rv->KindStr().c_str(), rv->Layers().Start(), tl );
219  }
220 
221  return rv;
222 }
223 
224 
225 void TOOL_BASE::highlightNet( bool aEnabled, int aNetcode )
226 {
228 
229  if( aNetcode >= 0 && aEnabled )
230  {
231  // If the user has previously set the current net to be highlighted,
232  // we assume they want to keep it highlighted after routing
233  m_startHighlight = ( rs->IsHighlightEnabled() && rs->GetHighlightNetCode() == aNetcode );
234 
235  rs->SetHighlight( true, aNetcode );
236  }
237  else
238  {
239  if( !m_startHighlight )
240  rs->SetHighlight( false );
241 
242  m_startHighlight = false;
243  }
244 
246 }
247 
249 {
250  // Sync PNS engine settings with the general PCB editor options.
251  auto& pnss = m_router->Settings();
252 
253  pnss.SetSnapToPads(
254  frame()->Settings().m_MagneticPads == MAGNETIC_OPTIONS::CAPTURE_CURSOR_IN_TRACK_TOOL ||
255  frame()->Settings().m_MagneticPads == MAGNETIC_OPTIONS::CAPTURE_ALWAYS );
256 
257  pnss.SetSnapToTracks(
258  frame()->Settings().m_MagneticTracks == MAGNETIC_OPTIONS::CAPTURE_CURSOR_IN_TRACK_TOOL
259  || frame()->Settings().m_MagneticTracks == MAGNETIC_OPTIONS::CAPTURE_ALWAYS );
260 
261  if( aItem )
262  {
263  if( aItem->OfKind( ITEM::VIA_T | ITEM::SEGMENT_T | ITEM::ARC_T ) )
264  return pnss.GetSnapToTracks();
265  else if( aItem->OfKind( ITEM::SOLID_T ) )
266  return pnss.GetSnapToPads();
267  }
268 
269  return false;
270 }
271 
272 void TOOL_BASE::updateStartItem( const TOOL_EVENT& aEvent, bool aIgnorePads )
273 {
274  int tl = getView()->GetTopLayer();
275  VECTOR2I cp = controls()->GetCursorPosition( !aEvent.Modifier( MD_SHIFT ) );
276  VECTOR2I p;
277 
278  controls()->ForceCursorPosition( false );
279  m_gridHelper->SetUseGrid( !aEvent.Modifier( MD_ALT ) );
280  m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
281 
282  bool snapEnabled = true;
283 
284  if( aEvent.IsMotion() || aEvent.IsClick() )
285  {
286  snapEnabled = !aEvent.Modifier( MD_SHIFT );
287  p = aEvent.Position();
288  }
289  else
290  {
291  p = cp;
292  }
293 
294  m_startItem = pickSingleItem( p, -1, -1, aIgnorePads );
295 
296  if( !snapEnabled && m_startItem && !m_startItem->Layers().Overlaps( tl ) )
297  m_startItem = nullptr;
298 
299  m_startSnapPoint = snapToItem( snapEnabled, m_startItem, p );
300 
301  if( checkSnap( m_startItem ) )
302  {
304  }
305 }
306 
307 
309 {
310  int layer;
311  bool snapEnabled = !aEvent.Modifier( MD_SHIFT );
312  m_gridHelper->SetUseGrid( !aEvent.Modifier( MD_ALT ) );
313  m_gridHelper->SetSnap( snapEnabled );
314 
315  controls()->ForceCursorPosition( false );
316  VECTOR2I mousePos = controls()->GetMousePosition();
317 
318  if( m_router->Settings().Mode() != RM_MarkObstacles &&
319  ( m_router->GetCurrentNets().empty() || m_router->GetCurrentNets().front() < 0 ) )
320  {
321  m_endSnapPoint = snapToItem( snapEnabled, nullptr, mousePos );
323  m_endItem = nullptr;
324 
325  return;
326  }
327 
328  if( m_router->IsPlacingVia() )
329  layer = -1;
330  else
331  layer = m_router->GetCurrentLayer();
332 
333  ITEM* endItem = nullptr;
334 
335  std::vector<int> nets = m_router->GetCurrentNets();
336 
337  for( int net : nets )
338  {
339  endItem = pickSingleItem( mousePos, net, layer, false, { m_startItem } );
340 
341  if( endItem )
342  break;
343  }
344 
345  if( checkSnap( endItem ) )
346  {
347  m_endItem = endItem;
348  m_endSnapPoint = snapToItem( snapEnabled, endItem, mousePos );
349  } else {
350  m_endItem = nullptr;
351  m_endSnapPoint = m_gridHelper->Align( mousePos );
352  }
353 
355 
356  if( m_endItem )
357  {
358  wxLogTrace( "PNS", "%s, layer : %d", m_endItem->KindStr().c_str(), m_endItem->Layers().Start() );
359  }
360 }
361 
362 
363 void TOOL_BASE::deleteTraces( ITEM* aStartItem, bool aWholeTrack )
364 {
365  NODE *node = m_router->GetWorld()->Branch();
366 
367  if( !aStartItem )
368  return;
369 
370  if( !aWholeTrack )
371  {
372  node->Remove( aStartItem );
373  }
374  else
375  {
376  TOPOLOGY topo( node );
377  ITEM_SET path = topo.AssembleTrivialPath( aStartItem );
378 
379  for( const auto& ent : path.Items() )
380  node->Remove( ent.item );
381  }
382 
383  m_router->CommitRouting( node );
384 }
385 
386 
388 {
389  return m_router;
390 }
391 
392 
393 const VECTOR2I TOOL_BASE::snapToItem( bool aEnabled, ITEM* aItem, VECTOR2I aP)
394 {
395  VECTOR2I anchor;
396 
397  if( !aItem || !aEnabled || !m_iface->IsItemVisible( aItem ) )
398  {
399  return m_gridHelper->Align( aP );
400  }
401 
402  switch( aItem->Kind() )
403  {
404  case ITEM::SOLID_T:
405  anchor = static_cast<SOLID*>( aItem )->Pos();
406  break;
407 
408  case ITEM::VIA_T:
409  anchor = static_cast<VIA*>( aItem )->Pos();
410  break;
411 
412  case ITEM::SEGMENT_T:
413  case ITEM::ARC_T:
414  {
415  LINKED_ITEM* li = static_cast<LINKED_ITEM*>( aItem );
416  int w = li->Width();
417  auto A = li->Anchor( 0 );
418  auto B = li->Anchor( 1 );
419 
420  if( ( aP - A ).EuclideanNorm() < w / 2 )
421  anchor = A;
422  else if( ( aP - B ).EuclideanNorm() < w / 2 )
423  anchor = B;
424  else // TODO(snh): Clean this up
425  if( aItem->Kind() == ITEM::SEGMENT_T )
426  anchor = m_gridHelper->AlignToSegment( aP, static_cast<SEGMENT*>( li )->Seg() );
427  else if( aItem->Kind() == ITEM::ARC_T )
428  anchor = m_gridHelper->AlignToArc( aP,
429  *static_cast<const SHAPE_ARC*>( static_cast<ARC*>( li )->Shape() ) );
430 
431  break;
432  }
433 
434  default:
435  break;
436  }
437 
438  return anchor;
439 }
440 
441 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:128
void SetHostTool(PCB_TOOL_BASE *aTool)
ITEM.
Definition: pns_item.h:53
void SetView(KIGFX::VIEW *aView)
NODE.
Definition: pns_node.h:145
GRID_HELPER * m_gridHelper
Definition: pns_tool_base.h:75
static const int dist[10][10]
Definition: ar_matrix.cpp:326
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:131
RENDER_SETTINGS Contains all the knowledge about how graphical objects are drawn on any output surfac...
Definition: painter.h:56
Implementation of conversion functions that require both schematic and board internal units.
VIEW_CONTROLS class definition.
VECTOR2I m_startSnapPoint
Definition: pns_tool_base.h:69
const ITEM_SET QueryHoverItems(const VECTOR2I &aP)
Definition: pns_router.cpp:123
bool IsClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.cpp:178
void CommitRouting()
Definition: pns_router.cpp:422
ENTRIES & Items()
Definition: pns_itemset.h:140
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:96
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
bool IsPlacingVia() const
Definition: pns_router.cpp:531
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:491
bool IsAnyLayerVisible(const LAYER_RANGE &aLayer) override
bool IsHighlightEnabled() const
Function IsHighlightEnabled Returns current highlight setting.
Definition: painter.h:113
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:199
This file contains miscellaneous commonly used macros and functions.
void ClearWorld()
Definition: pns_router.cpp:105
void Remove(ARC *aArc)
Function Remove()
Definition: pns_node.cpp:796
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:71
virtual void updateEndItem(const TOOL_EVENT &aEvent)
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
void SetHighlight(bool aEnabled, int aNetcode=-1, bool aHighlightItems=false)
Function SetHighlight Turns on/off highlighting - it may be done for the active layer,...
Definition: painter.h:136
virtual ~TOOL_BASE()
virtual int GetTopLayer() const
Definition: view.cpp:851
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.
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)
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:36
void SetInterface(ROUTER_IFACE *aIface)
Definition: pns_router.cpp:561
const PCB_DISPLAY_OPTIONS & displayOptions() const
void SetBoard(BOARD *aBoard)
void SetSnap(bool aSnap)
Definition: grid_helper.h:84
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:226
bool IsItemVisible(const PNS::ITEM *aItem) override
VECTOR2I Align(const VECTOR2I &aPoint) const
virtual RENDER_SETTINGS * GetSettings()=0
Function GetSettings 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:332
KIGFX::VIEW_CONTROLS * controls() const
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:133
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:78
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
PnsKind Kind() const
Function Kind()
Definition: pns_item.h:123
int GetHighlightNetCode() const
Function GetHighlightNetCode Returns netcode of currently highlighted net.
Definition: painter.h:123
void LoadSettings(ROUTING_SETTINGS *aSettings)
Changes routing settings to ones passed in the parameter.
Definition: pns_router.h:213
void SetUseGrid(bool aGrid=true)
Definition: grid_helper.h:94
ROUTER * Router() const
void UpdateAllLayersColor()
Function UpdateAllLayersColor() Applies the new coloring scheme to all layers.
Definition: view.cpp:798
Push and Shove diff pair dimensions (gap) settings dialog.
NODE * GetWorld() const
Definition: pns_router.h:152
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:199
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:151
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:69
PCBNEW_SETTINGS * GetSettings()
int GetCurrentLayer() const
Definition: pns_router.cpp:500