KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2024 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
27
28#include <advanced_config.h>
30
31#include <pcb_painter.h>
32#include <pad.h>
33#include <zone.h>
34
35#include <geometry/shape.h>
36
37#include "pns_node.h"
38#include "pns_line_placer.h"
39#include "pns_line.h"
40#include "pns_solid.h"
41#include "pns_utils.h"
42#include "pns_router.h"
43#include "pns_shove.h"
44#include "pns_dragger.h"
45#include "pns_multi_dragger.h"
47#include "pns_topology.h"
49#include "pns_meander_placer.h"
52#include "router_preview_item.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 = nullptr;
68
69 if( ADVANCED_CFG::GetCfg().m_EnableRouterDump )
70 m_logger = new LOGGER;
71
72 // Initialize all other variables:
73 m_lastNode = nullptr;
74 m_iterLimit = 0;
75 m_settings = nullptr;
76 m_iface = nullptr;
78}
79
80
82{
83 return theRouter;
84}
85
86
88{
89 ClearWorld();
90 theRouter = nullptr;
91 delete m_logger;
92}
93
94
96{
97 ClearWorld();
98
99 m_world = std::make_unique<NODE>( );
100 m_iface->SyncWorld( m_world.get() );
101 m_world->FixupVirtualVias();
102}
103
104
106{
107 if( m_world )
108 {
109 m_world->SetRuleResolver( nullptr );
110 m_world->KillChildren();
111 m_world.reset();
112 }
113
114 m_placer.reset();
115}
116
117
119{
120 return m_state != IDLE;
121}
122
123
124const ITEM_SET ROUTER::QueryHoverItems( const VECTOR2I& aP, int aSlopRadius )
125{
126 NODE* node = m_placer ? m_placer->CurrentNode() : m_world.get();
127 PNS::ITEM_SET ret;
128
129 wxCHECK( node, ret );
130
131 if( aSlopRadius > 0 )
132 {
133 NODE::OBSTACLES obs;
134 SEGMENT test( SEG( aP, aP ), nullptr );
136
137 test.SetWidth( 1 );
138 test.SetLayers( PNS_LAYER_RANGE::All() );
139
140 opts.m_differentNetsOnly = false;
141 opts.m_overrideClearance = aSlopRadius;
142
143 node->QueryColliding( &test, obs, opts );
144
145 for( const OBSTACLE& obstacle : obs )
146 ret.Add( obstacle.m_item, false );
147
148 return ret;
149 }
150 else
151 {
152 return node->HitTest( aP );
153 }
154}
155
156
157bool ROUTER::StartDragging( const VECTOR2I& aP, ITEM* aItem, int aDragMode )
158{
159 m_leaderSegments.clear();
160 return StartDragging( aP, ITEM_SET( aItem ), aDragMode );
161}
162
163
164bool ROUTER::StartDragging( const VECTOR2I& aP, ITEM_SET aStartItems, int aDragMode )
165{
166 m_leaderSegments.clear();
167
168 if( aStartItems.Empty() )
169 return false;
170
172
173 if( aStartItems.Count( ITEM::SOLID_T ) == aStartItems.Size() )
174 {
175 m_dragger = std::make_unique<COMPONENT_DRAGGER>( this );
177 }
178 // more than 1 track segment or arc to drag? launch the multisegment dragger
179 else if( aStartItems.Count( ITEM::SEGMENT_T | ITEM::ARC_T ) > 1 )
180 {
181 m_dragger = std::make_unique<MULTI_DRAGGER>( this );
183 }
184 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 )
199 {
200 if( aStartItems.Size() == 1 )
201 m_logger->Log( LOGGER::EVT_START_DRAG, aP, aStartItems[0] );
202 else if( aStartItems.Size() > 1 )
203 m_logger->LogM( LOGGER::EVT_START_MULTIDRAG, aP, aStartItems.Items() ); // fixme default args
204 }
205
206 if( m_dragger->Start( aP, aStartItems ) )
207 {
208 return true;
209 }
210 else
211 {
212 m_dragger.reset();
213 m_state = IDLE;
214 return false;
215 }
216}
217
218
219bool ROUTER::isStartingPointRoutable( const VECTOR2I& aWhere, ITEM* aStartItem, int aLayer )
220{
221 if( Settings().AllowDRCViolations() )
222 return true;
223
225 {
227 {
228 SetFailureReason( _( "Diff pair gap is less than board minimum clearance." ) );
229 return false;
230 }
231 }
232
233 ITEM_SET candidates = QueryHoverItems( aWhere );
234 wxString failureReason;
235
236 for( ITEM* item : candidates.Items() )
237 {
238 // Edge cuts are put on all layers, but they're not *really* on all layers
239 if( item->BoardItem() && item->BoardItem()->GetLayer() == Edge_Cuts )
240 continue;
241
242 if( !item->Layers().Overlaps( aLayer ) )
243 continue;
244
245 if( item->IsRoutable() )
246 {
247 failureReason = wxEmptyString;
248 break;
249 }
250 else
251 {
252 BOARD_ITEM* parent = item->BoardItem();
253
254 switch( parent->Type() )
255 {
256 case PCB_PAD_T:
257 {
258 PAD* pad = static_cast<PAD*>( parent );
259
260 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
261 failureReason = _( "Cannot start routing from a non-plated hole." );
262 }
263 break;
264
265 case PCB_ZONE_T:
266 {
267 ZONE* zone = static_cast<ZONE*>( parent );
268
269 if( !zone->HasKeepoutParametersSet() )
270 break;
271
272 if( !zone->GetZoneName().IsEmpty() )
273 {
274 failureReason = wxString::Format( _( "Rule area '%s' disallows tracks." ),
275 zone->GetZoneName() );
276 }
277 else
278 {
279 failureReason = _( "Rule area disallows tracks." );
280 }
281 }
282 break;
283
284 case PCB_FIELD_T:
285 case PCB_TEXT_T:
286 case PCB_TEXTBOX_T:
287 failureReason = _( "Cannot start routing from a text item." );
288 break;
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 // If the only reason we collide is track width; it's better to allow the user to start
320 // anyway and just highlight the resulting collisions, so they can change width later.
321 dummyStartLine.SetWidth( m_sizes.BoardMinTrackWidth() );
322
323 if( m_world->CheckColliding( &dummyStartLine, ITEM::ANY_T ) )
324 {
325 ITEM_SET dummyStartSet( &dummyStartLine );
326 NODE::ITEM_VECTOR highlightedItems;
327
328 markViolations( m_world.get(), dummyStartSet, highlightedItems );
329
330 for( ITEM* item : highlightedItems )
331 m_iface->HideItem( item );
332
333 SetFailureReason( _( "The routing start point violates DRC." ) );
334 return false;
335 }
336 }
337 }
338 else if( m_mode == PNS_MODE_ROUTE_DIFF_PAIR )
339 {
340 if( !aStartItem )
341 {
342 SetFailureReason( _( "Cannot start a differential pair in the middle of nowhere." ) );
343 return false;
344 }
345
346 DP_PRIMITIVE_PAIR dpPair;
347 wxString errorMsg;
348
349 if( !DIFF_PAIR_PLACER::FindDpPrimitivePair( m_world.get(), startPoint, aStartItem, dpPair,
350 &errorMsg ) )
351 {
352 SetFailureReason( errorMsg );
353 return false;
354 }
355
356 SHAPE_LINE_CHAIN dummyStartSegA;
357 SHAPE_LINE_CHAIN dummyStartSegB;
358 LINE dummyStartLineA;
359 LINE dummyStartLineB;
360
361 dummyStartSegA.Append( dpPair.AnchorN() );
362 dummyStartSegA.Append( dpPair.AnchorN(), true );
363
364 dummyStartSegB.Append( dpPair.AnchorP() );
365 dummyStartSegB.Append( dpPair.AnchorP(), true );
366
367 dummyStartLineA.SetShape( dummyStartSegA );
368 dummyStartLineA.SetLayer( aLayer );
369 dummyStartLineA.SetNet( dpPair.PrimN()->Net() );
370 dummyStartLineA.SetWidth( m_sizes.DiffPairWidth() );
371
372 dummyStartLineB.SetShape( dummyStartSegB );
373 dummyStartLineB.SetLayer( aLayer );
374 dummyStartLineB.SetNet( dpPair.PrimP()->Net() );
375 dummyStartLineB.SetWidth( m_sizes.DiffPairWidth() );
376
377 if( m_world->CheckColliding( &dummyStartLineA, ITEM::ANY_T )
378 || m_world->CheckColliding( &dummyStartLineB, ITEM::ANY_T ) )
379 {
380 // If the only reason we collide is track width; it's better to allow the user to start
381 // anyway and just highlight the resulting collisions, so they can change width later.
382 dummyStartLineA.SetWidth( m_sizes.BoardMinTrackWidth() );
383 dummyStartLineB.SetWidth( m_sizes.BoardMinTrackWidth() );
384
385 if( m_world->CheckColliding( &dummyStartLineA, ITEM::ANY_T )
386 || m_world->CheckColliding( &dummyStartLineB, ITEM::ANY_T ) )
387 {
388 ITEM_SET dummyStartSet;
389 NODE::ITEM_VECTOR highlightedItems;
390
391 dummyStartSet.Add( dummyStartLineA );
392 dummyStartSet.Add( dummyStartLineB );
393 markViolations( m_world.get(), dummyStartSet, highlightedItems );
394
395 for( ITEM* item : highlightedItems )
396 m_iface->HideItem( item );
397
398 SetFailureReason( _( "The routing start point violates DRC." ) );
399 return false;
400 }
401 }
402 }
403
404 return true;
405}
406
407
408bool ROUTER::StartRouting( const VECTOR2I& aP, ITEM* aStartItem, int aLayer )
409{
411
412 if( !isStartingPointRoutable( aP, aStartItem, aLayer ) )
413 return false;
414
415 switch( m_mode )
416 {
418 m_placer = std::make_unique<LINE_PLACER>( this );
419 break;
420
422 m_placer = std::make_unique<DIFF_PAIR_PLACER>( this );
423 break;
424
426 m_placer = std::make_unique<MEANDER_PLACER>( this );
427 break;
428
430 m_placer = std::make_unique<DP_MEANDER_PLACER>( this );
431 break;
432
434 m_placer = std::make_unique<MEANDER_SKEW_PLACER>( this );
435 break;
436
437 default:
438 return false;
439 }
440
441 m_placer->UpdateSizes( m_sizes );
442 m_placer->SetLayer( aLayer );
443 m_placer->SetDebugDecorator( m_iface->GetDebugDecorator() );
444 m_placer->SetLogger( m_logger );
445
446 if( m_placer->Start( aP, aStartItem ) )
447 {
449
450 if( m_logger )
451 {
452 m_logger->Clear();
453 m_logger->Log( LOGGER::EVT_START_ROUTE, aP, aStartItem, &m_sizes, m_placer->CurrentLayer() );
454 }
455
456 return true;
457 }
458 else
459 {
460 m_state = IDLE;
461 m_placer.reset();
462
463 return false;
464 }
465}
466
467
468bool ROUTER::Move( const VECTOR2I& aP, ITEM* endItem )
469{
470 if( m_logger )
471 m_logger->Log( LOGGER::EVT_MOVE, aP, endItem );
472
473 switch( m_state )
474 {
475 case ROUTE_TRACK:
476 return movePlacing( aP, endItem );
477
478 case DRAG_SEGMENT:
479 case DRAG_COMPONENT:
480 return moveDragging( aP, endItem );
481
482 default:
483 break;
484 }
485
487
488 return false;
489}
490
491
493 ITEM*& aOtherEndItem )
494{
495 // Can't finish something with no connections
496 if( GetCurrentNets().empty() )
497 return false;
498
499 PLACEMENT_ALGO* placer = Placer();
500
501 if( placer == nullptr || placer->Traces().Size() == 0 )
502 return false;
503
504 LINE* trace = dynamic_cast<LINE*>( placer->Traces()[0] );
505
506 if( trace == nullptr )
507 return false;
508
509 PNS::NODE* lastNode = placer->CurrentNode( true );
510 PNS::TOPOLOGY topo( lastNode );
511
512 // If the user has drawn a line, get the anchor nearest to the line end
513 if( trace->SegmentCount() > 0 )
514 {
515 return topo.NearestUnconnectedAnchorPoint( trace, aOtherEnd, aOtherEndLayers,
516 aOtherEndItem );
517 }
518
519 // Otherwise, find the closest anchor to our start point
520
521 // Get joint from placer start item
522 const JOINT* jt = lastNode->FindJoint( placer->CurrentStart(), placer->CurrentLayer(),
523 placer->CurrentNets()[0] );
524
525 if( !jt )
526 return false;
527
528 // Get unconnected item from joint
529 int anchor;
530 PNS::ITEM* it = topo.NearestUnconnectedItem( jt, &anchor );
531
532 if( !it )
533 return false;
534
535 aOtherEnd = it->Anchor( anchor );
536 aOtherEndLayers = it->Layers();
537 aOtherEndItem = it;
538
539 return true;
540}
541
542
544{
545 if( m_state != ROUTE_TRACK )
546 return false;
547
548 PLACEMENT_ALGO* placer = Placer();
549
550 if( placer == nullptr || placer->Traces().Size() == 0 )
551 return false;
552
553 LINE* current = dynamic_cast<LINE*>( placer->Traces()[0] );
554
555 if( current == nullptr )
556 return false;
557
558 // Get our current line and position and nearest ratsnest to them if it exists
559 VECTOR2I otherEnd;
560 PNS_LAYER_RANGE otherEndLayers;
561 ITEM* otherEndItem = nullptr;
562
563 // Get the anchor nearest to the end of the trace the user is routing
564 if( !getNearestRatnestAnchor( otherEnd, otherEndLayers, otherEndItem ) )
565 return false;
566
567 // Keep moving until we don't change position or hit the limit
568 int triesLeft = 5;
569 VECTOR2I moveResultPoint;
570
571 do
572 {
573 moveResultPoint = placer->CurrentEnd();
574 Move( otherEnd, otherEndItem );
575 triesLeft--;
576 } while( placer->CurrentEnd() != moveResultPoint && triesLeft );
577
578 // If we've made it, fix the route and we're done
579 if( moveResultPoint == otherEnd && otherEndLayers.Overlaps( GetCurrentLayer() ) )
580 {
581 bool forceFinish = false;
582 bool allowViolations = false;
583
584 return FixRoute( otherEnd, otherEndItem, forceFinish, allowViolations );
585 }
586
587 return false;
588}
589
590
591bool ROUTER::ContinueFromEnd( ITEM** aNewStartItem )
592{
593 PLACEMENT_ALGO* placer = Placer();
594
595 if( placer == nullptr || placer->Traces().Size() == 0 )
596 return false;
597
598 LINE* current = dynamic_cast<LINE*>( placer->Traces()[0] );
599
600 if( current == nullptr )
601 return false;
602
603 int currentLayer = GetCurrentLayer();
604 VECTOR2I currentEnd = placer->CurrentEnd();
605 VECTOR2I otherEnd;
606 PNS_LAYER_RANGE otherEndLayers;
607 ITEM* otherEndItem = nullptr;
608
609 // Get the anchor nearest to the end of the trace the user is routing
610 if( !getNearestRatnestAnchor( otherEnd, otherEndLayers, otherEndItem ) )
611 return false;
612
614
615 // Commit whatever we've fixed and restart routing from the other end
616 int nextLayer = otherEndLayers.Overlaps( currentLayer ) ? currentLayer : otherEndLayers.Start();
617
618 if( !StartRouting( otherEnd, otherEndItem, nextLayer ) )
619 return false;
620
621 // Attempt to route to our current position
622 Move( currentEnd, nullptr );
623
624 *aNewStartItem = otherEndItem;
625
626 return true;
627}
628
629
630bool ROUTER::moveDragging( const VECTOR2I& aP, ITEM* aEndItem )
631{
633
634 bool ret = m_dragger->Drag( aP );
635 ITEM_SET dragged = m_dragger->Traces();
636
637 m_leaderSegments = m_dragger->GetLastCommittedLeaderSegments();
638
639 updateView( m_dragger->CurrentNode(), dragged, true );
640 return ret;
641}
642
643
644void ROUTER::markViolations( NODE* aNode, ITEM_SET& aCurrent, NODE::ITEM_VECTOR& aRemoved )
645{
646 auto updateItem =
647 [&]( ITEM* currentItem, ITEM* itemToMark )
648 {
649 std::unique_ptr<ITEM> tmp( itemToMark->Clone() );
650
651 int clearance;
652 bool removeOriginal = true;
653
654 clearance = aNode->GetClearance( currentItem, itemToMark );
655
656 if( itemToMark->Layers().IsMultilayer() && !currentItem->Layers().IsMultilayer() )
657 tmp->SetLayer( currentItem->Layer() );
658
659 if( itemToMark->IsCompoundShapePrimitive() )
660 {
661 // We're only highlighting one (or more) of several primitives so we don't
662 // want all the other parts of the object to disappear
663 removeOriginal = false;
664 }
665
666 m_iface->DisplayItem( tmp.get(), clearance );
667
668 if( removeOriginal )
669 aRemoved.push_back( itemToMark );
670 };
671
672 for( ITEM* item : aCurrent.Items() )
673 {
674 NODE::OBSTACLES obstacles;
675
676 aNode->QueryColliding( item, obstacles );
677
678 if( item->OfKind( ITEM::LINE_T ) )
679 {
680 LINE* l = static_cast<LINE*>( item );
681
682 if( l->EndsWithVia() )
683 {
684 VIA v( l->Via() );
685 aNode->QueryColliding( &v, obstacles );
686 }
687 }
688
689 ITEM_SET draggedItems;
690
691 if( GetDragger() )
692 draggedItems = GetDragger()->Traces();
693
694 for( const OBSTACLE& obs : obstacles )
695 {
696 // Don't mark items being dragged; only board items they collide with
697 if( draggedItems.Contains( obs.m_item ) )
698 continue;
699
700 obs.m_item->Mark( obs.m_item->Marker() | MK_VIOLATION );
701 updateItem( item, obs.m_item );
702 }
703
704 if( item->Kind() == ITEM::LINE_T )
705 {
706 LINE* line = static_cast<LINE*>( item );
707
708 // Show clearance on any blocking obstacles
709 if( line->GetBlockingObstacle() )
710 updateItem( item, line->GetBlockingObstacle() );
711 }
712 }
713}
714
715
716void ROUTER::updateView( NODE* aNode, ITEM_SET& aCurrent, bool aDragging )
717{
718 NODE::ITEM_VECTOR removed, added;
719 NODE::OBSTACLES obstacles;
720
721 if( !aNode )
722 return;
723
724 markViolations( aNode, aCurrent, removed );
725
726 aNode->GetUpdatedItems( removed, added );
727
728 std::vector<const PNS::ITEM*> cacheCheckItems( added.begin(), added.end() );
729 GetRuleResolver()->ClearCacheForItems( cacheCheckItems );
730
731 for( ITEM* item : added )
732 {
733 int clearance = GetRuleResolver()->Clearance( item, nullptr );
734 m_iface->DisplayItem( item, clearance, aDragging );
735 }
736
737 for( ITEM* item : removed )
738 m_iface->HideItem( item );
739}
740
741
743{
744 m_sizes = aSizes;
745
746 // Change track/via size settings
747 if( m_state == ROUTE_TRACK )
748 m_placer->UpdateSizes( m_sizes );
749}
750
751
752bool ROUTER::movePlacing( const VECTOR2I& aP, ITEM* aEndItem )
753{
755
756 bool ret = m_placer->Move( aP, aEndItem );
757 ITEM_SET current = m_placer->Traces();
758
759 for( const ITEM* item : current.CItems() )
760 {
761 if( !item->OfKind( ITEM::LINE_T ) )
762 continue;
763
764 const LINE* l = static_cast<const LINE*>( item );
765 int clearance = GetRuleResolver()->Clearance( item, nullptr );
766
767 m_iface->DisplayItem( l, clearance, false, PNS_HEAD_TRACE );
768
769 if( l->EndsWithVia() )
770 {
771 const VIA& via = l->Via();
772 clearance = GetRuleResolver()->Clearance( &via, nullptr );
773
774 if( via.HasHole() )
775 {
776 int holeClearance = GetRuleResolver()->Clearance( via.Hole(), nullptr );
777 int annularWidth = std::max( 0, via.Diameter( l->Layer() ) - via.Drill() ) / 2;
778 int excessHoleClearance = holeClearance - annularWidth;
779
780 if( excessHoleClearance > clearance )
781 clearance = excessHoleClearance;
782 }
783
784 m_iface->DisplayItem( &l->Via(), clearance, false, PNS_HEAD_TRACE );
785 }
786 }
787
788 //ITEM_SET tmp( &current );
789
790 updateView( m_placer->CurrentNode( true ), current );
791
792 return ret;
793}
794
795
796void ROUTER::GetUpdatedItems( std::vector<PNS::ITEM*>& aRemoved, std::vector<PNS::ITEM*>& aAdded,
797 std::vector<PNS::ITEM*>& aHeads )
798{
799 NODE *node = nullptr;
800 ITEM_SET current;
801
802 if( m_state == ROUTE_TRACK )
803 {
804 node = m_placer->CurrentNode( true );
805 current = m_placer->Traces();
806 }
807 else if ( m_state == DRAG_SEGMENT )
808 {
809 node = m_dragger->CurrentNode();
810 current = m_dragger->Traces();
811 }
812
813 // There probably should be a debugging assertion and possibly a PNS_LOGGER call here but
814 // I'm not sure how to be proceed WLS.
815 if( !node )
816 return;
817
818 node->GetUpdatedItems( aRemoved, aAdded );
819
820 for( const ITEM* item : current.CItems() )
821 aHeads.push_back( item->Clone() );
822}
823
824
826{
827 if( m_state == ROUTE_TRACK && !m_placer->HasPlacedAnything() )
828 return;
829
830 NODE::ITEM_VECTOR removed;
831 NODE::ITEM_VECTOR added;
832 NODE::ITEM_VECTOR changed;
833
834 aNode->GetUpdatedItems( removed, added );
835
836 for( ITEM* item : removed )
837 {
838 bool is_changed = false;
839
840 // Items in remove/add that share the same parent are just updated versions
841 // We move them to the updated vector to preserve attributes such as UUID and pad data
842 if( item->Parent() )
843 {
844 for( NODE::ITEM_VECTOR::iterator added_it = added.begin();
845 added_it != added.end(); ++added_it )
846 {
847 if( ( *added_it )->Parent() && ( *added_it )->Parent() == item->Parent() )
848 {
849 changed.push_back( *added_it );
850 added.erase( added_it );
851 is_changed = true;
852 break;
853 }
854 }
855 }
856
857 if( !is_changed && !item->IsVirtual() )
858 m_iface->RemoveItem( item );
859 }
860
861 for( ITEM* item : added )
862 {
863 if( !item->IsVirtual() )
864 m_iface->AddItem( item );
865 }
866
867 for( ITEM* item : changed )
868 {
869 if( !item->IsVirtual() )
870 m_iface->UpdateItem( item );
871 }
872
873 m_iface->Commit();
874 m_world->Commit( aNode );
875}
876
877
878bool ROUTER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinish, bool aForceCommit )
879{
880 bool rv = false;
881
882 if( m_logger )
883 m_logger->Log( LOGGER::EVT_FIX, aP, aEndItem );
884
885 switch( m_state )
886 {
887 case ROUTE_TRACK:
888 rv = m_placer->FixRoute( aP, aEndItem, aForceFinish );
889 break;
890
891 case DRAG_SEGMENT:
892 case DRAG_COMPONENT:
893 rv = m_dragger->FixRoute( aForceCommit );
894 break;
895
896 default:
897 break;
898 }
899
900 return rv;
901}
902
904{
905 return m_leaderSegments;
906};
907
908
909std::optional<VECTOR2I> ROUTER::UndoLastSegment()
910{
911 if( !RoutingInProgress() )
912 return std::nullopt;
913
914 if( m_logger )
916
917 return m_placer->UnfixRoute();
918}
919
920
922{
923 if( m_state == ROUTE_TRACK )
924 m_placer->CommitPlacement();
925
926 StopRouting();
927}
928
929
931{
932 // Update the ratsnest with new changes
933
934 if( m_placer )
935 {
936 std::vector<NET_HANDLE> nets;
937 m_placer->GetModifiedNets( nets );
938
939 // Update the ratsnest with new changes
940 for( NET_HANDLE n : nets )
941 m_iface->UpdateNet( n );
942 }
943
944 if( !RoutingInProgress() )
945 return;
946
947 m_placer.reset();
948 m_dragger.reset();
949
951
952 m_state = IDLE;
953 m_world->KillChildren();
954 m_world->ClearRanks();
955}
956
957
959{
961}
962
963
965{
966 if( m_state == ROUTE_TRACK )
967 {
968 m_placer->FlipPosture();
969 }
970}
971
972
973bool ROUTER::SwitchLayer( int aLayer )
974{
975 if( m_state == ROUTE_TRACK )
976 return m_placer->SetLayer( aLayer );
977
978 return false;
979}
980
981
983{
984 if( m_state == ROUTE_TRACK )
985 {
986 bool toggle = !m_placer->IsPlacingVia();
987 m_placer->ToggleVia( toggle );
988
989 if( m_logger )
991 }
992}
993
994
995const std::vector<NET_HANDLE> ROUTER::GetCurrentNets() const
996{
997 if( m_placer )
998 return m_placer->CurrentNets();
999 else if( m_dragger )
1000 return m_dragger->CurrentNets();
1001
1002 return std::vector<NET_HANDLE>();
1003}
1004
1005
1007{
1008 if( m_placer )
1009 return m_placer->CurrentLayer();
1010 else if( m_dragger )
1011 return m_dragger->CurrentLayer();
1012
1013 return -1;
1014}
1015
1016
1018{
1019 return m_logger;
1020}
1021
1022
1024{
1025 if( !m_placer )
1026 return false;
1027
1028 return m_placer->IsPlacingVia();
1029}
1030
1031
1033{
1035
1036 switch( m_settings->GetCornerMode() )
1037 {
1042 }
1043
1044 m_settings->SetCornerMode( mode );
1045}
1046
1047
1048void ROUTER::SetOrthoMode( bool aEnable )
1049{
1050 if( !m_placer )
1051 return;
1052
1053 m_placer->SetOrthoMode( aEnable );
1054}
1055
1056
1058{
1059 m_mode = aMode;
1060}
1061
1062
1064{
1065 m_iface = aIface;
1066}
1067
1068
1069void ROUTER::BreakSegmentOrArc( ITEM *aItem, const VECTOR2I& aP )
1070{
1071 NODE *node = m_world->Branch();
1072
1073 LINE_PLACER placer( this );
1074
1075 bool ret = false;
1076
1077 if( aItem->OfKind( ITEM::SEGMENT_T ) )
1078 ret = placer.SplitAdjacentSegments( node, aItem, aP );
1079 else if( aItem->OfKind( ITEM::ARC_T ) )
1080 ret = placer.SplitAdjacentArcs( node, aItem, aP );
1081
1082 if( ret )
1083 {
1084 CommitRouting( node );
1085 }
1086 else
1087 {
1088 delete node;
1089 }
1090}
1091
1092}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
constexpr void SetMaximum()
Definition: box2.h:80
CORNER_MODE
Corner modes.
Definition: direction45.h:67
@ ROUNDED_90
H/V with filleted corners.
Definition: direction45.h:71
@ MITERED_90
H/V only (90-degree corners)
Definition: direction45.h:70
@ ROUNDED_45
H/V/45 with filleted corners.
Definition: direction45.h:69
@ MITERED_45
H/V/45 with mitered corners (default)
Definition: direction45.h:68
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
Definition: pad.h:54
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:82
int Size() const
Definition: pns_itemset.h:112
int Count(int aKindMask=-1) const
Definition: pns_itemset.h:66
void Add(const LINE &aLine)
Definition: pns_itemset.cpp:33
bool Contains(ITEM *aItem) const
Definition: pns_itemset.h:151
std::vector< ITEM * > & Items()
Definition: pns_itemset.h:87
const std::vector< ITEM * > & CItems() const
Definition: pns_itemset.h:88
Base class for PNS router board items.
Definition: pns_item.h:97
const PNS_LAYER_RANGE & Layers() const
Definition: pns_item.h:199
virtual NET_HANDLE Net() const
Definition: pns_item.h:197
void SetNet(NET_HANDLE aNet)
Definition: pns_item.h:196
virtual int Layer() const
Definition: pns_item.h:203
void SetLayer(int aLayer)
Definition: pns_item.h:202
@ SEGMENT_T
Definition: pns_item.h:106
bool OfKind(int aKindMask) const
Definition: pns_item.h:178
virtual VECTOR2I Anchor(int n) const
Definition: pns_item.h:255
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.
bool SplitAdjacentArcs(NODE *aNode, ITEM *aArc, const VECTOR2I &aP)
Snaps the point aP to arc aArc.
bool SplitAdjacentSegments(NODE *aNode, ITEM *aSeg, const VECTOR2I &aP)
Snaps the point aP to segment aSeg.
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition: pns_line.h:62
ITEM * GetBlockingObstacle() const
Definition: pns_line.h:217
void SetShape(const SHAPE_LINE_CHAIN &aLine)
Return the shape of the line.
Definition: pns_line.h:127
VIA & Via()
Definition: pns_line.h:198
int SegmentCount() const
Definition: pns_line.h:140
void SetWidth(int aWidth)
Return line width.
Definition: pns_line.h:150
bool EndsWithVia() const
Definition: pns_line.h:190
void Log(EVENT_TYPE evt, const VECTOR2I &pos=VECTOR2I(), const ITEM *item=nullptr, const SIZES_SETTINGS *sizes=nullptr, int aLayer=0)
Definition: pns_logger.cpp:70
void LogM(EVENT_TYPE evt, const VECTOR2I &pos=VECTOR2I(), std::vector< ITEM * > items={}, const SIZES_SETTINGS *sizes=nullptr, int aLayer=0)
Definition: pns_logger.cpp:46
void Clear()
Definition: pns_logger.cpp:40
@ EVT_START_ROUTE
Definition: pns_logger.h:47
@ EVT_START_MULTIDRAG
Definition: pns_logger.h:54
@ EVT_START_DRAG
Definition: pns_logger.h:48
@ EVT_TOGGLE_VIA
Definition: pns_logger.h:52
Keep the router "world" - i.e.
Definition: pns_node.h:231
std::vector< ITEM * > ITEM_VECTOR
Definition: pns_node.h:242
int GetClearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true) const
Return the pre-set worst case clearance between any pair of items.
Definition: pns_node.cpp:129
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:1443
const JOINT * FindJoint(const VECTOR2I &aPos, int aLayer, NET_HANDLE aNet) const
Search for a joint at a given position, layer and belonging to given net.
Definition: pns_node.cpp:1242
std::set< OBSTACLE > OBSTACLES
Definition: pns_node.h:243
int QueryColliding(const ITEM *aItem, OBSTACLES &aObstacles, const COLLISION_SEARCH_OPTIONS &aOpts=COLLISION_SEARCH_OPTIONS()) const
Find items colliding (closer than clearance) with the item aItem.
Definition: pns_node.cpp:255
const ITEM_SET HitTest(const VECTOR2I &aPoint) const
Find all items that contain the point aPoint.
Definition: pns_node.cpp:490
virtual NODE * CurrentNode(bool aLoopsRemoved=false) const =0
Function CurrentNode()
virtual const VECTOR2I & CurrentEnd() const =0
Function CurrentEnd()
virtual const ITEM_SET Traces()=0
Function Traces()
virtual const VECTOR2I & CurrentStart() const =0
Function CurrentStart()
virtual int CurrentLayer() const =0
Function CurrentLayer()
virtual const std::vector< NET_HANDLE > CurrentNets() const =0
Function CurrentNets()
virtual void RemoveItem(ITEM *aItem)=0
virtual void UpdateItem(ITEM *aItem)=0
virtual void DisplayItem(const ITEM *aItem, int aClearance, bool aEdit=false, int aFlags=0)=0
virtual DEBUG_DECORATOR * GetDebugDecorator()=0
virtual void HideItem(ITEM *aItem)=0
virtual void Commit()=0
virtual void UpdateNet(NET_HANDLE aNet)=0
virtual void AddItem(ITEM *aItem)=0
virtual void EraseView()=0
virtual void SyncWorld(NODE *aNode)=0
void updateView(NODE *aNode, ITEM_SET &aCurrent, bool aDragging=false)
Definition: pns_router.cpp:716
void SetMode(ROUTER_MODE aMode)
bool moveDragging(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:630
bool SwitchLayer(int layer)
Definition: pns_router.cpp:973
void StopRouting()
Definition: pns_router.cpp:930
void ClearViewDecorations()
Definition: pns_router.cpp:958
std::vector< PNS::ITEM * > m_leaderSegments
Definition: pns_router.h:255
void ToggleCornerMode()
int m_iterLimit
Definition: pns_router.h:259
PLACEMENT_ALGO * Placer()
Definition: pns_router.h:221
std::vector< PNS::ITEM * > GetLastCommittedLeaderSegments()
Definition: pns_router.cpp:903
NODE * m_lastNode
Definition: pns_router.h:250
void ClearWorld()
Definition: pns_router.cpp:105
void BreakSegmentOrArc(ITEM *aItem, const VECTOR2I &aP)
bool ContinueFromEnd(ITEM **aNewStartItem)
Definition: pns_router.cpp:591
void UpdateSizes(const SIZES_SETTINGS &aSizes)
Applies stored settings.
Definition: pns_router.cpp:742
void SetFailureReason(const wxString &aReason)
Definition: pns_router.h:218
LOGGER * Logger()
RouterState m_state
Definition: pns_router.h:247
void CommitRouting()
Definition: pns_router.cpp:921
std::unique_ptr< DRAG_ALGO > m_dragger
Definition: pns_router.h:253
const ITEM_SET QueryHoverItems(const VECTOR2I &aP, int aSlopRadius=0)
Definition: pns_router.cpp:124
void SetInterface(ROUTER_IFACE *aIface)
bool Finish()
Definition: pns_router.cpp:543
void markViolations(NODE *aNode, ITEM_SET &aCurrent, NODE::ITEM_VECTOR &aRemoved)
Definition: pns_router.cpp:644
void SyncWorld()
Definition: pns_router.cpp:95
std::unique_ptr< PLACEMENT_ALGO > m_placer
Definition: pns_router.h:252
bool isStartingPointRoutable(const VECTOR2I &aWhere, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:219
ROUTER_IFACE * m_iface
Definition: pns_router.h:257
bool IsPlacingVia() const
void FlipPosture()
Definition: pns_router.cpp:964
RULE_RESOLVER * GetRuleResolver() const
Definition: pns_router.h:185
SIZES_SETTINGS m_sizes
Definition: pns_router.h:262
ROUTING_SETTINGS & Settings()
Definition: pns_router.h:197
DRAG_ALGO * GetDragger()
Definition: pns_router.h:145
bool movePlacing(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:752
bool RoutingInProgress() const
Definition: pns_router.cpp:118
BOX2I m_visibleViewArea
Definition: pns_router.h:246
static ROUTER * GetInstance()
Definition: pns_router.cpp:81
std::optional< VECTOR2I > UndoLastSegment()
Definition: pns_router.cpp:909
LOGGER * m_logger
Definition: pns_router.h:264
void SetOrthoMode(bool aEnable)
bool StartDragging(const VECTOR2I &aP, ITEM *aItem, int aDragMode=DM_ANY)
Definition: pns_router.cpp:157
bool StartRouting(const VECTOR2I &aP, ITEM *aItem, int aLayer)
Definition: pns_router.cpp:408
int GetCurrentLayer() const
bool getNearestRatnestAnchor(VECTOR2I &aOtherEnd, PNS_LAYER_RANGE &aOtherEndLayers, ITEM *&aOtherEndItem)
Definition: pns_router.cpp:492
void GetUpdatedItems(std::vector< PNS::ITEM * > &aRemoved, std::vector< PNS::ITEM * > &aAdded, std::vector< PNS::ITEM * > &aHeads)
Definition: pns_router.cpp:796
bool FixRoute(const VECTOR2I &aP, ITEM *aItem, bool aForceFinish, bool aForceCommit)
Definition: pns_router.cpp:878
std::unique_ptr< NODE > m_world
Definition: pns_router.h:249
void ToggleViaPlacement()
Definition: pns_router.cpp:982
ROUTING_SETTINGS * m_settings
Definition: pns_router.h:261
const std::vector< NET_HANDLE > GetCurrentNets() const
Definition: pns_router.cpp:995
ROUTER_MODE m_mode
Definition: pns_router.h:263
bool Move(const VECTOR2I &aP, ITEM *aItem)
Definition: pns_router.cpp:468
void SetCornerMode(DIRECTION_45::CORNER_MODE aMode)
DIRECTION_45::CORNER_MODE GetCornerMode() const
virtual void ClearCacheForItems(std::vector< const ITEM * > &aItems)
Definition: pns_node.h:167
virtual void ClearTemporaryCaches()
Definition: pns_node.h:169
virtual int Clearance(const ITEM *aA, const ITEM *aB, bool aUseClearanceEpsilon=true)=0
virtual void ClearCaches()
Definition: pns_node.h:168
int BoardMinTrackWidth() const
ITEM * NearestUnconnectedItem(const JOINT *aStart, int *aAnchor=nullptr, int aKindMask=ITEM::ANY_T)
bool NearestUnconnectedAnchorPoint(const LINE *aTrack, VECTOR2I &aPoint, PNS_LAYER_RANGE &aLayers, ITEM *&aItem)
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:32
int Start() const
Definition: pns_layerset.h:86
bool Overlaps(const PNS_LAYER_RANGE &aOther) const
Definition: pns_layerset.h:67
static PNS_LAYER_RANGE All()
Definition: pns_layerset.h:129
bool IsMultilayer() const
Definition: pns_layerset.h:81
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.
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
const wxString & GetZoneName() const
Definition: zone.h:132
bool HasKeepoutParametersSet() const
Accessor to determine if any keepout parameters are set.
Definition: zone.h:712
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
@ Edge_Cuts
Definition: layer_ids.h:112
Push and Shove diff pair dimensions (gap) settings dialog.
static ROUTER * theRouter
Definition: pns_router.cpp:58
void * NET_HANDLE
Definition: pns_item.h:54
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
@ MK_VIOLATION
Definition: pns_item.h:43
#define PNS_HEAD_TRACE
Hold an object colliding with another object, along with some useful data about the collision.
Definition: pns_node.h:87
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691