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-2023 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 {
146 return m_placer->CurrentNode()->HitTest( aP );
147 }
148}
149
150
151bool ROUTER::StartDragging( const VECTOR2I& aP, ITEM* aItem, int aDragMode )
152{
153 return StartDragging( aP, ITEM_SET( aItem ), aDragMode );
154}
155
156
157bool ROUTER::StartDragging( const VECTOR2I& aP, ITEM_SET aStartItems, int aDragMode )
158{
159 if( aStartItems.Empty() )
160 return false;
161
162 if( Settings().Mode() == RM_MarkObstacles )
163 {
164 m_world->SetCollisionQueryScope( NODE::CQS_ALL_RULES );
165 }
166 else
167 {
168 m_world->SetCollisionQueryScope( NODE::CQS_IGNORE_HOLE_CLEARANCE );
169 }
170
172
173 if( aStartItems.Count( ITEM::SOLID_T ) == aStartItems.Size() )
174 {
175 m_dragger = std::make_unique<COMPONENT_DRAGGER>( this );
178 }
179 else
180 {
181 if( aDragMode & DM_FREE_ANGLE )
183 else
185
186 m_dragger = std::make_unique<DRAGGER>( this );
188 }
189
190 m_dragger->SetMode( static_cast<PNS::DRAG_MODE>( aDragMode ) );
191 m_dragger->SetWorld( m_world.get() );
192 m_dragger->SetLogger( m_logger );
193 m_dragger->SetDebugDecorator( m_iface->GetDebugDecorator() );
194
195 if( m_logger )
196 m_logger->Clear();
197
198 if( m_logger && aStartItems.Size() )
199 {
200 m_logger->Log( LOGGER::EVT_START_DRAG, aP, aStartItems[0] );
201 }
202
203 if( m_dragger->Start( aP, aStartItems ) )
204 {
205 return true;
206 }
207 else
208 {
209 m_dragger.reset();
210 m_state = IDLE;
211 return false;
212 }
213}
214
215
216bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem, int aLayer )
217{
218 if( Settings().AllowDRCViolations() )
219 return true;
220
222 {
224 {
225 SetFailureReason( _( "Diff pair gap is less than board minimum clearance." ) );
226 return false;
227 }
228 }
229
230 ITEM_SET candidates = QueryHoverItems( aWhere );
231 wxString failureReason;
232
233 for( ITEM* item : candidates.Items() )
234 {
235 // Edge cuts are put on all layers, but they're not *really* on all layers
236 if( item->Parent() && item->Parent()->GetLayer() == Edge_Cuts )
237 continue;
238
239 if( !item->Layers().Overlaps( aLayer ) )
240 continue;
241
242 if( item->IsRoutable() )
243 {
244 failureReason = wxEmptyString;
245 break;
246 }
247 else
248 {
249 BOARD_ITEM* parent = item->Parent();
250
251 switch( parent->Type() )
252 {
253 case PCB_PAD_T:
254 {
255 PAD* pad = static_cast<PAD*>( parent );
256
257 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
258 failureReason = _( "Cannot start routing from a non-plated hole." );
259 }
260 break;
261
262 case PCB_ZONE_T:
263 case PCB_FP_ZONE_T:
264 {
265 ZONE* zone = static_cast<ZONE*>( parent );
266
267 if( !zone->GetZoneName().IsEmpty() )
268 {
269 failureReason = wxString::Format( _( "Rule area '%s' disallows tracks." ),
270 zone->GetZoneName() );
271 }
272 else
273 {
274 failureReason = _( "Rule area disallows tracks." );
275 }
276 }
277 break;
278
279 case PCB_TEXT_T:
280 case PCB_FP_TEXT_T:
281 case PCB_TEXTBOX_T:
282 case PCB_FP_TEXTBOX_T:
283 failureReason = _( "Cannot start routing from a text item." );
284 break;
285
286 case PCB_SHAPE_T:
287 case PCB_FP_SHAPE_T:
288 failureReason = _( "Cannot start routing from a graphic." );
289
290 default:
291 break;
292 }
293 }
294 }
295
296 if( !failureReason.IsEmpty() )
297 {
298 SetFailureReason( failureReason );
299 return false;
300 }
301
302 VECTOR2I startPoint = aWhere;
303
305 {
306 SHAPE_LINE_CHAIN dummyStartSeg;
307 LINE dummyStartLine;
308
309 dummyStartSeg.Append( startPoint );
310 dummyStartSeg.Append( startPoint, true );
311
312 dummyStartLine.SetShape( dummyStartSeg );
313 dummyStartLine.SetLayer( aLayer );
314 dummyStartLine.SetNet( aStartItem ? aStartItem->Net() : 0 );
315 dummyStartLine.SetWidth( m_sizes.TrackWidth() );
316
317 if( m_world->CheckColliding( &dummyStartLine, ITEM::ANY_T ) )
318 {
319 ITEM_SET dummyStartSet( &dummyStartLine );
320 NODE::ITEM_VECTOR highlightedItems;
321
322 markViolations( m_world.get(), dummyStartSet, highlightedItems );
323
324 for( ITEM* item : highlightedItems )
325 m_iface->HideItem( item );
326
327 SetFailureReason( _( "The routing start point violates DRC." ) );
328 return false;
329 }
330 }
331 else if( m_mode == PNS_MODE_ROUTE_DIFF_PAIR )
332 {
333 if( !aStartItem )
334 {
335 SetFailureReason( _( "Cannot start a differential pair in the middle of nowhere." ) );
336 return false;
337 }
338
339 DP_PRIMITIVE_PAIR dpPair;
340 wxString errorMsg;
341
342 if( !DIFF_PAIR_PLACER::FindDpPrimitivePair( m_world.get(), startPoint, aStartItem, dpPair,
343 &errorMsg ) )
344 {
345 SetFailureReason( errorMsg );
346 return false;
347 }
348
349 SHAPE_LINE_CHAIN dummyStartSegA;
350 SHAPE_LINE_CHAIN dummyStartSegB;
351 LINE dummyStartLineA;
352 LINE dummyStartLineB;
353
354 dummyStartSegA.Append( dpPair.AnchorN() );
355 dummyStartSegA.Append( dpPair.AnchorN(), true );
356
357 dummyStartSegB.Append( dpPair.AnchorP() );
358 dummyStartSegB.Append( dpPair.AnchorP(), true );
359
360 dummyStartLineA.SetShape( dummyStartSegA );
361 dummyStartLineA.SetLayer( aLayer );
362 dummyStartLineA.SetNet( dpPair.PrimN()->Net() );
363 dummyStartLineA.SetWidth( m_sizes.DiffPairWidth() );
364
365 dummyStartLineB.SetShape( dummyStartSegB );
366 dummyStartLineB.SetLayer( aLayer );
367 dummyStartLineB.SetNet( dpPair.PrimP()->Net() );
368 dummyStartLineB.SetWidth( m_sizes.DiffPairWidth() );
369
370 if( m_world->CheckColliding( &dummyStartLineA, ITEM::ANY_T )
371 || m_world->CheckColliding( &dummyStartLineB, ITEM::ANY_T ) )
372 {
373 ITEM_SET dummyStartSet;
374 NODE::ITEM_VECTOR highlightedItems;
375
376 dummyStartSet.Add( dummyStartLineA );
377 dummyStartSet.Add( dummyStartLineB );
378 markViolations( m_world.get(), dummyStartSet, highlightedItems );
379
380 for( ITEM* item : highlightedItems )
381 m_iface->HideItem( item );
382
383 SetFailureReason( _( "The routing start point violates DRC." ) );
384 return false;
385 }
386 }
387
388 return true;
389}
390
391
392bool ROUTER::StartRouting( const VECTOR2I& aP, ITEM* aStartItem, int aLayer )
393{
394 if( Settings().Mode() == RM_MarkObstacles )
395 {
396 m_world->SetCollisionQueryScope( NODE::CQS_ALL_RULES );
397 }
398 else
399 {
400 m_world->SetCollisionQueryScope( NODE::CQS_IGNORE_HOLE_CLEARANCE );
401 }
402
404
405 if( !isStartingPointRoutable( aP, aStartItem, aLayer ) )
406 return false;
407
409
410 switch( m_mode )
411 {
413 m_placer = std::make_unique<LINE_PLACER>( this );
414 break;
415
417 m_placer = std::make_unique<DIFF_PAIR_PLACER>( this );
418 break;
419
421 m_placer = std::make_unique<MEANDER_PLACER>( this );
422 break;
423
425 m_placer = std::make_unique<DP_MEANDER_PLACER>( this );
426 break;
427
429 m_placer = std::make_unique<MEANDER_SKEW_PLACER>( this );
430 break;
431
432 default:
433 return false;
434 }
435
436 m_placer->UpdateSizes( m_sizes );
437 m_placer->SetLayer( aLayer );
438 m_placer->SetDebugDecorator( m_iface->GetDebugDecorator() );
439 m_placer->SetLogger( m_logger );
440
441 if( m_placer->Start( aP, aStartItem ) )
442 {
444
445 if( m_logger )
446 {
447 m_logger->Clear();
448 m_logger->Log( LOGGER::EVT_START_ROUTE, aP, aStartItem, &m_sizes );
449 }
450
451 return true;
452 }
453 else
454 {
455 m_state = IDLE;
456 return false;
457 }
458}
459
460
461bool ROUTER::Move( const VECTOR2I& aP, ITEM* endItem )
462{
463 if( m_logger )
464 m_logger->Log( LOGGER::EVT_MOVE, aP, endItem );
465
466 switch( m_state )
467 {
468 case ROUTE_TRACK:
469 return movePlacing( aP, endItem );
470
471 case DRAG_SEGMENT:
472 case DRAG_COMPONENT:
473 return moveDragging( aP, endItem );
474
475 default:
476 break;
477 }
478
479 return false;
480}
481
482
483bool ROUTER::getNearestRatnestAnchor( VECTOR2I& aOtherEnd, LAYER_RANGE& aOtherEndLayers )
484{
485 // Can't finish something with no connections
486 if( GetCurrentNets().empty() )
487 return false;
488
489 PNS::LINE_PLACER* placer = dynamic_cast<PNS::LINE_PLACER*>( Placer() );
490
491 if( placer == nullptr )
492 return false;
493
494 PNS::LINE trace = placer->Trace();
495 PNS::NODE* lastNode = placer->CurrentNode( true );
496 PNS::TOPOLOGY topo( lastNode );
497
498 // If the user has drawn a line, get the anchor nearest to the line end
499 if( trace.SegmentCount() > 0 )
500 return topo.NearestUnconnectedAnchorPoint( &trace, aOtherEnd, aOtherEndLayers );
501
502 // Otherwise, find the closest anchor to our start point
503
504 // Get joint from placer start item
505 JOINT* jt = lastNode->FindJoint( placer->CurrentStart(), placer->CurrentLayer(),
506 placer->CurrentNets()[0] );
507
508 if( !jt )
509 return false;
510
511 // Get unconnected item from joint
512 int anchor;
513 PNS::ITEM* it = topo.NearestUnconnectedItem( jt, &anchor );
514
515 if( !it )
516 return false;
517
518 aOtherEnd = it->Anchor( anchor );
519 aOtherEndLayers = it->Layers();
520
521 return true;
522}
523
524
526{
527 if( m_state != ROUTE_TRACK )
528 return false;
529
530 LINE_PLACER* placer = dynamic_cast<LINE_PLACER*>( Placer() );
531
532 if( placer == nullptr )
533 return false;
534
535 // Get our current line and position and nearest ratsnest to them if it exists
536 PNS::LINE current = placer->Trace();
537 VECTOR2I currentEnd = placer->CurrentEnd();
538 VECTOR2I otherEnd;
539 LAYER_RANGE otherEndLayers;
540
541 // Get the anchor nearest to the end of the trace the user is routing
542 if( !getNearestRatnestAnchor( otherEnd, otherEndLayers ) )
543 return false;
544
545 // Keep moving until we don't change position or hit the limit
546 int triesLeft = 5;
547 VECTOR2I moveResultPoint;
548
549 do
550 {
551 moveResultPoint = Placer()->CurrentEnd();
552 Move( otherEnd, &current );
553 triesLeft--;
554 } while( Placer()->CurrentEnd() != moveResultPoint && triesLeft );
555
556 // If we've made it, fix the route and we're done
557 if( moveResultPoint == otherEnd && otherEndLayers.Overlaps( GetCurrentLayer() ) )
558 {
559 return FixRoute( otherEnd, &current, false );
560 }
561
562 return false;
563}
564
565
567{
568 LINE_PLACER* placer = dynamic_cast<LINE_PLACER*>( Placer() );
569
570 if( placer == nullptr )
571 return false;
572
573 LINE current = placer->Trace();
574 int currentLayer = GetCurrentLayer();
575 VECTOR2I currentEnd = placer->CurrentEnd();
576 VECTOR2I otherEnd;
577 LAYER_RANGE otherEndLayers;
578
579 // Get the anchor nearest to the end of the trace the user is routing
580 if( !getNearestRatnestAnchor( otherEnd, otherEndLayers ) )
581 return false;
582
584
585 // Commit whatever we've fixed and restart routing from the other end
586 int nextLayer = otherEndLayers.Overlaps( currentLayer ) ? currentLayer : otherEndLayers.Start();
587
588 if( !StartRouting( otherEnd, &current, nextLayer ) )
589 return false;
590
591 // Attempt to route to our current position
592 Move( currentEnd, &current );
593
594 return true;
595}
596
597
598bool ROUTER::moveDragging( const VECTOR2I& aP, ITEM* aEndItem )
599{
601
602 bool ret = m_dragger->Drag( aP );
603 ITEM_SET dragged = m_dragger->Traces();
604
605 updateView( m_dragger->CurrentNode(), dragged, true );
606 return ret;
607}
608
609
610void ROUTER::markViolations( NODE* aNode, ITEM_SET& aCurrent, NODE::ITEM_VECTOR& aRemoved )
611{
612 auto updateItem =
613 [&]( ITEM* currentItem, ITEM* itemToMark )
614 {
615 std::unique_ptr<ITEM> tmp( itemToMark->Clone() );
616
617 int clearance;
618 bool removeOriginal = true;
619 bool holeOnly = ( ( itemToMark->Marker() & MK_HOLE )
620 && !( itemToMark->Marker() & MK_VIOLATION ) );
621
622 if( holeOnly )
623 clearance = aNode->GetHoleClearance( currentItem, itemToMark );
624 else
625 clearance = aNode->GetClearance( currentItem, itemToMark );
626
627 if( itemToMark->Layers().IsMultilayer() && !currentItem->Layers().IsMultilayer() )
628 tmp->SetLayer( currentItem->Layer() );
629
630 if( itemToMark->Kind() == ITEM::SOLID_T )
631 {
632 if( holeOnly || !m_iface->IsFlashedOnLayer( itemToMark, currentItem->Layer() ) )
633 {
634 SOLID* solid = static_cast<SOLID*>( tmp.get() );
635
636 if( solid->Hole() )
637 {
638 solid->SetShape( solid->Hole()->Clone() );
639
640 // Leave the pad flashing around the highlighted hole
641 removeOriginal = false;
642 }
643 }
644
645 if( itemToMark->IsCompoundShapePrimitive() )
646 {
647 // We're only highlighting one (or more) of several primitives so we
648 // don't want all the other parts of the object to disappear
649 removeOriginal = false;
650 }
651 }
652
653 m_iface->DisplayItem( tmp.get(), clearance );
654
655 if( removeOriginal )
656 aRemoved.push_back( itemToMark );
657 };
658
659 for( ITEM* item : aCurrent.Items() )
660 {
661 NODE::OBSTACLES obstacles;
662
663 aNode->QueryColliding( item, obstacles, ITEM::ANY_T );
664
665 if( item->OfKind( ITEM::LINE_T ) )
666 {
667 LINE* l = static_cast<LINE*>( item );
668
669 if( l->EndsWithVia() )
670 {
671 VIA v( l->Via() );
672 aNode->QueryColliding( &v, obstacles, ITEM::ANY_T );
673 }
674 }
675
676 ITEM_SET draggedItems;
677
678 if( GetDragger() )
679 draggedItems = GetDragger()->Traces();
680
681 for( OBSTACLE& obs : obstacles )
682 {
683 // Don't mark items being dragged; only board items they collide with
684 if( draggedItems.Contains( obs.m_item ) )
685 continue;
686
687 obs.m_item->Mark( obs.m_item->Marker() | MK_VIOLATION );
688 updateItem( item, obs.m_item );
689 }
690
691 if( item->Kind() == ITEM::LINE_T )
692 {
693 LINE* line = static_cast<LINE*>( item );
694
695 // Show clearance on any blocking obstacles
696 if( line->GetBlockingObstacle() )
697 updateItem( item, line->GetBlockingObstacle() );
698 }
699 }
700}
701
702
703void ROUTER::updateView( NODE* aNode, ITEM_SET& aCurrent, bool aDragging )
704{
705 NODE::ITEM_VECTOR removed, added;
706 NODE::OBSTACLES obstacles;
707
708 if( !aNode )
709 return;
710
712 markViolations( aNode, aCurrent, removed );
713
714 aNode->GetUpdatedItems( removed, added );
715
716 for( ITEM* item : added )
717 {
719 int clearance = GetRuleResolver()->Clearance( item, nullptr );
720 m_iface->DisplayItem( item, clearance, aDragging );
721 }
722
723 for( ITEM* item : removed )
724 m_iface->HideItem( item );
725}
726
727
729{
730 m_sizes = aSizes;
731
732 // Change track/via size settings
733 if( m_state == ROUTE_TRACK )
734 {
735 m_placer->UpdateSizes( m_sizes );
736 }
737}
738
739
740bool ROUTER::movePlacing( const VECTOR2I& aP, ITEM* aEndItem )
741{
743
744 bool ret = m_placer->Move( aP, aEndItem );
745 ITEM_SET current = m_placer->Traces();
746
747 for( const ITEM* item : current.CItems() )
748 {
749 if( !item->OfKind( ITEM::LINE_T ) )
750 continue;
751
752 const LINE* l = static_cast<const LINE*>( item );
753 int clearance = GetRuleResolver()->Clearance( item, nullptr );
754
755 m_iface->DisplayItem( l, clearance, false, true );
756
757 if( l->EndsWithVia() )
758 {
759 const VIA& via = l->Via();
760 int viaClearance = GetRuleResolver()->Clearance( &via, nullptr );
761 int holeClearance = GetRuleResolver()->HoleClearance( &via, nullptr );
762
763 if( holeClearance + via.Drill() / 2 > viaClearance + via.Diameter() / 2 )
764 viaClearance = holeClearance + via.Drill() / 2 - via.Diameter() / 2;
765
766 m_iface->DisplayItem( &l->Via(), viaClearance, false, true );
767 }
768 }
769
770 //ITEM_SET tmp( &current );
771
772 updateView( m_placer->CurrentNode( true ), current );
773
774 return ret;
775}
776
777
778void ROUTER::GetUpdatedItems( std::vector<PNS::ITEM*>& aRemoved, std::vector<PNS::ITEM*>& aAdded,
779 std::vector<PNS::ITEM*>& aHeads )
780{
781 NODE *node = nullptr;
782 ITEM_SET current;
783
784 if( m_state == ROUTE_TRACK )
785 {
786 node = m_placer->CurrentNode( true );
787 current = m_placer->Traces();
788 }
789 else if ( m_state == DRAG_SEGMENT )
790 {
791 node = m_dragger->CurrentNode();
792 current = m_dragger->Traces();
793 }
794
795 // There probably should be a debugging assertion and possibly a PNS_LOGGER call here but
796 // I'm not sure how to be proceed WLS.
797 if( !node )
798 return;
799
800 node->GetUpdatedItems( aRemoved, aAdded );
801
802 for( auto item : current.CItems() )
803 {
804 aHeads.push_back( item.item->Clone() );
805 }
806}
807
808
810{
811 if( m_state == ROUTE_TRACK && !m_placer->HasPlacedAnything() )
812 return;
813
814 NODE::ITEM_VECTOR removed;
815 NODE::ITEM_VECTOR added;
816 NODE::ITEM_VECTOR changed;
817
818 aNode->GetUpdatedItems( removed, added );
819
820 for( ITEM* item : removed )
821 {
822 bool is_changed = false;
823
824 // Items in remove/add that share the same parent are just updated versions
825 // We move them to the updated vector to preserve attributes such as UUID and pad data
826 if( item->Parent() )
827 {
828 for( NODE::ITEM_VECTOR::iterator added_it = added.begin();
829 added_it != added.end(); ++added_it )
830 {
831 if( ( *added_it )->Parent() && ( *added_it )->Parent() == item->Parent() )
832 {
833 changed.push_back( *added_it );
834 added.erase( added_it );
835 is_changed = true;
836 break;
837 }
838 }
839 }
840
841 if( !is_changed && !item->IsVirtual() )
842 m_iface->RemoveItem( item );
843 }
844
845 for( ITEM* item : added )
846 {
847 if( !item->IsVirtual() )
848 {
849 m_iface->AddItem( item );
850 }
851 }
852
853 for( ITEM* item : changed )
854 {
855 if( !item->IsVirtual() )
856 {
857 m_iface->UpdateItem( item );
858 }
859 }
860
861 m_iface->Commit();
862 m_world->Commit( aNode );
863}
864
865
866bool ROUTER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish )
867{
868 bool rv = false;
869
870 if( m_logger )
871 m_logger->Log( LOGGER::EVT_FIX, aP, aEndItem );
872
873 switch( m_state )
874 {
875 case ROUTE_TRACK:
876 rv = m_placer->FixRoute( aP, aEndItem, aForceFinish );
877 break;
878
879 case DRAG_SEGMENT:
880 case DRAG_COMPONENT:
881 rv = m_dragger->FixRoute();
882 break;
883
884 default:
885 break;
886 }
887
888 return rv;
889}
890
891
893{
894 if( !RoutingInProgress() )
895 return;
896
898 m_placer->UnfixRoute();
899}
900
901
903{
904 if( m_state == ROUTE_TRACK )
905 m_placer->CommitPlacement();
906
907 StopRouting();
908}
909
910
912{
913 // Update the ratsnest with new changes
914
915 if( m_placer )
916 {
917 std::vector<int> nets;
918 m_placer->GetModifiedNets( nets );
919
920 // Update the ratsnest with new changes
921 for( int n : nets )
922 m_iface->UpdateNet( n );
923 }
924
925 if( !RoutingInProgress() )
926 return;
927
928 m_placer.reset();
929 m_dragger.reset();
930
932
933 m_state = IDLE;
934 m_world->KillChildren();
935 m_world->ClearRanks();
936}
937
938
940{
942}
943
944
946{
947 if( m_state == ROUTE_TRACK )
948 {
949 m_placer->FlipPosture();
950 }
951}
952
953
954bool ROUTER::SwitchLayer( int aLayer )
955{
956 if( m_state == ROUTE_TRACK )
957 return m_placer->SetLayer( aLayer );
958
959 return false;
960}
961
962
964{
965 if( m_state == ROUTE_TRACK )
966 {
967 bool toggle = !m_placer->IsPlacingVia();
968 m_placer->ToggleVia( toggle );
969
970 if( m_logger )
971 {
973 }
974 }
975}
976
977
978const std::vector<int> ROUTER::GetCurrentNets() const
979{
980 if( m_placer )
981 return m_placer->CurrentNets();
982 else if( m_dragger )
983 return m_dragger->CurrentNets();
984
985 return std::vector<int>();
986}
987
988
990{
991 if( m_placer )
992 return m_placer->CurrentLayer();
993 else if( m_dragger )
994 return m_dragger->CurrentLayer();
995
996 return -1;
997}
998
999
1001{
1002 return m_logger;
1003}
1004
1005
1007{
1008 if( !m_placer )
1009 return false;
1010
1011 return m_placer->IsPlacingVia();
1012}
1013
1014
1016{
1018
1019 switch( m_settings->GetCornerMode() )
1020 {
1021 case DIRECTION_45::CORNER_MODE::MITERED_45: mode = DIRECTION_45::CORNER_MODE::ROUNDED_45; break;
1022 case DIRECTION_45::CORNER_MODE::ROUNDED_45: mode = DIRECTION_45::CORNER_MODE::MITERED_90; break;
1023 case DIRECTION_45::CORNER_MODE::MITERED_90: mode = DIRECTION_45::CORNER_MODE::ROUNDED_90; break;
1024 case DIRECTION_45::CORNER_MODE::ROUNDED_90: mode = DIRECTION_45::CORNER_MODE::MITERED_45; break;
1025 }
1026
1027 m_settings->SetCornerMode( mode );
1028}
1029
1030
1031void ROUTER::SetOrthoMode( bool aEnable )
1032{
1033 if( !m_placer )
1034 return;
1035
1036 m_placer->SetOrthoMode( aEnable );
1037}
1038
1039
1041{
1042 m_mode = aMode;
1043}
1044
1045
1047{
1048 m_iface = aIface;
1049}
1050
1051void ROUTER::BreakSegment( ITEM *aItem, const VECTOR2I& aP )
1052{
1053 NODE *node = m_world->Branch();
1054
1055 LINE_PLACER placer( this );
1056
1057 if( placer.SplitAdjacentSegments( node, aItem, aP ) )
1058 {
1059 CommitRouting( node );
1060 }
1061 else
1062 {
1063 delete node;
1064 }
1065}
1066
1067}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:70
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:60
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
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:1403
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:272
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:1201
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 EraseView()=0
virtual void SyncWorld(NODE *aNode)=0
virtual void DisplayItem(const ITEM *aItem, int aClearance, bool aEdit=false, bool aIsHeadTrace=false)=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:703
void SetMode(ROUTER_MODE aMode)
bool moveDragging(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:598
bool SwitchLayer(int layer)
Definition: pns_router.cpp:954
void StopRouting()
Definition: pns_router.cpp:911
void ClearViewDecorations()
Definition: pns_router.cpp:939
void ToggleCornerMode()
int m_iterLimit
Definition: pns_router.h:247
PLACEMENT_ALGO * Placer()
Definition: pns_router.h:213
NODE * m_lastNode
Definition: pns_router.h:239
void ClearWorld()
Definition: pns_router.cpp:102
void UpdateSizes(const SIZES_SETTINGS &aSizes)
Applies stored settings.
Definition: pns_router.cpp:728
void SetFailureReason(const wxString &aReason)
Definition: pns_router.h:210
bool getNearestRatnestAnchor(VECTOR2I &aOtherEnd, LAYER_RANGE &aOtherEndLayers)
Definition: pns_router.cpp:483
LOGGER * Logger()
ROUTER_MODE Mode() const
Definition: pns_router.h:133
void UndoLastSegment()
Definition: pns_router.cpp:892
RouterState m_state
Definition: pns_router.h:236
const std::vector< int > GetCurrentNets() const
Definition: pns_router.cpp:978
void CommitRouting()
Definition: pns_router.cpp:902
bool m_forceMarkObstaclesMode
Definition: pns_router.h:248
std::unique_ptr< DRAG_ALGO > m_dragger
Definition: pns_router.h:242
void SetInterface(ROUTER_IFACE *aIface)
bool Finish()
Definition: pns_router.cpp:525
void markViolations(NODE *aNode, ITEM_SET &aCurrent, NODE::ITEM_VECTOR &aRemoved)
Definition: pns_router.cpp:610
void SyncWorld()
Definition: pns_router.cpp:92
bool ContinueFromEnd()
Definition: pns_router.cpp:566
std::unique_ptr< PLACEMENT_ALGO > m_placer
Definition: pns_router.h:241
bool isStartingPointRoutable(const VECTOR2I &aWhere, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:216
ROUTER_IFACE * m_iface
Definition: pns_router.h:245
bool IsPlacingVia() const
void FlipPosture()
Definition: pns_router.cpp:945
RULE_RESOLVER * GetRuleResolver() const
Definition: pns_router.h:177
SIZES_SETTINGS m_sizes
Definition: pns_router.h:251
const ITEM_SET QueryHoverItems(const VECTOR2I &aP, bool aUseClearance=false)
Definition: pns_router.cpp:120
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:189
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish=false)
Definition: pns_router.cpp:866
DRAG_ALGO * GetDragger()
Definition: pns_router.h:137
bool movePlacing(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:740
bool RoutingInProgress() const
Definition: pns_router.cpp:114
BOX2I m_visibleViewArea
Definition: pns_router.h:235
static ROUTER * GetInstance()
Definition: pns_router.cpp:78
LOGGER * m_logger
Definition: pns_router.h:253
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:151
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:392
int GetCurrentLayer() const
Definition: pns_router.cpp:989
void GetUpdatedItems(std::vector< PNS::ITEM * > &aRemoved, std::vector< PNS::ITEM * > &aAdded, std::vector< PNS::ITEM * > &aHeads)
Definition: pns_router.cpp:778
std::unique_ptr< NODE > m_world
Definition: pns_router.h:238
void ToggleViaPlacement()
Definition: pns_router.cpp:963
ROUTING_SETTINGS * m_settings
Definition: pns_router.h:250
ROUTER_MODE m_mode
Definition: pns_router.h:252
bool Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:461
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:146
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
DRAG_MODE
Definition: pns_router.h:71
@ 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:590