1 /*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2015 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 <class_board.h>
23 #include <class_board_item.h>
24 #include <class_netinfo.h>*/
25
26 #include "pns_node.h"
27 #include "pns_walkaround.h"
28 #include "pns_shove.h"
29 #include "pns_utils.h"
30 #include "pns_router.h"
31 #include "pns_diff_pair_placer.h"
32 #include "pns_solid.h"
33 #include "pns_topology.h"
34 #include "pns_debug_decorator.h"
35
36 namespace PNS {
37
DIFF_PAIR_PLACER(ROUTER * aRouter)38 DIFF_PAIR_PLACER::DIFF_PAIR_PLACER( ROUTER* aRouter ) :
39 PLACEMENT_ALGO( aRouter )
40 {
41 m_state = RT_START;
42 m_chainedPlacement = false;
43 m_initialDiagonal = false;
44 m_startDiagonal = false;
45 m_fitOk = false;
46 m_netP = 0;
47 m_netN = 0;
48 m_iteration = 0;
49 m_world = NULL;
50 m_shove = NULL;
51 m_currentNode = NULL;
52 m_lastNode = NULL;
53 m_placingVia = false;
54 m_viaDiameter = 0;
55 m_viaDrill = 0;
56 m_currentWidth = 0;
57 m_currentNet = 0;
58 m_currentLayer = 0;
59 m_startsOnVia = false;
60 m_orthoMode = false;
61 m_snapOnTarget = false;
62 m_currentEndItem = NULL;
63 m_currentMode = RM_MarkObstacles;
64 m_idle = true;
65 }
66
~DIFF_PAIR_PLACER()67 DIFF_PAIR_PLACER::~DIFF_PAIR_PLACER()
68 {
69 if( m_shove )
70 delete m_shove;
71 }
72
73
setWorld(NODE * aWorld)74 void DIFF_PAIR_PLACER::setWorld( NODE* aWorld )
75 {
76 m_world = aWorld;
77 }
78
makeVia(const VECTOR2I & aP,int aNet)79 const VIA DIFF_PAIR_PLACER::makeVia( const VECTOR2I& aP, int aNet )
80 {
81 const LAYER_RANGE layers( m_sizes.GetLayerTop(), m_sizes.GetLayerBottom() );
82
83 VIA v( aP, layers, m_sizes.ViaDiameter(), m_sizes.ViaDrill(), -1, m_sizes.ViaType() );
84 v.SetNet( aNet );
85
86 return v;
87 }
88
89
SetOrthoMode(bool aOrthoMode)90 void DIFF_PAIR_PLACER::SetOrthoMode ( bool aOrthoMode )
91 {
92 m_orthoMode = aOrthoMode;
93
94 if( !m_idle )
95 Move( m_currentEnd, NULL );
96 }
97
98
ToggleVia(bool aEnabled)99 bool DIFF_PAIR_PLACER::ToggleVia( bool aEnabled )
100 {
101 m_placingVia = aEnabled;
102
103 if( !m_idle )
104 Move( m_currentEnd, NULL );
105
106 return true;
107 }
108
109
rhMarkObstacles(const VECTOR2I & aP)110 bool DIFF_PAIR_PLACER::rhMarkObstacles( const VECTOR2I& aP )
111 {
112 if( !routeHead( aP ) )
113 return false;
114
115 bool collP = static_cast<bool>( m_currentNode->CheckColliding( &m_currentTrace.PLine() ) );
116 bool collN = static_cast<bool>( m_currentNode->CheckColliding( &m_currentTrace.NLine() ) );
117
118 m_fitOk = !( collP || collN ) ;
119
120 return m_fitOk;
121 }
122
123
propagateDpHeadForces(const VECTOR2I & aP,VECTOR2I & aNewP)124 bool DIFF_PAIR_PLACER::propagateDpHeadForces ( const VECTOR2I& aP, VECTOR2I& aNewP )
125 {
126 VIA virtHead = makeVia( aP, -1 );
127
128 if( m_placingVia )
129 virtHead.SetDiameter( viaGap() + 2 * virtHead.Diameter() );
130 else
131 {
132 virtHead.SetLayer( m_currentLayer );
133 virtHead.SetDiameter( m_sizes.DiffPairGap() + 2 * m_sizes.DiffPairWidth() );
134 }
135
136 VECTOR2I lead( 0, 0 );// = aP - m_currentStart ;
137 VECTOR2I force;
138 bool solidsOnly = true;
139
140 if( m_currentMode == RM_MarkObstacles )
141 {
142 aNewP = aP;
143 return true;
144 }
145 else if( m_currentMode == RM_Walkaround )
146 {
147 solidsOnly = false;
148 }
149
150 // fixme: I'm too lazy to do it well. Circular approximaton will do for the moment.
151 if( virtHead.PushoutForce( m_currentNode, lead, force, solidsOnly, 40 ) )
152 {
153 aNewP = aP + force;
154 return true;
155 }
156
157 return false;
158 }
159
160
attemptWalk(NODE * aNode,DIFF_PAIR * aCurrent,DIFF_PAIR & aWalk,bool aPFirst,bool aWindCw,bool aSolidsOnly)161 bool DIFF_PAIR_PLACER::attemptWalk( NODE* aNode, DIFF_PAIR* aCurrent,
162 DIFF_PAIR& aWalk, bool aPFirst, bool aWindCw, bool aSolidsOnly )
163 {
164 WALKAROUND walkaround( aNode, Router() );
165 WALKAROUND::WALKAROUND_STATUS wf1;
166
167 walkaround.SetSolidsOnly( aSolidsOnly );
168 walkaround.SetIterationLimit( Settings().WalkaroundIterationLimit() );
169
170 SHOVE shove( aNode, Router() );
171 LINE walkP, walkN;
172
173 aWalk = *aCurrent;
174
175 int iter = 0;
176
177 DIFF_PAIR cur( *aCurrent );
178
179 bool currentIsP = aPFirst;
180
181 int mask = aSolidsOnly ? ITEM::SOLID_T : ITEM::ANY_T;
182
183 do
184 {
185 LINE preWalk = ( currentIsP ? cur.PLine() : cur.NLine() );
186 LINE preShove = ( currentIsP ? cur.NLine() : cur.PLine() );
187 LINE postWalk;
188
189 if( !aNode->CheckColliding ( &preWalk, mask ) )
190 {
191 currentIsP = !currentIsP;
192
193 if( !aNode->CheckColliding( &preShove, mask ) )
194 break;
195 else
196 continue;
197 }
198
199 wf1 = walkaround.Route( preWalk, postWalk, false );
200
201 if( wf1 != WALKAROUND::DONE )
202 return false;
203
204 LINE postShove( preShove );
205
206 shove.ForceClearance( true, cur.Gap() - 2 * PNS_HULL_MARGIN );
207
208 SHOVE::SHOVE_STATUS sh1;
209
210 sh1 = shove.ProcessSingleLine( postWalk, preShove, postShove );
211
212 if( sh1 != SHOVE::SH_OK )
213 return false;
214
215 postWalk.Line().Simplify();
216 postShove.Line().Simplify();
217
218 cur.SetShape( postWalk.CLine(), postShove.CLine(), !currentIsP );
219
220 currentIsP = !currentIsP;
221
222 if( !aNode->CheckColliding( &postShove, mask ) )
223 break;
224
225 iter++;
226 }
227 while( iter < 3 );
228
229 if( iter == 3 )
230 return false;
231
232 aWalk.SetShape( cur.CP(), cur.CN() );
233
234 return true;
235 }
236
237
tryWalkDp(NODE * aNode,DIFF_PAIR & aPair,bool aSolidsOnly)238 bool DIFF_PAIR_PLACER::tryWalkDp( NODE* aNode, DIFF_PAIR &aPair, bool aSolidsOnly )
239 {
240 DIFF_PAIR best;
241 double bestScore = 100000000000000.0;
242
243 for( int attempt = 0; attempt <= 3; attempt++ )
244 {
245 DIFF_PAIR p;
246 NODE *tmp = m_currentNode->Branch();
247
248 bool pfirst = ( attempt & 1 ) ? true : false;
249 bool wind_cw = ( attempt & 2 ) ? true : false;
250
251 if( attemptWalk( tmp, &aPair, p, pfirst, wind_cw, aSolidsOnly ) )
252 {
253 // double len = p.TotalLength();
254 double cl = p.CoupledLength();
255 double skew = p.Skew();
256
257 double score = cl + fabs( skew ) * 3.0;
258
259 if( score < bestScore )
260 {
261 bestScore = score;
262 best = p;
263 }
264 }
265
266 delete tmp;
267 }
268
269 if( bestScore > 0.0 )
270 {
271 OPTIMIZER optimizer( m_currentNode );
272
273 aPair.SetShape( best );
274 optimizer.Optimize( &aPair );
275
276 return true;
277 }
278
279 return false;
280 }
281
282
rhWalkOnly(const VECTOR2I & aP)283 bool DIFF_PAIR_PLACER::rhWalkOnly( const VECTOR2I& aP )
284 {
285 if( !routeHead ( aP ) )
286 return false;
287
288 m_fitOk = tryWalkDp( m_currentNode, m_currentTrace, false );
289
290 return m_fitOk;
291 }
292
293
route(const VECTOR2I & aP)294 bool DIFF_PAIR_PLACER::route( const VECTOR2I& aP )
295 {
296 switch( m_currentMode )
297 {
298 case RM_MarkObstacles:
299 return rhMarkObstacles( aP );
300 case RM_Walkaround:
301 return rhWalkOnly( aP );
302 case RM_Shove:
303 return rhShoveOnly( aP );
304 default:
305 break;
306 }
307
308 return false;
309 }
310
311
rhShoveOnly(const VECTOR2I & aP)312 bool DIFF_PAIR_PLACER::rhShoveOnly( const VECTOR2I& aP )
313 {
314 m_currentNode = m_shove->CurrentNode();
315
316 bool ok = routeHead( aP );
317
318 m_fitOk = false;
319
320 if( !ok )
321 return false;
322
323 if( !tryWalkDp( m_currentNode, m_currentTrace, true ) )
324 return false;
325
326 LINE pLine( m_currentTrace.PLine() );
327 LINE nLine( m_currentTrace.NLine() );
328 ITEM_SET head;
329
330 head.Add( &pLine );
331 head.Add( &nLine );
332
333 SHOVE::SHOVE_STATUS status = m_shove->ShoveMultiLines( head );
334
335 m_currentNode = m_shove->CurrentNode();
336
337 if( status == SHOVE::SH_OK )
338 {
339 m_currentNode = m_shove->CurrentNode();
340
341 if( !m_currentNode->CheckColliding( &m_currentTrace.PLine() ) &&
342 !m_currentNode->CheckColliding( &m_currentTrace.NLine() ) )
343 {
344 m_fitOk = true;
345 }
346 }
347
348 return m_fitOk;
349 }
350
351
Traces()352 const ITEM_SET DIFF_PAIR_PLACER::Traces()
353 {
354 ITEM_SET t;
355
356 t.Add( const_cast<LINE*>( &m_currentTrace.PLine() ) );
357 t.Add( const_cast<LINE*>( &m_currentTrace.NLine() ) );
358
359 return t;
360 }
361
362
FlipPosture()363 void DIFF_PAIR_PLACER::FlipPosture()
364 {
365 m_startDiagonal = !m_startDiagonal;
366
367 if( !m_idle )
368 Move( m_currentEnd, NULL );
369 }
370
371
CurrentNode(bool aLoopsRemoved) const372 NODE* DIFF_PAIR_PLACER::CurrentNode( bool aLoopsRemoved ) const
373 {
374 if( m_lastNode )
375 return m_lastNode;
376
377 return m_currentNode;
378 }
379
380
SetLayer(int aLayer)381 bool DIFF_PAIR_PLACER::SetLayer( int aLayer )
382 {
383 if( m_idle )
384 {
385 m_currentLayer = aLayer;
386 return true;
387 }
388 else if( m_chainedPlacement || !m_prevPair )
389 {
390 return false;
391 }
392 else if( !m_prevPair->PrimP() || ( m_prevPair->PrimP()->OfKind( ITEM::VIA_T ) &&
393 m_prevPair->PrimP()->Layers().Overlaps( aLayer ) ) )
394 {
395 m_currentLayer = aLayer;
396 m_start = *m_prevPair;
397 initPlacement();
398 Move( m_currentEnd, NULL );
399 return true;
400 }
401
402 return false;
403 }
404
405
getDanglingAnchor(NODE * aNode,ITEM * aItem)406 OPT_VECTOR2I DIFF_PAIR_PLACER::getDanglingAnchor( NODE* aNode, ITEM* aItem )
407 {
408 switch( aItem->Kind() )
409 {
410 case ITEM::VIA_T:
411 case ITEM::SOLID_T:
412 return aItem->Anchor( 0 );
413
414 case ITEM::SEGMENT_T:
415 {
416 SEGMENT* s =static_cast<SEGMENT*>( aItem );
417
418 JOINT* jA = aNode->FindJoint( s->Seg().A, s );
419 JOINT* jB = aNode->FindJoint( s->Seg().B, s );
420
421 if( jA->LinkCount() == 1 )
422 return s->Seg().A;
423 else if( jB->LinkCount() == 1 )
424 return s->Seg().B;
425 else
426 return OPT_VECTOR2I();
427 }
428
429 default:
430 return OPT_VECTOR2I();
431 break;
432 }
433 }
434
435
436
findDpPrimitivePair(const VECTOR2I & aP,ITEM * aItem,DP_PRIMITIVE_PAIR & aPair,std::string * aErrorMsg)437 bool DIFF_PAIR_PLACER::findDpPrimitivePair( const VECTOR2I& aP, ITEM* aItem,
438 DP_PRIMITIVE_PAIR& aPair, std::string* aErrorMsg )
439 {
440 int netP, netN;
441
442 wxLogTrace( "PNS", "world %p", m_world );
443
444 bool result = m_world->GetRuleResolver()->DpNetPair( aItem, netP, netN );
445
446 if( !result )
447 {
448 if( aErrorMsg )
449 {
450 *aErrorMsg = ( "Unable to find complementary differential pair "
451 "nets. Make sure the names of the nets belonging "
452 "to a differential pair end with either _N/_P or +/-." );
453 }
454 return false;
455 }
456
457 int refNet = aItem->Net();
458 int coupledNet = ( refNet == netP ) ? netN : netP;
459
460 wxLogTrace( "PNS", "result %d", !!result );
461
462 OPT_VECTOR2I refAnchor = getDanglingAnchor( m_currentNode, aItem );
463 ITEM* primRef = aItem;
464
465 wxLogTrace( "PNS", "refAnchor %p", aItem );
466
467 if( !refAnchor )
468 {
469 if( aErrorMsg )
470 {
471 *aErrorMsg = ( "Can't find a suitable starting point. If starting "
472 "from an existing differential pair make sure you are "
473 "at the end." );
474 }
475 return false;
476 }
477
478 std::set<ITEM*> coupledItems;
479
480 m_currentNode->AllItemsInNet( coupledNet, coupledItems );
481 double bestDist = std::numeric_limits<double>::max();
482 bool found = false;
483
484 for( ITEM* item : coupledItems )
485 {
486 if( item->Kind() == aItem->Kind() )
487 {
488 OPT_VECTOR2I anchor = getDanglingAnchor( m_currentNode, item );
489 if( !anchor )
490 continue;
491
492 double dist = ( *anchor - *refAnchor ).EuclideanNorm();
493
494 bool shapeMatches = true;
495
496 if( item->OfKind( ITEM::SOLID_T ) && item->Layers() != aItem->Layers() )
497 {
498 shapeMatches = false;
499 }
500
501 if( dist < bestDist && shapeMatches )
502 {
503 found = true;
504 bestDist = dist;
505
506 if( refNet != netP )
507 {
508 aPair = DP_PRIMITIVE_PAIR ( item, primRef );
509 aPair.SetAnchors( *anchor, *refAnchor );
510 }
511 else
512 {
513 aPair = DP_PRIMITIVE_PAIR( primRef, item );
514 aPair.SetAnchors( *refAnchor, *anchor );
515 }
516 }
517 }
518 }
519
520 if( !found )
521 {
522 if( aErrorMsg )
523 {
524 *aErrorMsg = "Can't find a suitable starting point "
525 "for coupled net \""+
526 m_world->GetRuleResolver()->NetName( coupledNet ) + "\".";
527 }
528 return false;
529 }
530
531 return true;
532 }
533
534
viaGap() const535 int DIFF_PAIR_PLACER::viaGap() const
536 {
537 return m_sizes.DiffPairViaGap();
538 }
539
540
gap() const541 int DIFF_PAIR_PLACER::gap() const
542 {
543 return m_sizes.DiffPairGap() + m_sizes.DiffPairWidth();
544 }
545
546
Start(const VECTOR2I & aP,ITEM * aStartItem)547 bool DIFF_PAIR_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
548 {
549 VECTOR2I p( aP );
550 std::string msg;
551
552 if( !aStartItem )
553 {
554 Router()->SetFailureReason( ( "Can't start a differential pair "
555 " in the middle of nowhere." ) );
556 return false;
557 }
558
559 setWorld( Router()->GetWorld() );
560 m_currentNode = m_world;
561
562 if( !findDpPrimitivePair( aP, aStartItem, m_start, &msg ) )
563 {
564 Router()->SetFailureReason( msg );
565 return false;
566 }
567
568 m_netP = m_start.PrimP()->Net();
569 m_netN = m_start.PrimN()->Net();
570
571 #if 0
572 // FIXME: this also needs to be factored out but not so important right now
573 // Check if the current track/via gap & track width settings are violated
574 BOARD* brd = NULL; // FIXME Router()->GetBoard();
575 NETCLASSPTR netclassP = brd->FindNet( m_netP )->GetNetClass();
576 NETCLASSPTR netclassN = brd->FindNet( m_netN )->GetNetClass();
577 int clearance = std::min( m_sizes.DiffPairGap(), m_sizes.DiffPairViaGap() );
578
579 if( clearance < netclassP->GetClearance() || clearance < netclassN->GetClearance() )
580 {
581 Router()->SetFailureReason( _( "Current track/via gap setting violates "
582 "design rules for this net." ) );
583 return false;
584 }
585
586 if( m_sizes.DiffPairWidth() < brd->GetDesignSettings().m_TrackMinWidth )
587 {
588 Router()->SetFailureReason( _( "Current track width setting violates design rules." ) );
589 return false;
590 }
591 #endif
592
593 m_currentStart = p;
594 m_currentEnd = p;
595 m_placingVia = false;
596 m_chainedPlacement = false;
597
598 initPlacement();
599
600 return true;
601 }
602
603
initPlacement()604 void DIFF_PAIR_PLACER::initPlacement()
605 {
606 m_idle = false;
607 m_orthoMode = false;
608 m_currentEndItem = NULL;
609 m_startDiagonal = m_initialDiagonal;
610
611 NODE* world = Router()->GetWorld();
612
613 world->KillChildren();
614 NODE* rootNode = world->Branch();
615
616 setWorld( rootNode );
617
618 m_lastNode = NULL;
619 m_currentNode = rootNode;
620 m_currentMode = Settings().Mode();
621
622 if( m_shove )
623 delete m_shove;
624
625 m_shove = NULL;
626
627 if( m_currentMode == RM_Shove || m_currentMode == RM_Smart )
628 {
629 m_shove = new SHOVE( m_currentNode, Router() );
630 }
631 }
632
633
routeHead(const VECTOR2I & aP)634 bool DIFF_PAIR_PLACER::routeHead( const VECTOR2I& aP )
635 {
636 m_fitOk = false;
637
638 DP_GATEWAYS gwsEntry( gap() );
639 DP_GATEWAYS gwsTarget( gap() );
640
641 if( !m_prevPair )
642 m_prevPair = m_start;
643
644 gwsEntry.BuildFromPrimitivePair( *m_prevPair, m_startDiagonal );
645
646 DP_PRIMITIVE_PAIR target;
647
648 if( findDpPrimitivePair( aP, m_currentEndItem, target ) )
649 {
650 gwsTarget.BuildFromPrimitivePair( target, m_startDiagonal );
651 m_snapOnTarget = true;
652 }
653 else
654 {
655 VECTOR2I fp;
656
657 if( !propagateDpHeadForces( aP, fp ) )
658 return false;
659
660 VECTOR2I midp, dirV;
661 m_prevPair->CursorOrientation( fp, midp, dirV );
662
663 VECTOR2I fpProj = SEG( midp, midp + dirV ).LineProject( fp );
664
665 // compute 'leader point' distance from the cursor (project cursor position
666 // on the extension of the starting segment pair of the DP)
667 int lead_dist = ( fpProj - fp ).EuclideanNorm();
668
669 gwsTarget.SetFitVias( m_placingVia, m_sizes.ViaDiameter(), viaGap() );
670
671 // far from the initial segment extension line -> allow a 45-degree obtuse turn
672 if( lead_dist > m_sizes.DiffPairGap() + m_sizes.DiffPairWidth() )
673 {
674 gwsTarget.BuildForCursor( fp );
675 }
676 // close to the initial segment extension line -> keep straight part only, project as close
677 // as possible to the cursor
678 else
679 {
680 gwsTarget.BuildForCursor( fpProj );
681 gwsTarget.FilterByOrientation( DIRECTION_45::ANG_STRAIGHT | DIRECTION_45::ANG_HALF_FULL, DIRECTION_45( dirV ) );
682 }
683
684 m_snapOnTarget = false;
685 }
686
687 m_currentTrace = DIFF_PAIR();
688 m_currentTrace.SetGap( gap() );
689 m_currentTrace.SetLayer( m_currentLayer );
690
691 bool result = gwsEntry.FitGateways( gwsEntry, gwsTarget, m_startDiagonal, m_currentTrace );
692
693 if( result )
694 {
695 m_currentTrace.SetNets( m_netP, m_netN );
696 m_currentTrace.SetWidth( m_sizes.DiffPairWidth() );
697 m_currentTrace.SetGap( m_sizes.DiffPairGap() );
698
699 if( m_placingVia )
700 {
701 m_currentTrace.AppendVias ( makeVia( m_currentTrace.CP().CPoint( -1 ), m_netP ),
702 makeVia( m_currentTrace.CN().CPoint( -1 ), m_netN ) );
703 }
704
705 return true;
706 }
707
708 return false;
709 }
710
711
Move(const VECTOR2I & aP,ITEM * aEndItem)712 bool DIFF_PAIR_PLACER::Move( const VECTOR2I& aP , ITEM* aEndItem )
713 {
714 m_currentEndItem = aEndItem;
715 m_fitOk = false;
716
717 delete m_lastNode;
718 m_lastNode = NULL;
719
720 bool retval = route( aP );
721
722 NODE* latestNode = m_currentNode;
723 m_lastNode = latestNode->Branch();
724
725 assert( m_lastNode != NULL );
726 m_currentEnd = aP;
727
728 updateLeadingRatLine();
729
730 return retval;
731 }
732
733
UpdateSizes(const SIZES_SETTINGS & aSizes)734 void DIFF_PAIR_PLACER::UpdateSizes( const SIZES_SETTINGS& aSizes )
735 {
736 m_sizes = aSizes;
737
738 if( !m_idle )
739 {
740 initPlacement();
741 Move( m_currentEnd, NULL );
742 }
743 }
744
745
FixRoute(const VECTOR2I & aP,ITEM * aEndItem,bool aForceFinish)746 bool DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
747 {
748 if( !m_fitOk && !Settings().CanViolateDRC() )
749 return false;
750
751 if( m_currentTrace.CP().SegmentCount() < 1 ||
752 m_currentTrace.CN().SegmentCount() < 1 )
753 return false;
754
755 if( m_currentTrace.CP().SegmentCount() > 1 )
756 m_initialDiagonal = !DIRECTION_45( m_currentTrace.CP().CSegment( -2 ) ).IsDiagonal();
757
758 TOPOLOGY topo( m_lastNode );
759
760 if( !m_snapOnTarget && !m_currentTrace.EndsWithVias() && !aForceFinish )
761 {
762 SHAPE_LINE_CHAIN newP( m_currentTrace.CP() );
763 SHAPE_LINE_CHAIN newN( m_currentTrace.CN() );
764
765 if( newP.SegmentCount() > 1 && newN.SegmentCount() > 1 )
766 {
767 newP.Remove( -1, -1 );
768 newN.Remove( -1, -1 );
769 }
770
771 m_currentTrace.SetShape( newP, newN );
772 }
773
774 if( m_currentTrace.EndsWithVias() )
775 {
776 m_lastNode->Add( Clone( m_currentTrace.PLine().Via() ) );
777 m_lastNode->Add( Clone( m_currentTrace.NLine().Via() ) );
778 m_chainedPlacement = false;
779 }
780 else
781 {
782 m_chainedPlacement = !m_snapOnTarget && !aForceFinish;
783 }
784
785 LINE lineP( m_currentTrace.PLine() );
786 LINE lineN( m_currentTrace.NLine() );
787
788 m_lastNode->Add( lineP );
789 m_lastNode->Add( lineN );
790
791 topo.SimplifyLine( &lineP );
792 topo.SimplifyLine( &lineN );
793
794 m_prevPair = m_currentTrace.EndingPrimitives();
795
796 Router()->CommitRouting( m_lastNode );
797
798 m_lastNode = NULL;
799 m_placingVia = false;
800
801 if( m_snapOnTarget || aForceFinish )
802 {
803 m_idle = true;
804 return true;
805 }
806 else
807 {
808 initPlacement();
809 return false;
810 }
811 }
812
813
GetModifiedNets(std::vector<int> & aNets) const814 void DIFF_PAIR_PLACER::GetModifiedNets( std::vector<int> &aNets ) const
815 {
816 aNets.push_back( m_netP );
817 aNets.push_back( m_netN );
818 }
819
820
updateLeadingRatLine()821 void DIFF_PAIR_PLACER::updateLeadingRatLine()
822 {
823 SHAPE_LINE_CHAIN ratLineN, ratLineP;
824 TOPOLOGY topo( m_lastNode );
825
826 if( topo.LeadingRatLine( &m_currentTrace.PLine(), ratLineP ) )
827 {
828 Dbg()->AddLine( ratLineP, 1, 10000 );
829 }
830
831 if( topo.LeadingRatLine ( &m_currentTrace.NLine(), ratLineN ) )
832 {
833 Dbg()->AddLine( ratLineN, 3, 10000 );
834 }
835 }
836
837
CurrentNets() const838 const std::vector<int> DIFF_PAIR_PLACER::CurrentNets() const
839 {
840 std::vector<int> rv;
841 rv.push_back( m_netP );
842 rv.push_back( m_netN );
843 return rv;
844 }
845
846 }
847