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