KiCad PCB EDA Suite
pns_dragger.cpp
Go to the documentation of this file.
1 /*
2  * KiRouter - a push-and-(sometimes-)shove PCB router
3  *
4  * Copyright (C) 2013-2014 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 "pns_dragger.h"
23 #include "pns_shove.h"
24 #include "pns_router.h"
25 
26 namespace PNS {
27 
28 DRAGGER::DRAGGER( ROUTER* aRouter ) :
29  ALGO_BASE( aRouter )
30 {
31  m_world = NULL;
32  m_lastNode = NULL;
35  m_dragStatus = false;
37  m_freeAngleMode = false;
38 }
39 
40 
42 {
43 }
44 
45 
46 void DRAGGER::SetWorld( NODE* aWorld )
47 {
48  m_world = aWorld;
49 }
50 
51 
52 bool DRAGGER::startDragSegment( const VECTOR2D& aP, SEGMENT* aSeg )
53 {
54  int w2 = aSeg->Width() / 2;
55 
57 
58  if( m_shove )
59  {
60  m_shove->SetInitialLine( m_draggedLine );
61  }
62 
63  auto distA = ( aP - aSeg->Seg().A ).EuclideanNorm();
64  auto distB = ( aP - aSeg->Seg().B ).EuclideanNorm();
65 
66  if( distA <= w2 )
67  {
68  m_mode = DM_CORNER;
69  }
70  else if( distB <= w2 )
71  {
73  m_mode = DM_CORNER;
74  }
75  else if ( m_freeAngleMode )
76  {
77  if( distB < distA )
78  {
80  }
81  m_mode = DM_CORNER;
82  }
83  else
84  {
86  }
87 
88  return true;
89 }
90 
91 
93 {
94  m_initialVia = aVia->MakeHandle();
96 
97  m_mode = DM_VIA;
98 
99  return true;
100 }
101 
103 {
104  ITEM_SET rv;
105 
106  JOINT* jt = aNode->FindJoint( handle.pos, handle.layers.Start(), handle.net );
107 
108  if( !jt )
109  return rv;
110 
111  for( ITEM* item : jt->LinkList() )
112  {
113  if( item->OfKind( ITEM::SEGMENT_T ) )
114  {
115  int segIndex;
116  SEGMENT* seg = ( SEGMENT*) item;
117  LINE l = aNode->AssembleLine( seg, &segIndex );
118 
119  if( segIndex != 0 )
120  l.Reverse();
121 
122  rv.Add( l );
123  } else if ( item->OfKind( ITEM::VIA_T ))
124  {
125  rv.Add( item );
126  }
127  }
128 
129  return rv;
130 }
131 
132 bool DRAGGER::Start( const VECTOR2I& aP, ITEM* aStartItem )
133 {
134  m_lastNode = NULL;
138 
140  m_shove = std::make_unique<SHOVE>( m_world, Router() );
141 
142  aStartItem->Unmark( MK_LOCKED );
143 
144  wxLogTrace( "PNS", "StartDragging: item %p [kind %d]", aStartItem, (int) aStartItem->Kind() );
145 
146  switch( aStartItem->Kind() )
147  {
148  case ITEM::SEGMENT_T:
149  return startDragSegment( aP, static_cast<SEGMENT*>( aStartItem ) );
150 
151  case ITEM::VIA_T:
152  return startDragVia( static_cast<VIA*>( aStartItem ) );
153 
154  default:
155  return false;
156  }
157 }
158 
159 
160 void DRAGGER::SetMode( int aMode )
161 {
162  m_mode = aMode;
163 }
164 
165 
167 {
168  // fixme: rewrite using shared_ptr...
169  if( m_lastNode )
170  {
171  delete m_lastNode;
172  m_lastNode = nullptr;
173  }
174 
176 
177  switch( m_mode )
178  {
179  case DM_SEGMENT:
180  case DM_CORNER:
181  {
182  int thresh = Settings().SmoothDraggedSegments() ? m_draggedLine.Width() / 4 : 0;
183  LINE origLine( m_draggedLine );
184  LINE dragged( m_draggedLine );
185  dragged.ClearSegmentLinks();
186 
187  if( m_mode == DM_SEGMENT )
188  dragged.DragSegment( aP, m_draggedSegmentIndex, thresh );
189  else
190  dragged.DragCorner( aP, m_draggedSegmentIndex, thresh, m_freeAngleMode );
191 
192  m_lastNode->Remove( origLine );
193  m_lastNode->Add( dragged );
194 
196  m_draggedItems.Add( dragged );
197 
198  break;
199  }
200 
201  case DM_VIA: // fixme...
202  {
204 
205  break;
206  }
207  }
208 
209  if( Settings().CanViolateDRC() )
210  m_dragStatus = true;
211  else
213 
214  return true;
215 }
216 
217 
218 void DRAGGER::dumbDragVia( const VIA_HANDLE& aHandle, NODE* aNode, const VECTOR2I& aP )
219 {
221 
222  ITEM_SET fanout = findViaFanoutByHandle( aNode, aHandle );
223 
224  if( fanout.Empty() )
225  {
226  return;
227  }
228 
229  for( ITEM* item : fanout.Items() )
230  {
231  if( const LINE* l = dyn_cast<const LINE*>( item ) )
232  {
233  LINE origLine( *l );
234  LINE draggedLine( *l );
235 
236  draggedLine.DragCorner( aP, origLine.CLine().Find( aHandle.pos ), 0, m_freeAngleMode );
237  draggedLine.ClearSegmentLinks();
238 
239  m_draggedItems.Add( draggedLine );
240 
241  m_lastNode->Remove( origLine );
242  m_lastNode->Add( draggedLine );
243  }
244  else if ( VIA *via = dyn_cast<VIA*>( item ) )
245  {
246  auto nvia = Clone( *via );
247 
248  nvia->SetPos( aP );
249  m_draggedItems.Add( nvia.get() );
250 
251  m_lastNode->Remove( via );
252  m_lastNode->Add( std::move( nvia ) );
253  }
254  }
255 }
256 
257 
258 bool DRAGGER::dragShove( const VECTOR2I& aP )
259 {
260  bool ok = false;
261 
262  if( m_lastNode )
263  {
264  delete m_lastNode;
265  m_lastNode = NULL;
266  }
267 
268  switch( m_mode )
269  {
270  case DM_SEGMENT:
271  case DM_CORNER:
272  {
273  int thresh = Settings().SmoothDraggedSegments() ? m_draggedLine.Width() / 4 : 0;
274  LINE dragged( m_draggedLine );
275 
276  if( m_mode == DM_SEGMENT )
277  dragged.DragSegment( aP, m_draggedSegmentIndex, thresh );
278  else
279  dragged.DragCorner( aP, m_draggedSegmentIndex, thresh );
280 
281  SHOVE::SHOVE_STATUS st = m_shove->ShoveLines( dragged );
282 
283  if( st == SHOVE::SH_OK )
284  ok = true;
285  else if( st == SHOVE::SH_HEAD_MODIFIED )
286  {
287  dragged = m_shove->NewHead();
288  ok = true;
289  }
290 
291  m_lastNode = m_shove->CurrentNode()->Branch();
292 
293  if( ok )
294  {
295  dragged.ClearSegmentLinks();
296  dragged.Unmark();
297  m_lastNode->Add( dragged );
299  m_draggedItems.Add( dragged );
300  }
301 
302  break;
303  }
304 
305  case DM_VIA:
306  {
307  VIA_HANDLE newVia;
308 
309  SHOVE::SHOVE_STATUS st = m_shove->ShoveDraggingVia( m_draggedVia, aP, newVia );
310 
311  if( st == SHOVE::SH_OK || st == SHOVE::SH_HEAD_MODIFIED )
312  ok = true;
313 
314  m_lastNode = m_shove->CurrentNode()->Branch();
315 
316  if( newVia.valid )
317  m_draggedVia = newVia;
318 
320  break;
321  }
322  }
323 
324  m_dragStatus = ok;
325 
326  return ok;
327 }
328 
329 
331 {
332  NODE* node = CurrentNode();
333 
334  if( node )
335  {
336  // Collisions still prevent fixing unless "Allow DRC violations" is checked
337  if( !m_dragStatus )
338  return false;
339 
340  Router()->CommitRouting( node );
341  return true;
342  }
343 
344  return false;
345 }
346 
347 
348 bool DRAGGER::Drag( const VECTOR2I& aP )
349 {
350  if( m_freeAngleMode )
351  return dragMarkObstacles( aP );
352 
353  switch( m_currentMode )
354  {
355  case RM_MarkObstacles:
356  return dragMarkObstacles( aP );
357 
358  case RM_Shove:
359  case RM_Walkaround:
360  case RM_Smart:
361  return dragShove( aP );
362 
363  default:
364  return false;
365  }
366 }
367 
368 
370 {
371  return m_lastNode;
372 }
373 
374 
376 {
377  return m_draggedItems;
378 }
379 
380 
382 {
383  if( m_shove )
384  return m_shove->Logger();
385 
386  return NULL;
387 }
388 
389 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:123
int Find(const VECTOR2I &aP) const
Function Find()
const SHAPE_LINE_CHAIN & CLine() const
Const accessor to the underlying shape
Definition: pns_line.h:141
ITEM.
Definition: pns_item.h:53
ITEM_SET m_draggedItems
Definition: pns_dragger.h:129
void DragCorner(const VECTOR2I &aP, int aIndex, int aSnappingThreshold=0, bool aFreeAngle=false)
Definition: pns_line.cpp:477
ROUTER * Router() const
Returns the instance of our router
Definition: pns_algo_base.h:49
void dumbDragVia(const VIA_HANDLE &aHandle, NODE *aNode, const VECTOR2I &aP)
bool Empty() const
Definition: pns_itemset.h:135
virtual LOGGER * Logger() override
Returns the logger object, allowing to dump geometry to a file.
NODE.
Definition: pns_node.h:140
NODE * m_world
Definition: pns_dragger.h:118
const VIA_HANDLE MakeHandle() const
Definition: pns_via.cpp:116
DRAGGER(ROUTER *aRouter)
Definition: pns_dragger.cpp:28
std::unique_ptr< SHOVE > m_shove
Definition: pns_dragger.h:124
NODE * CurrentNode() const
Function CurrentNode()
const LINE AssembleLine(SEGMENT *aSeg, int *aOriginSegmentIndex=NULL, bool aStopAtLockedJoints=false)
Function AssembleLine()
Definition: pns_node.cpp:820
Ignore collisions, mark obstacles
ALGO_BASE.
Definition: pns_algo_base.h:39
ENTRIES & Items()
Definition: pns_itemset.h:140
bool m_dragStatus
Definition: pns_dragger.h:126
virtual void Unmark(int aMarker=-1)
Definition: pns_item.h:219
bool startDragSegment(const VECTOR2D &aP, SEGMENT *aSeg)
Definition: pns_dragger.cpp:52
VIA_HANDLE m_draggedVia
Definition: pns_dragger.h:116
LINE m_draggedLine
Definition: pns_dragger.h:121
void DragSegment(const VECTOR2I &aP, int aIndex, int aSnappingThreshold=0, bool aFreeAngle=false)
Definition: pns_line.cpp:489
const SEG & Seg() const
Definition: pns_segment.h:93
void Add(const LINE &aLine)
Definition: pns_itemset.cpp:32
NODE * Branch()
Function Branch()
Definition: pns_node.cpp:104
bool startDragVia(VIA *aVia)
Definition: pns_dragger.cpp:92
bool Drag(const VECTOR2I &aP)
Function Drag()
int Start() const
Definition: pns_layerset.h:83
void SetWorld(NODE *aWorld)
Function SetWorld()
Definition: pns_dragger.cpp:46
ROUTING_SETTINGS & Settings() const
Returns current router settings
JOINT.
Definition: pns_joint.h:43
int Width() const
Definition: pns_segment.h:88
void Reverse()
Reverses the point/vertex order
Definition: pns_line.cpp:770
#define NULL
const ITEM_SET Traces()
Function Traces()
int m_draggedSegmentIndex
Definition: pns_dragger.h:125
bool SmoothDraggedSegments() const
Returns true if smoothing segments durign dragging is enabled.
PNS_MODE Mode() const
Returns the routing mode.
bool FixRoute()
Function FixRoute()
bool Start(const VECTOR2I &aP, ITEM *aStartItem)
Function Start()
const LINKED_ITEMS & LinkList() const
Definition: pns_joint.h:195
void Remove(SOLID *aSolid)
Function Remove()
Definition: pns_node.cpp:715
JOINT * FindJoint(const VECTOR2I &aPos, int aLayer, int aNet)
Function FindJoint()
Definition: pns_node.cpp:954
void SetMode(int aDragMode)
NODE * m_lastNode
Definition: pns_dragger.h:119
std::unique_ptr< typename std::remove_const< T >::type > Clone(const T &aItem)
Definition: pns_item.h:270
Only walkaround
const ITEM_SET findViaFanoutByHandle(NODE *aNode, const VIA_HANDLE &handle)
void ClearSegmentLinks()
Erases the linking information. Used to detach the line from the owning node.
Definition: pns_line.cpp:855
bool dragShove(const VECTOR2I &aP)
PNS_MODE m_currentMode
Definition: pns_dragger.h:127
void CommitRouting(NODE *aNode)
Definition: pns_router.cpp:356
OPT_OBSTACLE CheckColliding(const ITEM *aItem, int aKindMask=ITEM::ANY_T)
Function CheckColliding()
Definition: pns_node.cpp:421
LAYER_RANGE layers
Definition: pns_via.h:44
VECTOR2I A
Definition: seg.h:47
VIA_HANDLE m_initialVia
Definition: pns_dragger.h:115
int Width() const
Returns line width
Definition: pns_line.h:178
bool dragMarkObstacles(const VECTOR2I &aP)
VECTOR2I pos
Definition: pns_via.h:43
PnsKind Kind() const
Function Kind()
Definition: pns_item.h:122
bool m_freeAngleMode
Definition: pns_dragger.h:130
Push and Shove diff pair dimensions (gap) settings dialog.
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Function Add()
Definition: pns_node.cpp:590
virtual void Unmark(int aMarker=-1) override
Definition: pns_line.cpp:96
VECTOR2I B
Definition: seg.h:48