KiCad PCB EDA Suite
pns_router.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-2021 KiCad Developers, see AUTHORS.txt for contributors.
6 * Author: Tomasz Wlostowski <[email protected]>
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 <cstdio>
23#include <memory>
24#include <vector>
25
26#include <view/view.h>
27#include <view/view_group.h>
29
31
32#include <pcb_painter.h>
33#include <pcbnew_settings.h>
34#include <pad.h>
35#include <zone.h>
36
37#include <geometry/shape.h>
38
39#include "pns_node.h"
40#include "pns_line_placer.h"
41#include "pns_line.h"
42#include "pns_solid.h"
43#include "pns_utils.h"
44#include "pns_router.h"
45#include "pns_shove.h"
46#include "pns_dragger.h"
48#include "pns_topology.h"
50#include "pns_meander_placer.h"
53
54namespace PNS {
55
56// an ugly singleton for drawing debug items within the router context.
57// To be fixed sometime in the future.
59
61{
62 theRouter = this;
63
64 m_state = IDLE;
66
67 m_logger = new LOGGER;
68
69 // Initialize all other variables:
70 m_lastNode = nullptr;
71 m_iterLimit = 0;
72 m_settings = nullptr;
73 m_iface = nullptr;
75}
76
77
79{
80 return theRouter;
81}
82
83
85{
86 ClearWorld();
87 theRouter = nullptr;
88 delete m_logger;
89}
90
91
93{
94 ClearWorld();
95
96 m_world = std::make_unique<NODE>( );
97 m_iface->SyncWorld( m_world.get() );
98 m_world->FixupVirtualVias();
99}
100
101
103{
104 if( m_world )
105 {
106 m_world->KillChildren();
107 m_world.reset();
108 }
109
110 m_placer.reset();
111}
112
113
115{
116 return m_state != IDLE;
117}
118
119
120const ITEM_SET ROUTER::QueryHoverItems( const VECTOR2I& aP, bool aUseClearance )
121{
122 if( m_state == IDLE || m_placer == nullptr )
123 {
124 if( aUseClearance )
125 {
126 SEGMENT test( SEG( aP, aP ), -1 );
127 test.SetWidth( 1 );
128 test.SetLayers( LAYER_RANGE::All() );
129 NODE::OBSTACLES obs;
130 m_world->QueryColliding( &test, obs, ITEM::ANY_T, -1, false );
131
132 PNS::ITEM_SET ret;
133
134 for( OBSTACLE& obstacle : obs )
135 ret.Add( obstacle.m_item, false );
136
137 return ret;
138 }
139 else
140 {
141 return m_world->HitTest( aP );
142 }
143 }
144 else
145 return m_placer->CurrentNode()->HitTest( aP );
146}
147
148
149bool ROUTER::StartDragging( const VECTOR2I& aP, ITEM* aItem, int aDragMode )
150{
151 return StartDragging( aP, ITEM_SET( aItem ), aDragMode );
152}
153
154
155bool ROUTER::StartDragging( const VECTOR2I& aP, ITEM_SET aStartItems, int aDragMode )
156{
157 if( aStartItems.Empty() )
158 return false;
159
160 if( Settings().Mode() == RM_MarkObstacles )
161 {
162 m_world->SetCollisionQueryScope( NODE::CQS_ALL_RULES );
163 }
164 else
165 {
166 m_world->SetCollisionQueryScope( NODE::CQS_IGNORE_HOLE_CLEARANCE );
167 }
168
170
171 if( aStartItems.Count( ITEM::SOLID_T ) == aStartItems.Size() )
172 {
173 m_dragger = std::make_unique<COMPONENT_DRAGGER>( this );
176 }
177 else
178 {
179 if( aDragMode & DM_FREE_ANGLE )
181 else
183
184 m_dragger = std::make_unique<DRAGGER>( this );
186 }
187
188 m_dragger->SetMode( aDragMode );
189 m_dragger->SetWorld( m_world.get() );
190 m_dragger->SetLogger( m_logger );
191 m_dragger->SetDebugDecorator( m_iface->GetDebugDecorator() );
192
193 if( m_logger )
194 m_logger->Clear();
195
196 if( m_logger && aStartItems.Size() )
197 {
198 m_logger->Log( LOGGER::EVT_START_DRAG, aP, aStartItems[0] );
199 }
200
201 if( m_dragger->Start( aP, aStartItems ) )
202 {
203 return true;
204 }
205 else
206 {
207 m_dragger.reset();
208 m_state = IDLE;
209 return false;
210 }
211}
212
213
214bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem, int aLayer )
215{
216 if( Settings().AllowDRCViolations() )
217 return true;
218
220 {
222 {
223 SetFailureReason( _( "Diff pair gap is less than board minimum clearance." ) );
224 return false;
225 }
226 }
227
228 ITEM_SET candidates = QueryHoverItems( aWhere );
229 wxString failureReason;
230
231 for( ITEM* item : candidates.Items() )
232 {
233 // Edge cuts are put on all layers, but they're not *really* on all layers
234 if( item->Parent() && item->Parent()->GetLayer() == Edge_Cuts )
235 continue;
236
237 if( !item->Layers().Overlaps( aLayer ) )
238 continue;
239
240 if( item->IsRoutable() )
241 {
242 failureReason = wxEmptyString;
243 break;
244 }
245 else
246 {
247 BOARD_ITEM* parent = item->Parent();
248
249 switch( parent->Type() )
250 {
251 case PCB_PAD_T:
252 {
253 PAD* pad = static_cast<PAD*>( parent );
254
255 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
256 failureReason = _( "Cannot start routing from a non-plated hole." );
257 }
258 break;
259
260 case PCB_ZONE_T:
261 case PCB_FP_ZONE_T:
262 {
263 ZONE* zone = static_cast<ZONE*>( parent );
264
265 if( !zone->GetZoneName().IsEmpty() )
266 {
267 failureReason = wxString::Format( _( "Rule area '%s' disallows tracks." ),
268 zone->GetZoneName() );
269 }
270 else
271 {
272 failureReason = _( "Rule area disallows tracks." );
273 }
274 }
275 break;
276
277 case PCB_TEXT_T:
278 case PCB_FP_TEXT_T:
279 case PCB_TEXTBOX_T:
280 case PCB_FP_TEXTBOX_T:
281 failureReason = _( "Cannot start routing from a text item." );
282 break;
283
284 case PCB_SHAPE_T:
285 case PCB_FP_SHAPE_T:
286 failureReason = _( "Cannot start routing from a graphic." );
287
288 default:
289 break;
290 }
291 }
292 }
293
294 if( !failureReason.IsEmpty() )
295 {
296 SetFailureReason( failureReason );
297 return false;
298 }
299
300 VECTOR2I startPoint = aWhere;
301
303 {
304 SHAPE_LINE_CHAIN dummyStartSeg;
305 LINE dummyStartLine;
306
307 dummyStartSeg.Append( startPoint );
308 dummyStartSeg.Append( startPoint, true );
309
310 dummyStartLine.SetShape( dummyStartSeg );
311 dummyStartLine.SetLayer( aLayer );
312 dummyStartLine.SetNet( aStartItem ? aStartItem->Net() : 0 );
313 dummyStartLine.SetWidth( m_sizes.TrackWidth() );
314
315 if( m_world->CheckColliding( &dummyStartLine, ITEM::ANY_T ) )
316 {
317 ITEM_SET dummyStartSet( &dummyStartLine );
318 NODE::ITEM_VECTOR highlightedItems;
319
320 markViolations( m_world.get(), dummyStartSet, highlightedItems );
321
322 for( ITEM* item : highlightedItems )
323 m_iface->HideItem( item );
324
325 SetFailureReason( _( "The routing start point violates DRC." ) );
326 return false;
327 }
328 }
329 else if( m_mode == PNS_MODE_ROUTE_DIFF_PAIR )
330 {
331 if( !aStartItem )
332 {
333 SetFailureReason( _( "Cannot start a differential pair in the middle of nowhere." ) );
334 return false;
335 }
336
337 DP_PRIMITIVE_PAIR dpPair;
338 wxString errorMsg;
339
340 if( !DIFF_PAIR_PLACER::FindDpPrimitivePair( m_world.get(), startPoint, aStartItem, dpPair,
341 &errorMsg ) )
342 {
343 SetFailureReason( errorMsg );
344 return false;
345 }
346
347 SHAPE_LINE_CHAIN dummyStartSegA;
348 SHAPE_LINE_CHAIN dummyStartSegB;
349 LINE dummyStartLineA;
350 LINE dummyStartLineB;
351
352 dummyStartSegA.Append( dpPair.AnchorN() );
353 dummyStartSegA.Append( dpPair.AnchorN(), true );
354
355 dummyStartSegB.Append( dpPair.AnchorP() );
356 dummyStartSegB.Append( dpPair.AnchorP(), true );
357
358 dummyStartLineA.SetShape( dummyStartSegA );
359 dummyStartLineA.SetLayer( aLayer );
360 dummyStartLineA.SetNet( dpPair.PrimN()->Net() );
361 dummyStartLineA.SetWidth( m_sizes.DiffPairWidth() );
362
363 dummyStartLineB.SetShape( dummyStartSegB );
364 dummyStartLineB.SetLayer( aLayer );
365 dummyStartLineB.SetNet( dpPair.PrimP()->Net() );
366 dummyStartLineB.SetWidth( m_sizes.DiffPairWidth() );
367
368 if( m_world->CheckColliding( &dummyStartLineA, ITEM::ANY_T )
369 || m_world->CheckColliding( &dummyStartLineB, ITEM::ANY_T ) )
370 {
371 ITEM_SET dummyStartSet;
372 NODE::ITEM_VECTOR highlightedItems;
373
374 dummyStartSet.Add( dummyStartLineA );
375 dummyStartSet.Add( dummyStartLineB );
376 markViolations( m_world.get(), dummyStartSet, highlightedItems );
377
378 for( ITEM* item : highlightedItems )
379 m_iface->HideItem( item );
380
381 SetFailureReason( _( "The routing start point violates DRC." ) );
382 return false;
383 }
384 }
385
386 return true;
387}
388
389
390bool ROUTER::StartRouting( const VECTOR2I& aP, ITEM* aStartItem, int aLayer )
391{
392 if( Settings().Mode() == RM_MarkObstacles )
393 {
394 m_world->SetCollisionQueryScope( NODE::CQS_ALL_RULES );
395 }
396 else
397 {
398 m_world->SetCollisionQueryScope( NODE::CQS_IGNORE_HOLE_CLEARANCE );
399 }
400
402
403 if( !isStartingPointRoutable( aP, aStartItem, aLayer ) )
404 return false;
405
407
408 switch( m_mode )
409 {
411 m_placer = std::make_unique<LINE_PLACER>( this );
412 break;
413
415 m_placer = std::make_unique<DIFF_PAIR_PLACER>( this );
416 break;
417
419 m_placer = std::make_unique<MEANDER_PLACER>( this );
420 break;
421
423 m_placer = std::make_unique<DP_MEANDER_PLACER>( this );
424 break;
425
427 m_placer = std::make_unique<MEANDER_SKEW_PLACER>( this );
428 break;
429
430 default:
431 return false;
432 }
433
434 m_placer->UpdateSizes( m_sizes );
435 m_placer->SetLayer( aLayer );
436 m_placer->SetDebugDecorator( m_iface->GetDebugDecorator() );
437 m_placer->SetLogger( m_logger );
438
439 if( m_placer->Start( aP, aStartItem ) )
440 {
442
443 if( m_logger )
444 {
445 m_logger->Clear();
446 m_logger->Log( LOGGER::EVT_START_ROUTE, aP, aStartItem, &m_sizes );
447 }
448
449 return true;
450 }
451 else
452 {
453 m_state = IDLE;
454 return false;
455 }
456}
457
458
459bool ROUTER::Move( const VECTOR2I& aP, ITEM* endItem )
460{
461 if( m_logger )
462 m_logger->Log( LOGGER::EVT_MOVE, aP, endItem );
463
464 switch( m_state )
465 {
466 case ROUTE_TRACK:
467 return movePlacing( aP, endItem );
468
469 case DRAG_SEGMENT:
470 case DRAG_COMPONENT:
471 return moveDragging( aP, endItem );
472
473 default:
474 break;
475 }
476
477 return false;
478}
479
480
481bool ROUTER::getNearestRatnestAnchor( VECTOR2I& aOtherEnd, LAYER_RANGE& aOtherEndLayers )
482{
483 // Can't finish something with no connections
484 if( GetCurrentNets().empty() )
485 return false;
486
487 PNS::LINE_PLACER* placer = dynamic_cast<PNS::LINE_PLACER*>( Placer() );
488
489 if( placer == nullptr )
490 return false;
491
492 PNS::LINE trace = placer->Trace();
493 PNS::NODE* lastNode = placer->CurrentNode( true );
494 PNS::TOPOLOGY topo( lastNode );
495
496 // If the user has drawn a line, get the anchor nearest to the line end
497 if( trace.SegmentCount() > 0 )
498 return topo.NearestUnconnectedAnchorPoint( &trace, aOtherEnd, aOtherEndLayers );
499
500 // Otherwise, find the closest anchor to our start point
501
502 // Get joint from placer start item
503 JOINT* jt = lastNode->FindJoint( placer->CurrentStart(), placer->CurrentLayer(),
504 placer->CurrentNets()[0] );
505
506 if( !jt )
507 return false;
508
509 // Get unconnected item from joint
510 int anchor;
511 PNS::ITEM* it = topo.NearestUnconnectedItem( jt, &anchor );
512
513 if( !it )
514 return false;
515
516 aOtherEnd = it->Anchor( anchor );
517 aOtherEndLayers = it->Layers();
518
519 return true;
520}
521
522
524{
525 if( m_state != ROUTE_TRACK )
526 return false;
527
528 LINE_PLACER* placer = dynamic_cast<LINE_PLACER*>( Placer() );
529
530 if( placer == nullptr )
531 return false;
532
533 // Get our current line and position and nearest ratsnest to them if it exists
534 PNS::LINE current = placer->Trace();
535 VECTOR2I currentEnd = placer->CurrentEnd();
536 VECTOR2I otherEnd;
537 LAYER_RANGE otherEndLayers;
538
539 // Get the anchor nearest to the end of the trace the user is routing
540 if( !getNearestRatnestAnchor( otherEnd, otherEndLayers ) )
541 return false;
542
543 // Keep moving until we don't change position or hit the limit
544 int triesLeft = 5;
545 VECTOR2I moveResultPoint;
546
547 do
548 {
549 moveResultPoint = Placer()->CurrentEnd();
550 Move( otherEnd, &current );
551 triesLeft--;
552 } while( Placer()->CurrentEnd() != moveResultPoint && triesLeft );
553
554 // If we've made it, fix the route and we're done
555 if( moveResultPoint == otherEnd && otherEndLayers.Overlaps( GetCurrentLayer() ) )
556 {
557 return FixRoute( otherEnd, &current, false );
558 }
559
560 return false;
561}
562
563
565{
566 LINE_PLACER* placer = dynamic_cast<LINE_PLACER*>( Placer() );
567
568 if( placer == nullptr )
569 return false;
570
571 LINE current = placer->Trace();
572 int currentLayer = GetCurrentLayer();
573 VECTOR2I currentEnd = placer->CurrentEnd();
574 VECTOR2I otherEnd;
575 LAYER_RANGE otherEndLayers;
576
577 // Get the anchor nearest to the end of the trace the user is routing
578 if( !getNearestRatnestAnchor( otherEnd, otherEndLayers ) )
579 return false;
580
582
583 // Commit whatever we've fixed and restart routing from the other end
584 int nextLayer = otherEndLayers.Overlaps( currentLayer ) ? currentLayer : otherEndLayers.Start();
585
586 if( !StartRouting( otherEnd, &current, nextLayer ) )
587 return false;
588
589 // Attempt to route to our current position
590 Move( currentEnd, &current );
591
592 return true;
593}
594
595
596bool ROUTER::moveDragging( const VECTOR2I& aP, ITEM* aEndItem )
597{
599
600 bool ret = m_dragger->Drag( aP );
601 ITEM_SET dragged = m_dragger->Traces();
602
603 updateView( m_dragger->CurrentNode(), dragged, true );
604 return ret;
605}
606
607
608void ROUTER::markViolations( NODE* aNode, ITEM_SET& aCurrent, NODE::ITEM_VECTOR& aRemoved )
609{
610 auto updateItem =
611 [&]( ITEM* currentItem, ITEM* itemToMark )
612 {
613 std::unique_ptr<ITEM> tmp( itemToMark->Clone() );
614
615 int clearance;
616 bool removeOriginal = true;
617 bool holeOnly = ( ( itemToMark->Marker() & MK_HOLE )
618 && !( itemToMark->Marker() & MK_VIOLATION ) );
619
620 if( holeOnly )
621 clearance = aNode->GetHoleClearance( currentItem, itemToMark );
622 else
623 clearance = aNode->GetClearance( currentItem, itemToMark );
624
625 if( itemToMark->Layers().IsMultilayer() && !currentItem->Layers().IsMultilayer() )
626 tmp->SetLayer( currentItem->Layer() );
627
628 if( itemToMark->Kind() == ITEM::SOLID_T )
629 {
630 if( holeOnly || !m_iface->IsFlashedOnLayer( itemToMark, currentItem->Layer() ) )
631 {
632 SOLID* solid = static_cast<SOLID*>( tmp.get() );
633
634 if( solid->Hole() )
635 {
636 solid->SetShape( solid->Hole()->Clone() );
637
638 // Leave the pad flashing around the highlighted hole
639 removeOriginal = false;
640 }
641 }
642
643 if( itemToMark->IsCompoundShapePrimitive() )
644 {
645 // We're only highlighting one (or more) of several primitives so we
646 // don't want all the other parts of the object to disappear
647 removeOriginal = false;
648 }
649 }
650
651 m_iface->DisplayItem( tmp.get(), clearance );
652
653 if( removeOriginal )
654 aRemoved.push_back( itemToMark );
655 };
656
657 for( ITEM* item : aCurrent.Items() )
658 {
659 NODE::OBSTACLES obstacles;
660
661 aNode->QueryColliding( item, obstacles, ITEM::ANY_T );
662
663 if( item->OfKind( ITEM::LINE_T ) )
664 {
665 LINE* l = static_cast<LINE*>( item );
666
667 if( l->EndsWithVia() )
668 {
669 VIA v( l->Via() );
670 aNode->QueryColliding( &v, obstacles, ITEM::ANY_T );
671 }
672 }
673
674 ITEM_SET draggedItems;
675
676 if( GetDragger() )
677 draggedItems = GetDragger()->Traces();
678
679 for( OBSTACLE& obs : obstacles )
680 {
681 // Don't mark items being dragged; only board items they collide with
682 if( draggedItems.Contains( obs.m_item ) )
683 continue;
684
685 obs.m_item->Mark( obs.m_item->Marker() | MK_VIOLATION );
686 updateItem( item, obs.m_item );
687 }
688
689 if( item->Kind() == ITEM::LINE_T )
690 {
691 LINE* line = static_cast<LINE*>( item );
692
693 // Show clearance on any blocking obstacles
694 if( line->GetBlockingObstacle() )
695 updateItem( item, line->GetBlockingObstacle() );
696 }
697 }
698}
699
700
701void ROUTER::updateView( NODE* aNode, ITEM_SET& aCurrent, bool aDragging )
702{
703 NODE::ITEM_VECTOR removed, added;
704 NODE::OBSTACLES obstacles;
705
706 if( !aNode )
707 return;
708
710 markViolations( aNode, aCurrent, removed );
711
712 aNode->GetUpdatedItems( removed, added );
713
714 for( ITEM* item : added )
715 {
717 int clearance = GetRuleResolver()->Clearance( item, nullptr );
718 m_iface->DisplayItem( item, clearance, aDragging );
719 }
720
721 for( ITEM* item : removed )
722 m_iface->HideItem( item );
723}
724
725
727{
728 m_sizes = aSizes;
729
730 // Change track/via size settings
731 if( m_state == ROUTE_TRACK )
732 {
733 m_placer->UpdateSizes( m_sizes );
734 }
735}
736
737
738bool ROUTER::movePlacing( const VECTOR2I& aP, ITEM* aEndItem )
739{
741
742 bool ret = m_placer->Move( aP, aEndItem );
743 ITEM_SET current = m_placer->Traces();
744
745 for( const ITEM* item : current.CItems() )
746 {
747 if( !item->OfKind( ITEM::LINE_T ) )
748 continue;
749
750 const LINE* l = static_cast<const LINE*>( item );
751 int clearance = GetRuleResolver()->Clearance( item, nullptr );
752
753 m_iface->DisplayItem( l, clearance );
754
755 if( l->EndsWithVia() )
756 {
757 const VIA& via = l->Via();
758 int viaClearance = GetRuleResolver()->Clearance( &via, nullptr );
759 int holeClearance = GetRuleResolver()->HoleClearance( &via, nullptr );
760
761 if( holeClearance + via.Drill() / 2 > viaClearance + via.Diameter() / 2 )
762 viaClearance = holeClearance + via.Drill() / 2 - via.Diameter() / 2;
763
764 m_iface->DisplayItem( &l->Via(), viaClearance );
765 }
766 }
767
768 //ITEM_SET tmp( &current );
769
770 updateView( m_placer->CurrentNode( true ), current );
771
772 return ret;
773}
774
775std::unique_ptr<NODE> ROUTER::GetUpdatedItems( std::vector<PNS::ITEM*>& aRemoved, std::vector<PNS::ITEM*>& aAdded )
776{
777 NODE *node;
778 ITEM_SET current;
779
780 if( m_state == ROUTE_TRACK )
781 {
782 node = m_placer->CurrentNode( true );
783 current = m_placer->Traces();
784 }
785 else if ( m_state == DRAG_SEGMENT )
786 {
787 node = m_dragger->CurrentNode();
788 current = m_dragger->Traces();
789 }
790
791 std::unique_ptr<NODE> tmpNode( node->Branch() );
792
793 for( auto item : current )
794 {
795 std::unique_ptr<ITEM> ip( item.item->Clone() );
796 tmpNode->Add( std::move( ip ) );
797 }
798
799 tmpNode->GetUpdatedItems( aRemoved, aAdded );
800
801 return std::move( tmpNode );
802}
803
805{
806 if( m_state == ROUTE_TRACK && !m_placer->HasPlacedAnything() )
807 return;
808
809 NODE::ITEM_VECTOR removed;
810 NODE::ITEM_VECTOR added;
811 NODE::ITEM_VECTOR changed;
812
813 aNode->GetUpdatedItems( removed, added );
814
815 for( ITEM* item : removed )
816 {
817 bool is_changed = false;
818
819 // Items in remove/add that share the same parent are just updated versions
820 // We move them to the updated vector to preserve attributes such as UUID and pad data
821 if( item->Parent() )
822 {
823 for( NODE::ITEM_VECTOR::iterator added_it = added.begin();
824 added_it != added.end(); ++added_it )
825 {
826 if( ( *added_it )->Parent() && ( *added_it )->Parent() == item->Parent() )
827 {
828 changed.push_back( *added_it );
829 added.erase( added_it );
830 is_changed = true;
831 break;
832 }
833 }
834 }
835
836 if( !is_changed && !item->IsVirtual() )
837 m_iface->RemoveItem( item );
838 }
839
840 for( ITEM* item : added )
841 {
842 if( !item->IsVirtual() )
843 {
844 m_iface->AddItem( item );
845 }
846 }
847
848 for( ITEM* item : changed )
849 {
850 if( !item->IsVirtual() )
851 {
852 m_iface->UpdateItem( item );
853 }
854 }
855
856 m_iface->Commit();
857 m_world->Commit( aNode );
858}
859
860
861bool ROUTER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
862{
863 bool rv = false;
864
865 if( m_logger )
866 m_logger->Log( LOGGER::EVT_FIX, aP, aEndItem );
867
868 switch( m_state )
869 {
870 case ROUTE_TRACK:
871 rv = m_placer->FixRoute( aP, aEndItem, aForceFinish );
872 break;
873
874 case DRAG_SEGMENT:
875 case DRAG_COMPONENT:
876 rv = m_dragger->FixRoute();
877 break;
878
879 default:
880 break;
881 }
882
883 return rv;
884}
885
886
888{
889 if( !RoutingInProgress() )
890 return;
891
893 m_placer->UnfixRoute();
894}
895
896
898{
899 if( m_state == ROUTE_TRACK )
900 m_placer->CommitPlacement();
901
902 StopRouting();
903}
904
905
907{
908 // Update the ratsnest with new changes
909
910 if( m_placer )
911 {
912 std::vector<int> nets;
913 m_placer->GetModifiedNets( nets );
914
915 // Update the ratsnest with new changes
916 for( int n : nets )
917 m_iface->UpdateNet( n );
918 }
919
920 if( !RoutingInProgress() )
921 return;
922
923 m_placer.reset();
924 m_dragger.reset();
925
927
928 m_state = IDLE;
929 m_world->KillChildren();
930 m_world->ClearRanks();
931}
932
933
935{
937}
938
939
941{
942 if( m_state == ROUTE_TRACK )
943 {
944 m_placer->FlipPosture();
945 }
946}
947
948
949bool ROUTER::SwitchLayer( int aLayer )
950{
951 if( m_state == ROUTE_TRACK )
952 return m_placer->SetLayer( aLayer );
953
954 return false;
955}
956
957
959{
960 if( m_state == ROUTE_TRACK )
961 {
962 bool toggle = !m_placer->IsPlacingVia();
963 m_placer->ToggleVia( toggle );
964
965 if( m_logger )
966 {
968 }
969 }
970}
971
972
973const std::vector<int> ROUTER::GetCurrentNets() const
974{
975 if( m_placer )
976 return m_placer->CurrentNets();
977 else if( m_dragger )
978 return m_dragger->CurrentNets();
979
980 return std::vector<int>();
981}
982
983
985{
986 if( m_placer )
987 return m_placer->CurrentLayer();
988 else if( m_dragger )
989 return m_dragger->CurrentLayer();
990
991 return -1;
992}
993
994
996{
997 return m_logger;
998}
999
1000
1002{
1003 if( !m_placer )
1004 return false;
1005
1006 return m_placer->IsPlacingVia();
1007}
1008
1009
1011{
1013
1014 switch( m_settings->GetCornerMode() )
1015 {
1016 case DIRECTION_45::CORNER_MODE::MITERED_45: mode = DIRECTION_45::CORNER_MODE::ROUNDED_45; break;
1017 case DIRECTION_45::CORNER_MODE::ROUNDED_45: mode = DIRECTION_45::CORNER_MODE::MITERED_90; break;
1018 case DIRECTION_45::CORNER_MODE::MITERED_90: mode = DIRECTION_45::CORNER_MODE::ROUNDED_90; break;
1019 case DIRECTION_45::CORNER_MODE::ROUNDED_90: mode = DIRECTION_45::CORNER_MODE::MITERED_45; break;
1020 }
1021
1022 m_settings->SetCornerMode( mode );
1023}
1024
1025
1026void ROUTER::SetOrthoMode( bool aEnable )
1027{
1028 if( !m_placer )
1029 return;
1030
1031 m_placer->SetOrthoMode( aEnable );
1032}
1033
1034
1036{
1037 m_mode = aMode;
1038}
1039
1040
1042{
1043 m_iface = aIface;
1044}
1045
1046void ROUTER::BreakSegment( ITEM *aItem, const VECTOR2I& aP )
1047{
1048 NODE *node = m_world->Branch();
1049
1050 LINE_PLACER placer( this );
1051
1052 if( placer.SplitAdjacentSegments( node, aItem, aP ) )
1053 {
1054 CommitRouting( node );
1055 }
1056 else
1057 {
1058 delete node;
1059 }
1060}
1061
1062}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
void SetMaximum()
Definition: box2.h:63
CORNER_MODE
Corner modes.
Definition: direction45.h:67
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:32
int Start() const
Definition: pns_layerset.h:82
bool IsMultilayer() const
Definition: pns_layerset.h:77
static LAYER_RANGE All()
Definition: pns_layerset.h:125
bool Overlaps(const LAYER_RANGE &aOther) const
Definition: pns_layerset.h:67
Definition: pad.h:59
static bool FindDpPrimitivePair(NODE *aWorld, const VECTOR2I &aP, ITEM *aItem, DP_PRIMITIVE_PAIR &aPair, wxString *aErrorMsg=nullptr)
Store starting/ending primitives (pads, vias or segments) for a differential pair.
const VECTOR2I & AnchorN() const
ITEM * PrimN() const
const VECTOR2I & AnchorP() const
ITEM * PrimP() const
virtual const ITEM_SET Traces()=0
Function Traces()
bool Empty() const
Definition: pns_itemset.h:130
int Size() const
Definition: pns_itemset.h:160
int Count(int aKindMask=-1) const
Definition: pns_itemset.h:114
void Add(const LINE &aLine)
Definition: pns_itemset.cpp:32
bool Contains(ITEM *aItem) const
Definition: pns_itemset.h:193
ENTRIES & Items()
Definition: pns_itemset.h:135
const ENTRIES & CItems() const
Definition: pns_itemset.h:136
Base class for PNS router board items.
Definition: pns_item.h:56
void SetNet(int aNet)
Definition: pns_item.h:153
virtual int Layer() const
Definition: pns_item.h:160
void SetLayer(int aLayer)
Definition: pns_item.h:159
@ SOLID_T
Definition: pns_item.h:63
@ LINE_T
Definition: pns_item.h:64
const LAYER_RANGE & Layers() const
Definition: pns_item.h:156
virtual VECTOR2I Anchor(int n) const
Definition: pns_item.h:219
int Net() const
Definition: pns_item.h:154
A 2D point on a given set of layers and belonging to a certain net, that links together a number of b...
Definition: pns_joint.h:43
Single track placement algorithm.
const LINE Trace() const
Return the complete routed line.
const std::vector< int > CurrentNets() const override
Return the net code of currently routed track.
NODE * CurrentNode(bool aLoopsRemoved=false) const override
Return the most recent world state.
bool SplitAdjacentSegments(NODE *aNode, ITEM *aSeg, const VECTOR2I &aP)
Check if point aP lies on segment aSeg.
int CurrentLayer() const override
Return the layer of currently routed track.
const VECTOR2I & CurrentEnd() const override
Return the current end of the line being placed.
const VECTOR2I & CurrentStart() const override
Return the current start of the line being placed.
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition: pns_line.h:61
ITEM * GetBlockingObstacle() const
Definition: pns_line.h:209
void SetShape(const SHAPE_LINE_CHAIN &aLine)
Return the shape of the line.
Definition: pns_line.h:126
const VIA & Via() const
Definition: pns_line.h:199
int SegmentCount() const
Definition: pns_line.h:144
void SetWidth(int aWidth)
Return line width.
Definition: pns_line.h:154
bool EndsWithVia() const
Definition: pns_line.h:194
void Clear()
Definition: pns_logger.cpp:40
@ EVT_START_ROUTE
Definition: pns_logger.h:47
@ EVT_START_DRAG
Definition: pns_logger.h:48
@ EVT_TOGGLE_VIA
Definition: pns_logger.h:52
void Log(EVENT_TYPE evt, const VECTOR2I &pos=VECTOR2I(), const ITEM *item=nullptr, const SIZES_SETTINGS *sizes=nullptr)
Definition: pns_logger.cpp:64
Keep the router "world" - i.e.
Definition: pns_node.h:156
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition: pns_node.cpp:139
std::vector< ITEM * > ITEM_VECTOR
Definition: pns_node.h:167
int GetClearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true) const
Definition: pns_node.cpp:103
@ CQS_IGNORE_HOLE_CLEARANCE
check everything except hole2hole / hole2copper
Definition: pns_node.h:163
@ CQS_ALL_RULES
check all rules
Definition: pns_node.h:162
void GetUpdatedItems(ITEM_VECTOR &aRemoved, ITEM_VECTOR &aAdded)
Return the list of items removed and added in this branch with respect to the root branch.
Definition: pns_node.cpp:1392
int QueryColliding(const ITEM *aItem, OBSTACLES &aObstacles, int aKindMask=ITEM::ANY_T, int aLimitCount=-1, bool aDifferentNetsOnly=true, int aOverrideClearance=-1)
Find items colliding (closer than clearance) with the item aItem.
Definition: pns_node.cpp:271
std::vector< OBSTACLE > OBSTACLES
Definition: pns_node.h:168
int GetHoleClearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true) const
Definition: pns_node.cpp:115
JOINT * FindJoint(const VECTOR2I &aPos, int aLayer, int aNet)
Search for a joint at a given position, layer and belonging to given net.
Definition: pns_node.cpp:1189
virtual const VECTOR2I & CurrentEnd() const =0
Function CurrentEnd()
virtual void RemoveItem(ITEM *aItem)=0
virtual void UpdateItem(ITEM *aItem)=0
virtual void UpdateNet(int aNetCode)=0
virtual DEBUG_DECORATOR * GetDebugDecorator()=0
virtual void HideItem(ITEM *aItem)=0
virtual void Commit()=0
virtual void AddItem(ITEM *aItem)=0
virtual void DisplayItem(const ITEM *aItem, int aClearance, bool aEdit=false)=0
virtual void EraseView()=0
virtual void SyncWorld(NODE *aNode)=0
virtual bool IsFlashedOnLayer(const PNS::ITEM *aItem, int aLayer) const =0
void updateView(NODE *aNode, ITEM_SET &aCurrent, bool aDragging=false)
Definition: pns_router.cpp:701
void SetMode(ROUTER_MODE aMode)
bool moveDragging(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:596
bool SwitchLayer(int layer)
Definition: pns_router.cpp:949
void StopRouting()
Definition: pns_router.cpp:906
void ClearViewDecorations()
Definition: pns_router.cpp:934
void ToggleCornerMode()
int m_iterLimit
Definition: pns_router.h:243
PLACEMENT_ALGO * Placer()
Definition: pns_router.h:209
NODE * m_lastNode
Definition: pns_router.h:235
void ClearWorld()
Definition: pns_router.cpp:102
void UpdateSizes(const SIZES_SETTINGS &aSizes)
Applies stored settings.
Definition: pns_router.cpp:726
void SetFailureReason(const wxString &aReason)
Definition: pns_router.h:206
bool getNearestRatnestAnchor(VECTOR2I &aOtherEnd, LAYER_RANGE &aOtherEndLayers)
Definition: pns_router.cpp:481
LOGGER * Logger()
Definition: pns_router.cpp:995
ROUTER_MODE Mode() const
Definition: pns_router.h:132
void UndoLastSegment()
Definition: pns_router.cpp:887
RouterState m_state
Definition: pns_router.h:232
const std::vector< int > GetCurrentNets() const
Definition: pns_router.cpp:973
void CommitRouting()
Definition: pns_router.cpp:897
bool m_forceMarkObstaclesMode
Definition: pns_router.h:244
std::unique_ptr< DRAG_ALGO > m_dragger
Definition: pns_router.h:238
void SetInterface(ROUTER_IFACE *aIface)
bool Finish()
Definition: pns_router.cpp:523
void markViolations(NODE *aNode, ITEM_SET &aCurrent, NODE::ITEM_VECTOR &aRemoved)
Definition: pns_router.cpp:608
void SyncWorld()
Definition: pns_router.cpp:92
bool ContinueFromEnd()
Definition: pns_router.cpp:564
std::unique_ptr< PLACEMENT_ALGO > m_placer
Definition: pns_router.h:237
bool isStartingPointRoutable(const VECTOR2I &aWhere, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:214
ROUTER_IFACE * m_iface
Definition: pns_router.h:241
bool IsPlacingVia() const
void FlipPosture()
Definition: pns_router.cpp:940
RULE_RESOLVER * GetRuleResolver() const
Definition: pns_router.h:173
SIZES_SETTINGS m_sizes
Definition: pns_router.h:247
std::unique_ptr< NODE > GetUpdatedItems(std::vector< PNS::ITEM * > &aRemoved, std::vector< PNS::ITEM * > &aAdded)
Definition: pns_router.cpp:775
const ITEM_SET QueryHoverItems(const VECTOR2I &aP, bool aUseClearance=false)
Definition: pns_router.cpp:120
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:185
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish=false)
Definition: pns_router.cpp:861
DRAG_ALGO * GetDragger()
Definition: pns_router.h:136
bool movePlacing(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:738
bool RoutingInProgress() const
Definition: pns_router.cpp:114
BOX2I m_visibleViewArea
Definition: pns_router.h:231
static ROUTER * GetInstance()
Definition: pns_router.cpp:78
LOGGER * m_logger
Definition: pns_router.h:249
void BreakSegment(ITEM *aItem, const VECTOR2I &aP)
void SetOrthoMode(bool aEnable)
bool StartDragging(const VECTOR2I &aP, ITEM *aItem, int aDragMode=DM_ANY)
Definition: pns_router.cpp:149
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:390
int GetCurrentLayer() const
Definition: pns_router.cpp:984
std::unique_ptr< NODE > m_world
Definition: pns_router.h:234
void ToggleViaPlacement()
Definition: pns_router.cpp:958
ROUTING_SETTINGS * m_settings
Definition: pns_router.h:246
ROUTER_MODE m_mode
Definition: pns_router.h:248
bool Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:459
void SetCornerMode(DIRECTION_45::CORNER_MODE aMode)
DIRECTION_45::CORNER_MODE GetCornerMode() const
virtual void ClearCacheForItem(const ITEM *aItem)
Definition: pns_node.h:105
virtual int Clearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true)=0
virtual void ClearCaches()
Definition: pns_node.h:106
virtual int HoleClearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true)=0
const SHAPE * Hole() const override
Definition: pns_solid.h:80
void SetShape(SHAPE *shape)
Definition: pns_solid.h:88
bool NearestUnconnectedAnchorPoint(const LINE *aTrack, VECTOR2I &aPoint, LAYER_RANGE &aLayers)
ITEM * NearestUnconnectedItem(JOINT *aStart, int *aAnchor=nullptr, int aKindMask=ITEM::ANY_T)
Definition: seg.h:42
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
virtual SHAPE * Clone() const
Return a dynamically allocated copy of the shape.
Definition: shape.h:145
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
wxString GetZoneName() const
Definition: zone.h:124
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
@ Edge_Cuts
Definition: layer_ids.h:113
Push and Shove diff pair dimensions (gap) settings dialog.
@ RM_MarkObstacles
Ignore collisions, mark obstacles.
static ROUTER * theRouter
Definition: pns_router.cpp:58
ROUTER_MODE
Definition: pns_router.h:62
@ PNS_MODE_ROUTE_SINGLE
Definition: pns_router.h:63
@ PNS_MODE_ROUTE_DIFF_PAIR
Definition: pns_router.h:64
@ PNS_MODE_TUNE_DIFF_PAIR
Definition: pns_router.h:66
@ PNS_MODE_TUNE_SINGLE
Definition: pns_router.h:65
@ PNS_MODE_TUNE_DIFF_PAIR_SKEW
Definition: pns_router.h:67
@ DM_FREE_ANGLE
Definition: pns_router.h:75
@ MK_VIOLATION
Definition: pns_item.h:42
@ MK_HOLE
Definition: pns_item.h:45
@ NPTH
like PAD_PTH, but not plated
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
Hold an object colliding with another object, along with some useful data about the collision.
Definition: pns_node.h:113
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
@ PCB_FP_TEXTBOX_T
class FP_TEXTBOX, wrapped text in a footprint
Definition: typeinfo.h:93
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:91
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:112
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:90
@ PCB_FP_ZONE_T
class ZONE, managed by a footprint
Definition: typeinfo.h:100
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_FP_TEXT_T
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618