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 <pcbnew_id.h>
34 #include <view/view_controls.h>
35 #include <pcb_painter.h>
40 #include <base_units.h>
41 #include <bitmaps.h>
42 #include <hotkeys.h>
43 
44 #include <tool/context_menu.h>
45 #include <tools/pcb_actions.h>
46 #include <tools/grid_helper.h>
47 
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( aToolName )
67 {
68  m_gridHelper = nullptr;
69  m_iface = nullptr;
70  m_router = nullptr;
71 
72  m_startItem = nullptr;
73  m_startLayer = 0;
74 
75  m_endItem = nullptr;
76  m_gridHelper = nullptr;
77 }
78 
79 
81 {
82  delete m_gridHelper;
83  delete m_iface;
84  delete m_router;
85 }
86 
87 
88 
90 {
91  delete m_gridHelper;
92  delete m_iface;
93  delete m_router;
94 
96  m_iface->SetBoard( board() );
97  m_iface->SetView( getView() );
98  m_iface->SetHostTool( this );
99  m_iface->SetDisplayOptions( (PCB_DISPLAY_OPTIONS*) frame()->GetDisplayOptions() );
100 
101  m_router = new ROUTER;
103  m_router->ClearWorld();
104  m_router->SyncWorld();
107 
108  m_gridHelper = new GRID_HELPER( frame() );
109 }
110 
111 
112 ITEM* TOOL_BASE::pickSingleItem( const VECTOR2I& aWhere, int aNet, int aLayer, bool aIgnorePads )
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  int dist[candidateCount];
122 
123  for( int i = 0; i < candidateCount; i++ )
124  {
125  prioritized[i] = 0;
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  // fixme: this causes flicker with live loop removal...
140  //if( item->Parent() && !item->Parent()->ViewIsVisible() )
141  // continue;
142 
143  if( aNet <= 0 || item->Net() == aNet )
144  {
145  if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) )
146  {
147  if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
148  continue;
149 
150  int itemDist = ( item->Shape()->Centre() - aWhere ).SquaredEuclideanNorm();
151 
152  if( !prioritized[2] || itemDist < dist[2] )
153  {
154  prioritized[2] = item;
155  dist[2] = itemDist;
156  }
157  if( item->Layers().Overlaps( tl ) && itemDist < dist[0] )
158  {
159  prioritized[0] = item;
160  dist[0] = itemDist;
161  }
162  }
163  else
164  {
165  if( !prioritized[3] )
166  prioritized[3] = item;
167  if( item->Layers().Overlaps( tl ) )
168  prioritized[1] = item;
169  }
170  }
171  // Allow unconnected items as last resort in RM_MarkObstacles mode
172  else if ( item->Net() == 0 && m_router->Settings().Mode() == RM_MarkObstacles )
173  {
174  if( item->OfKind( ITEM::SOLID_T ) && aIgnorePads )
175  continue;
176 
177  if( item->Layers().Overlaps( tl ) )
178  prioritized[4] = item;
179  }
180  }
181 
182  ITEM* rv = NULL;
183 
184  for( int i = 0; i < candidateCount; i++ )
185  {
186  ITEM* item = prioritized[i];
187 
189  if( item && !item->Layers().Overlaps( tl ) )
190  item = NULL;
191 
192  if( item )
193  {
194  rv = item;
195  break;
196  }
197  }
198 
199  if( rv && aLayer >= 0 && !rv->Layers().Overlaps( aLayer ) )
200  rv = NULL;
201 
202  if( rv )
203  {
204  wxLogTrace( "PNS", "%s, layer : %d, tl: %d", rv->KindStr().c_str(), rv->Layers().Start(), tl );
205  }
206 
207  return rv;
208 }
209 
210 
211 void TOOL_BASE::highlightNet( bool aEnabled, int aNetcode )
212 {
214 
215  if( aNetcode >= 0 && aEnabled )
216  rs->SetHighlight( true, aNetcode );
217  else
218  rs->SetHighlight( false );
219 
221 }
222 
224 {
225  bool doSnap = false;
226 
227  // Sync PNS engine settings with the general PCB editor options. I know the code below is awful, but...
228  auto& pnss = m_router->Settings();
229  const auto& gens = frame()->Settings();
230 
231  pnss.SetSnapToTracks( false );
232  pnss.SetSnapToPads( false );
233 
234  if( gens.m_magneticPads == CAPTURE_CURSOR_IN_TRACK_TOOL || gens.m_magneticPads == CAPTURE_ALWAYS )
235  pnss.SetSnapToPads( true );
236 
237  if( gens.m_magneticTracks == CAPTURE_CURSOR_IN_TRACK_TOOL || gens.m_magneticTracks == CAPTURE_ALWAYS )
238  pnss.SetSnapToTracks( true );
239 
240  if( aItem )
241  {
242  if( ( aItem->OfKind( ITEM::VIA_T ) || aItem->OfKind( ITEM::SEGMENT_T ) ) && pnss.GetSnapToTracks() )
243  doSnap = true;
244  else if( aItem->OfKind( ITEM::SOLID_T ) && pnss.GetSnapToPads() )
245  doSnap = true;
246  }
247 
248  return doSnap;
249 }
250 
251 void TOOL_BASE::updateStartItem( TOOL_EVENT& aEvent, bool aIgnorePads )
252 {
253  int tl = getView()->GetTopLayer();
255  VECTOR2I p;
256 
257  controls()->ForceCursorPosition( false );
258 
259  bool snapEnabled = true;
260 
261  if( aEvent.IsMotion() || aEvent.IsClick() )
262  {
263  snapEnabled = !aEvent.Modifier( MD_SHIFT );
264  p = aEvent.Position();
265  }
266  else
267  {
268  p = cp;
269  }
270 
271  m_startItem = pickSingleItem( p, -1, -1, aIgnorePads );
272 
273  if( !snapEnabled && m_startItem && !m_startItem->Layers().Overlaps( tl ) )
274  m_startItem = nullptr;
275 
276  m_startSnapPoint = snapToItem( snapEnabled, m_startItem, p );
277 
278  if( checkSnap ( m_startItem ))
279  {
281  }
282 }
283 
284 
286 {
287  controls()->ForceCursorPosition( false );
288 
289  VECTOR2I mousePos = controls()->GetMousePosition();
290  VECTOR2I cursorPos = controls()->GetCursorPosition();
291 
292  int layer;
293  bool snapEnabled = !aEvent.Modifier( MD_SHIFT );
294 
295  if( m_router->Settings().Mode() != RM_MarkObstacles &&
296  ( m_router->GetCurrentNets().empty() || m_router->GetCurrentNets().front() < 0 ) )
297  {
298  m_endSnapPoint = snapToItem( snapEnabled, nullptr, mousePos );
300  m_endItem = nullptr;
301 
302  return;
303  }
304 
305  if( m_router->IsPlacingVia() )
306  layer = -1;
307  else
308  layer = m_router->GetCurrentLayer();
309 
310  ITEM* endItem = nullptr;
311 
312  std::vector<int> nets = m_router->GetCurrentNets();
313 
314  for( int net : nets )
315  {
316  endItem = pickSingleItem( mousePos, net, layer );
317 
318  if( endItem )
319  break;
320  }
321 
322  if( checkSnap( endItem ) )
323  {
324  VECTOR2I p = snapToItem( snapEnabled, endItem, mousePos );
325  controls()->ForceCursorPosition( true, p );
326  m_endItem = endItem;
327  m_endSnapPoint = p;
328  } else {
329  m_endItem = nullptr;
330  m_endSnapPoint = cursorPos;
331  }
332 
333  if( m_endItem )
334  {
335  wxLogTrace( "PNS", "%s, layer : %d", m_endItem->KindStr().c_str(), m_endItem->Layers().Start() );
336  }
337 }
338 
339 
340 void TOOL_BASE::deleteTraces( ITEM* aStartItem, bool aWholeTrack )
341 {
342  NODE *node = m_router->GetWorld()->Branch();
343 
344  if( !aStartItem )
345  return;
346 
347  if( !aWholeTrack )
348  {
349  node->Remove( aStartItem );
350  }
351  else
352  {
353  TOPOLOGY topo( node );
354  ITEM_SET path = topo.AssembleTrivialPath( aStartItem );
355 
356  for( auto ent : path.Items() )
357  node->Remove( ent.item );
358  }
359 
360  m_router->CommitRouting( node );
361 }
362 
363 
365 {
366  return m_router;
367 }
368 
369 
370 const VECTOR2I TOOL_BASE::snapToItem( bool aEnabled, ITEM* aItem, VECTOR2I aP)
371 {
372  VECTOR2I anchor;
373 
374  if( !aItem || !aEnabled )
375  {
376  return m_gridHelper->Align( aP );
377  }
378 
379  switch( aItem->Kind() )
380  {
381  case ITEM::SOLID_T:
382  anchor = static_cast<SOLID*>( aItem )->Pos();
383  break;
384 
385  case ITEM::VIA_T:
386  anchor = static_cast<VIA*>( aItem )->Pos();
387  break;
388 
389  case ITEM::SEGMENT_T:
390  {
391  SEGMENT* seg = static_cast<SEGMENT*>( aItem );
392  const SEG& s = seg->Seg();
393  int w = seg->Width();
394 
395 
396  if( ( aP - s.A ).EuclideanNorm() < w / 2 )
397  anchor = s.A;
398  else if( ( aP - s.B ).EuclideanNorm() < w / 2 )
399  anchor = s.B;
400  else
401  anchor = m_gridHelper->AlignToSegment( aP, s );
402 
403  break;
404  }
405 
406  default:
407  break;
408  }
409 
410  return anchor;
411 }
412 
413 }
PNS_MODE Mode() const
Returns the routing mode.
Class ITEM.
Definition: pns_item.h:53
virtual int GetTopLayer() const
Definition: view.cpp:794
void SetView(KIGFX::VIEW *aView)
Class NODE.
Definition: pns_node.h:136
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.
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:58
const LAYER_RANGE & Layers() const
Function Layers()
Definition: pns_item.h:209
void LoadSettings(const ROUTING_SETTINGS &aSettings)
Changes routing settings to ones passed in the parameter.
Definition: pns_router.h:201
Class RENDER_SETTINGS Contains all the knowledge about how graphical objects are drawn on any output ...
Definition: painter.h:56
Implementation of conversion functions that require both schematic and board internal units...
bool IsMotion() const
Definition: tool_event.h:290
VECTOR2I Align(const VECTOR2I &aPoint) const
VIEW_CONTROLS class definition.
VECTOR2I m_startSnapPoint
Definition: pns_tool_base.h:70
const ITEM_SET QueryHoverItems(const VECTOR2I &aP)
Definition: pns_router.cpp:118
Class BOARD to handle a board.
ENTRIES & Items()
Definition: pns_itemset.h:140
SIZES_SETTINGS m_savedSizes
Stores sizes settings between router invocations.
Definition: pns_tool_base.h:67
static const int dist[10][10]
Definition: dist.cpp:57
void SyncWorld()
Definition: pns_router.cpp:91
VECTOR2I AlignToSegment(const VECTOR2I &aPoint, const SEG &aSeg)
int Modifier(int aMask=MD_MODIFIER_MASK) const
Returns information about key modifiers state (Ctrl, Alt, etc.)
Definition: tool_event.h:316
const VECTOR2D & Position() const
Returns mouse cursor position in world coordinates.
Definition: tool_event.h:248
bool IsPlacingVia() const
Definition: pns_router.cpp:489
const std::vector< int > GetCurrentNets() const
Definition: pns_router.cpp:449
NODE * Branch()
Function Branch()
Definition: pns_node.cpp:107
const VECTOR2I snapToItem(bool aEnabled, ITEM *aItem, VECTOR2I aP)
NODE * GetWorld() const
Definition: pns_router.h:143
virtual ITEM * pickSingleItem(const VECTOR2I &aWhere, int aNet=-1, int aLayer=-1, bool aIgnorePads=false)
Pcbnew hotkeys.
This file contains miscellaneous commonly used macros and functions.
void ClearWorld()
Definition: pns_router.cpp:100
bool OfKind(int aKindMask) const
Function OfKind()
Definition: pns_item.h:132
PCB_DISPLAY_OPTIONS * displayOptions() const
Definition: pcb_tool.cpp:211
KIGFX::VIEW_CONTROLS * controls() const
Definition: pcb_tool.h:135
virtual void updateEndItem(const TOOL_EVENT &aEvent)
virtual void Reset(RESET_REASON aReason) override
Function Reset() Brings the tool to a known, initial state.
Class PCB_DISPLAY_OPTIONS handles display options like enable/disable some optional drawings...
bool checkSnap(ITEM *aItem)
const ITEM_SET AssembleTrivialPath(ITEM *aStart)
virtual ~TOOL_BASE()
PCB_GENERAL_SETTINGS & Settings()
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
PCB_EDIT_FRAME * frame() const
Definition: pcb_tool.h:136
Class TOOL_EVENT.
Definition: tool_event.h:162
ITEM * m_startItem
Definition: pns_tool_base.h:68
ROUTER * m_router
Definition: pns_tool_base.h:77
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Function ForceCursorPosition() Places the cursor immediately at a given point.
ROUTING_SETTINGS m_savedSettings
Stores routing settings between router invocations.
Definition: pns_tool_base.h:66
int Width() const
Definition: pns_segment.h:88
PAINTER * GetPainter() const
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:196
int Start() const
Definition: pns_layerset.h:83
bool Overlaps(const LAYER_RANGE &aOther) const
Definition: pns_layerset.h:68
void SetInterface(ROUTER_IFACE *aIface)
Definition: pns_router.cpp:513
void Remove(SOLID *aSolid)
Function Remove()
Definition: pns_node.cpp:729
PnsKind Kind() const
Function Kind()
Definition: pns_item.h:122
KIGFX::VIEW * getView() const
Function getView()
Definition: tool_base.cpp:35
virtual void highlightNet(bool aEnabled, int aNetcode=-1)
Definition: seg.h:36
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:308
void CommitRouting(NODE *aNode)
Definition: pns_router.cpp:347
#define max(a, b)
Definition: auxiliary.h:86
VECTOR2I m_endSnapPoint
Definition: pns_tool_base.h:73
void deleteTraces(ITEM *aStartItem, bool aWholeTrack)
size_t i
Definition: json11.cpp:597
VECTOR2I A
Definition: seg.h:46
virtual void updateStartItem(TOOL_EVENT &aEvent, bool aIgnorePads=false)
void SetHostTool(PCB_TOOL *aTool)
RESET_REASON
Determines the reason of reset for a tool
Definition: tool_base.h:80
bool IsCopperLayer(LAYER_NUM aLayerId)
Function IsCopperLayer tests whether a layer is a copper layer.
const SEG & Seg() const
Definition: pns_segment.h:93
int GetCurrentLayer() const
Definition: pns_router.cpp:458
void UpdateAllLayersColor()
Function UpdateAllLayersColor() Applies the new coloring scheme to all layers.
Definition: view.cpp:743
void SetDisplayOptions(PCB_DISPLAY_OPTIONS *aDispOptions)
ROUTER * Router() const
bool IsClick(int aButtonMask=BUT_ANY) const
Definition: tool_event.h:268
Push and Shove diff pair dimensions (gap) settings dialog.
void SetHighlight(bool aEnabled, int aNetcode=-1)
Function SetHighlight Turns on/off highlighting - it may be done for the active layer or the specifie...
Definition: painter.h:140
void SetBoard(BOARD *aBoard)
PNS_KICAD_IFACE * m_iface
Definition: pns_tool_base.h:76
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:187
const std::string KindStr() const
Function KindStr()
Definition: pns_item.cpp:63
TOOL_BASE(TOOL_TYPE aType, TOOL_ID aId, const std::string &aName=std::string(""))
Definition: tool_base.h:71
BOARD * board() const
Definition: pcb_tool.h:137
VECTOR2I B
Definition: seg.h:47