KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pns_kicad_iface.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2016 CERN
5 * Copyright The 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
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <board.h>
26#include <netinfo.h>
27#include <footprint.h>
28#include <layer_range.h>
30#include <pad.h>
31#include <pcb_track.h>
32#include <zone.h>
33#include <pcb_shape.h>
34#include <pcb_generator.h>
35#include <pcb_text.h>
36#include <pcb_barcode.h>
37#include <pcb_table.h>
38#include <pcb_tablecell.h>
39#include <pcb_dimension.h>
40#include <board_commit.h>
41#include <eda_group.h>
42#include <layer_ids.h>
43#include <optional>
44#include <kidialog.h>
45#include <tools/pcb_tool_base.h>
47#include <tool/tool_manager.h>
49
51#include <pcb_painter.h>
52
53#include <geometry/shape.h>
55#include <geometry/shape_arc.h>
59
60#include <drc/drc_rule.h>
61#include <drc/drc_engine.h>
62
64
65#include <wx/log.h>
66
67#include <memory>
68#include <unordered_map>
69#include <unordered_set>
70
71#include <advanced_config.h>
72#include <pcbnew_settings.h>
73#include <macros.h>
74
75#include "pns_kicad_iface.h"
76#include "pns_arc.h"
77#include "pns_sizes_settings.h"
78#include "pns_item.h"
79#include "pns_layerset.h"
80#include "pns_line.h"
81#include "pns_solid.h"
82#include "pns_segment.h"
83#include "pns_node.h"
84#include "pns_router.h"
85#include "pns_debug_decorator.h"
86#include "pns_diff_pair.h"
87#include "pns_topology.h"
88#include "router_preview_item.h"
89
91
92// Keep this odd so that it can never match a "real" pointer
93#define ENTERED_GROUP_MAGIC_NUMBER ( (BOARD*)777 )
94
96{
97 const PNS::ITEM* A;
98 const PNS::ITEM* B;
99 bool Flag;
100
101 CLEARANCE_CACHE_KEY( const PNS::ITEM* aA, const PNS::ITEM* aB, bool aFlag ) :
102 A( aA < aB ? aA : aB ),
103 B( aA < aB ? aB : aA ),
104 Flag( aFlag )
105 {
106 }
107
108 bool operator==( const CLEARANCE_CACHE_KEY& other ) const
109 {
110 return A == other.A && B == other.B && Flag == other.Flag;
111 }
112};
113
114namespace std
115{
116 template <>
118 {
119 std::size_t operator()( const CLEARANCE_CACHE_KEY& k ) const noexcept
120 {
121 size_t retval = 0xBADC0FFEE0DDF00D;
122
123 hash_combine( retval,
124 hash<const void*>()( k.A ),
125 hash<const void*>()( k.B ),
126 hash<int>()( k.Flag ) );
127 return retval;
128 }
129 };
130}
131
132
133// Identifies a pair of items for the temporary clearance cache by their properties (net, layers,
134// kind) instead of their memory address. Items with the same properties get the same clearance
135// from the rules, so they share one cache entry.
137{
139 {
140 const void* boardItem;
141 const void* net;
146 int kind;
148
149 bool operator==( const PARTICIPANT& o ) const
150 {
151 return boardItem == o.boardItem
152 && net == o.net
153 && start == o.start && end == o.end
154 && layerStart == o.layerStart && layerEnd == o.layerEnd
155 && kind == o.kind
156 && freePad == o.freePad;
157 }
158
159 bool operator<( const PARTICIPANT& o ) const
160 {
161 if( boardItem != o.boardItem )
162 return boardItem < o.boardItem;
163
164 if( net != o.net )
165 return net < o.net;
166
167 if( start < o.start )
168 return start < o.start;
169
170 if( end < o.end )
171 return end < o.end;
172
173 if( layerStart != o.layerStart )
174 return layerStart < o.layerStart;
175
176 if( layerEnd != o.layerEnd )
177 return layerEnd < o.layerEnd;
178
179 if( kind != o.kind )
180 return kind < o.kind;
181
182 return freePad < o.freePad;
183 }
184 };
185
188 bool Flag;
189
190 static PARTICIPANT makeParticipant( const PNS::ITEM* aItem )
191 {
192 const SHAPE* shape = aItem->Shape( aItem->Layer() );
193
194 return PARTICIPANT{ (const void*) aItem->BoardItem(),
195 (const void*) aItem->Net(),
196 shape ? shape->GetStart() : VECTOR2I(),
197 shape ? shape->GetEnd() : VECTOR2I(),
198 aItem->Layers().Start(),
199 aItem->Layers().End(),
200 (int) aItem->Kind(),
201 aItem->IsFreePad() };
202 }
203
204 TEMP_CLEARANCE_CACHE_KEY( const PNS::ITEM* aA, const PNS::ITEM* aB, bool aFlag ) :
205 Flag( aFlag )
206 {
207 PARTICIPANT sa = makeParticipant( aA );
208 PARTICIPANT sb = makeParticipant( aB );
209
210 // Canonical order so the key is symmetric in (A, B)
211 if( sb < sa )
212 {
213 A = sb;
214 B = sa;
215 }
216 else
217 {
218 A = sa;
219 B = sb;
220 }
221 }
222
223 bool operator==( const TEMP_CLEARANCE_CACHE_KEY& o ) const { return A == o.A && B == o.B && Flag == o.Flag; }
224};
225
226namespace std
227{
228 template <>
230 {
231 std::size_t operator()( const TEMP_CLEARANCE_CACHE_KEY& k ) const noexcept
232 {
233 size_t retval = 0xBADC0FFEE0DDF00D;
234
235 for( const TEMP_CLEARANCE_CACHE_KEY::PARTICIPANT* s : { &k.A, &k.B } )
236 {
237 hash_combine( retval,
238 hash<const void*>()( s->boardItem ),
239 hash<const void*>()( s->net ),
240 hash<int>()( s->start.x ), hash<int>()( s->start.y ),
241 hash<int>()( s->end.x ), hash<int>()( s->end.y ),
242 hash<int>()( s->layerStart ), hash<int>()( s->layerEnd ),
243 hash<int>()( s->kind ),
244 hash<bool>()( s->freePad ) );
245 }
246
247 hash_combine( retval, hash<bool>()( k.Flag ) );
248 return retval;
249 }
250 };
251} // namespace std
252
253
255{
259 int layer;
260
261 bool operator==( const HULL_CACHE_KEY& other ) const
262 {
263 return item == other.item
264 && clearance == other.clearance
266 && layer == other.layer;
267 }
268};
269
270namespace std
271{
272 template <>
273 struct hash<HULL_CACHE_KEY>
274 {
275 std::size_t operator()( const HULL_CACHE_KEY& k ) const noexcept
276 {
277 size_t retval = 0xBADC0FFEE0DDF00D;
278
279 hash_combine( retval,
280 hash<const void*>()( k.item ),
281 hash<int>()( k.clearance ),
282 hash<int>()( k.walkaroundThickness ),
283 hash<int>()( k.layer ) );
284 return retval;
285 }
286 };
287}
288
289
291{
292public:
293 PNS_PCBNEW_RULE_RESOLVER( BOARD* aBoard, PNS::ROUTER_IFACE* aRouterIface );
295
296 int Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB, bool aUseClearanceEpsilon = true ) override;
297
298 bool HasUserDefinedPhysicalConstraint() override;
299
301 int DpNetPolarity( PNS::NET_HANDLE aNet ) override;
302 bool DpNetPair( const PNS::ITEM* aItem, PNS::NET_HANDLE& aNetP,
303 PNS::NET_HANDLE& aNetN ) override;
304
305 int NetCode( PNS::NET_HANDLE aNet ) override;
306 wxString NetName( PNS::NET_HANDLE aNet ) override;
307
308 bool IsInNetTie( const PNS::ITEM* aA ) override;
309 bool IsNetTieExclusion( const PNS::ITEM* aItem, const VECTOR2I& aCollisionPos,
310 const PNS::ITEM* aCollidingItem ) override;
311
312 bool IsDrilledHole( const PNS::ITEM* aItem ) override;
313 bool IsNonPlatedSlot( const PNS::ITEM* aItem ) override;
314
319 bool IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem, bool* aEnforce ) override;
320
321 bool QueryConstraint( PNS::CONSTRAINT_TYPE aType, const PNS::ITEM* aItemA,
322 const PNS::ITEM* aItemB, int aLayer,
323 PNS::CONSTRAINT* aConstraint ) override;
324
325 int ClearanceEpsilon() const override { return m_clearanceEpsilon; }
326
327 void ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems ) override;
328 void ClearCaches() override;
329 void ClearTemporaryCaches() override;
330
331 const SHAPE_LINE_CHAIN& HullCache( const PNS::ITEM* aItem, int aClearance,
332 int aWalkaroundThickness, int aLayer ) override;
333
334private:
335 BOARD_ITEM* getBoardItem( const PNS::ITEM* aItem, PCB_LAYER_ID aBoardLayer, int aIdx = 0 );
336
337private:
344
345 // Cached for the routing session; HasUserDefinedPhysicalConstraint runs in the
346 // collideSimple inner loop and walks the DRC engine map otherwise.
347 std::optional<bool> m_hasUserPhysicalConstraint;
348
349 std::unordered_map<CLEARANCE_CACHE_KEY, int> m_clearanceCache;
350 std::unordered_map<TEMP_CLEARANCE_CACHE_KEY, int> m_tempClearanceCache;
351 std::unordered_map<HULL_CACHE_KEY, SHAPE_LINE_CHAIN> m_hullCache;
352};
353
354
356 PNS::ROUTER_IFACE* aRouterIface ) :
357 m_routerIface( aRouterIface ),
358 m_board( aBoard ),
359 m_dummyTracks{ { aBoard }, { aBoard } },
360 m_dummyArcs{ { aBoard }, { aBoard } },
361 m_dummyVias{ { aBoard }, { aBoard } }
362{
363 for( PCB_TRACK& track : m_dummyTracks )
364 track.SetFlags( ROUTER_TRANSIENT );
365
366 for( PCB_ARC& arc : m_dummyArcs )
367 arc.SetFlags( ROUTER_TRANSIENT );
368
369 for ( PCB_VIA& via : m_dummyVias )
370 via.SetFlags( ROUTER_TRANSIENT );
371
372 if( aBoard )
373 m_clearanceEpsilon = aBoard->GetDesignSettings().GetDRCEpsilon();
374 else
375 m_clearanceEpsilon = 0;
376}
377
378
382
383
385{
386 BOARD_ITEM* item = aA->BoardItem();
387
388 return item && item->GetParentFootprint() && item->GetParentFootprint()->IsNetTie();
389}
390
391
393 const VECTOR2I& aCollisionPos,
394 const PNS::ITEM* aCollidingItem )
395{
396 if( !aItem || !aCollidingItem )
397 return false;
398
399 DRC_ENGINE* drcEngine = m_board->GetDesignSettings().m_DRCEngine.get();
400 BOARD_ITEM* item = aItem->BoardItem();
401 BOARD_ITEM* collidingItem = aCollidingItem->BoardItem();
402
403 FOOTPRINT* collidingFp = collidingItem->GetParentFootprint();
404 FOOTPRINT* itemFp = item ? item->GetParentFootprint() : nullptr;
405
406 if( collidingFp && itemFp && ( collidingFp == itemFp ) && itemFp->IsNetTie() )
407 {
408 // Two items colliding from the same net tie footprint are not checked
409 return true;
410 }
411
412 if( drcEngine )
413 {
414 return drcEngine->IsNetTieExclusion( NetCode( aItem->Net() ),
415 m_routerIface->GetBoardLayerFromPNSLayer( aItem->Layer() ),
416 aCollisionPos, collidingItem );
417 }
418
419 return false;
420}
421
422
423bool PNS_PCBNEW_RULE_RESOLVER::IsKeepout( const PNS::ITEM* aObstacle, const PNS::ITEM* aItem,
424 bool* aEnforce )
425{
426 auto checkKeepout =
427 []( const ZONE* aKeepout, const BOARD_ITEM* aOther )
428 {
429 if( !aOther )
430 return false;
431
432 if( aKeepout->GetDoNotAllowTracks() && aOther->IsType( { PCB_ARC_T, PCB_TRACE_T } ) )
433 return true;
434
435 if( aKeepout->GetDoNotAllowVias() && aOther->Type() == PCB_VIA_T )
436 return true;
437
438 if( aKeepout->GetDoNotAllowPads() && aOther->Type() == PCB_PAD_T )
439 return true;
440
441 // Incomplete test, but better than nothing:
442 if( aKeepout->GetDoNotAllowFootprints() && aOther->Type() == PCB_PAD_T )
443 {
444 return !aKeepout->GetParentFootprint()
445 || aKeepout->GetParentFootprint() != aOther->GetParentFootprint();
446 }
447
448 return false;
449 };
450
451 if( aObstacle->Parent() && aObstacle->Parent()->Type() == PCB_ZONE_T )
452 {
453 const ZONE* zone = static_cast<ZONE*>( aObstacle->Parent() );
454
455 if( zone->GetIsRuleArea() && zone->HasKeepoutParametersSet() )
456 {
457 *aEnforce = checkKeepout( zone,
458 getBoardItem( aItem, m_routerIface->GetBoardLayerFromPNSLayer(
459 aObstacle->Layer() ) ) );
460 return true;
461 }
462 }
463
464 return false;
465}
466
467
468static bool isCopper( const PNS::ITEM* aItem )
469{
470 if ( !aItem )
471 return false;
472
473 const BOARD_ITEM *parent = aItem->Parent();
474
475 return !parent || parent->IsOnCopperLayer();
476}
477
478
479static bool isHole( const PNS::ITEM* aItem )
480{
481 if ( !aItem )
482 return false;
483
484 return aItem->OfKind( PNS::ITEM::HOLE_T );
485}
486
487
488static bool isEdge( const PNS::ITEM* aItem )
489{
490 if ( !aItem )
491 return false;
492
493 const PCB_SHAPE *parent = dynamic_cast<PCB_SHAPE*>( aItem->BoardItem() );
494
495 return parent && ( parent->IsOnLayer( Edge_Cuts ) || parent->IsOnLayer( Margin ) );
496}
497
498
500{
501 if( !isHole( aItem ) )
502 return false;
503
504 BOARD_ITEM* parent = aItem->Parent();
505
506 if( !parent && aItem->ParentPadVia() )
507 {
508 const PNS::ITEM* padVia = aItem->ParentPadVia();
509 parent = padVia->Parent();
510
511 // A via the router is still placing has no board item yet; its hole is drilled all the
512 // same, otherwise it only ever gets hole-to-copper clearance against other holes.
513 if( !parent && padVia->OfKind( PNS::ITEM::VIA_T ) )
514 {
515 VIATYPE type = static_cast<const PNS::VIA*>( padVia )->ViaType();
516 return type == VIATYPE::THROUGH || type == VIATYPE::BLIND || type == VIATYPE::BURIED;
517 }
518 }
519
520 return parent && parent->HasDrilledHole();
521}
522
523
525{
526 if( !isHole( aItem ) )
527 return false;
528
529 BOARD_ITEM* parent = aItem->Parent();
530
531 if( !parent && aItem->ParentPadVia() )
532 parent = aItem->ParentPadVia()->Parent();
533
534 if( parent )
535 {
536 if( parent->Type() == PCB_PAD_T )
537 {
538 PAD* pad = static_cast<PAD*>( parent );
539
540 return pad->GetAttribute() == PAD_ATTRIB::NPTH
541 && pad->GetDrillSize().x != pad->GetDrillSize().y;
542 }
543
544 // Via holes are (currently) always round, and always plated
545 }
546
547 return false;
548}
549
550
552{
553 switch( aItem->Kind() )
554 {
555 case PNS::ITEM::ARC_T:
556 m_dummyArcs[aIdx].SetLayer( aBoardLayer );
557 m_dummyArcs[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
558 m_dummyArcs[aIdx].SetStart( aItem->Anchor( 0 ) );
559 m_dummyArcs[aIdx].SetEnd( aItem->Anchor( 1 ) );
560 return &m_dummyArcs[aIdx];
561
562 case PNS::ITEM::VIA_T:
564 m_dummyVias[aIdx].SetLayer( aBoardLayer );
565 m_dummyVias[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
566 m_dummyVias[aIdx].SetStart( aItem->Anchor( 0 ) );
567 return &m_dummyVias[aIdx];
568
571 m_dummyTracks[aIdx].SetLayer( aBoardLayer );
572 m_dummyTracks[aIdx].SetNet( static_cast<NETINFO_ITEM*>( aItem->Net() ) );
573 m_dummyTracks[aIdx].SetStart( aItem->Anchor( 0 ) );
574 m_dummyTracks[aIdx].SetEnd( aItem->Anchor( 1 ) );
575 return &m_dummyTracks[aIdx];
576
577 default:
578 return nullptr;
579 }
580}
581
582
584 const PNS::ITEM* aItemA, const PNS::ITEM* aItemB,
585 int aPNSLayer, PNS::CONSTRAINT* aConstraint )
586{
587 std::shared_ptr<DRC_ENGINE> drcEngine = m_board->GetDesignSettings().m_DRCEngine;
588
589 if( !drcEngine )
590 return false;
591
592 DRC_CONSTRAINT_T hostType;
593
594 switch ( aType )
595 {
609 default: return false; // should not happen
610 }
611
612 BOARD_ITEM* parentA = aItemA ? aItemA->BoardItem() : nullptr;
613 BOARD_ITEM* parentB = aItemB ? aItemB->BoardItem() : nullptr;
614 PCB_LAYER_ID board_layer = m_routerIface->GetBoardLayerFromPNSLayer( aPNSLayer );
615 DRC_CONSTRAINT hostConstraint;
616
617 // For clearance-type constraints, pick the smaller (more permissive) value.
618 // Returns true if we found a zero/negative clearance (can't get more permissive).
619 auto pickSmallerConstraint =
620 []( DRC_CONSTRAINT& aBest, const DRC_CONSTRAINT& aCandidate ) -> bool
621 {
622 if( aCandidate.IsNull() )
623 return false;
624
625 if( aBest.IsNull() )
626 {
627 aBest = aCandidate;
628 }
629 else if( aCandidate.m_Value.HasMin() && aBest.m_Value.HasMin()
630 && aCandidate.m_Value.Min() < aBest.m_Value.Min() )
631 {
632 aBest = aCandidate;
633 }
634
635 return aBest.m_Value.HasMin() && aBest.m_Value.Min() <= 0;
636 };
637
638 // Check for multi-segment LINEs without BoardItems. These need segment-by-segment
639 // evaluation because custom DRC rules may have geometry-dependent conditions (like
640 // intersectsCourtyard) that require evaluating actual segment positions.
641 auto isMultiSegmentLine =
642 []( const PNS::ITEM* aItem, BOARD_ITEM* aParent ) -> bool
643 {
644 if( !aItem || aParent || aItem->Kind() != PNS::ITEM::LINE_T )
645 return false;
646
647 const auto* line = static_cast<const PNS::LINE*>( aItem );
648 return line->CLine().SegmentCount() > 1;
649 };
650
651 bool lineANeedsSegmentEval = false;
652 bool lineBNeedsSegmentEval = false;
653
654 if( drcEngine->HasGeometryDependentRules() )
655 {
656 lineANeedsSegmentEval = isMultiSegmentLine( aItemA, parentA );
657 lineBNeedsSegmentEval = isMultiSegmentLine( aItemB, parentB );
658 }
659
660 // Evaluate segments of a multi-segment LINE against a single opposing item.
661 auto evaluateLineSegments =
662 [&]( const PNS::ITEM* aLineItem, BOARD_ITEM* aOpposingItem, bool aLineIsFirst, int aIdx ) -> DRC_CONSTRAINT
663 {
664 DRC_CONSTRAINT bestConstraint;
665 const PNS::LINE* line = static_cast<const PNS::LINE*>( aLineItem );
666 const SHAPE_LINE_CHAIN& chain = line->CLine();
667
668 PCB_TRACK& dummyTrack = m_dummyTracks[aIdx];
669 dummyTrack.SetLayer( board_layer );
670 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aLineItem->Net() ) );
671 dummyTrack.SetWidth( line->Width() );
672
673 for( int i = 0; i < chain.SegmentCount(); i++ )
674 {
675 dummyTrack.SetStart( chain.CPoint( i ) );
676 dummyTrack.SetEnd( chain.CPoint( i + 1 ) );
677
678 DRC_CONSTRAINT segConstraint = aLineIsFirst
679 ? drcEngine->EvalRules( hostType, &dummyTrack, aOpposingItem, board_layer )
680 : drcEngine->EvalRules( hostType, aOpposingItem, &dummyTrack, board_layer );
681
682 if( pickSmallerConstraint( bestConstraint, segConstraint ) )
683 break;
684 }
685
686 return bestConstraint;
687 };
688
689 // Check if two multi-segment lines have overlapping bboxes (worth doing segment evaluation)
690 auto linesBBoxOverlap =
691 [&]() -> bool
692 {
693 if( !lineANeedsSegmentEval || !lineBNeedsSegmentEval )
694 return true;
695
696 const PNS::LINE* lineA = static_cast<const PNS::LINE*>( aItemA );
697 const PNS::LINE* lineB = static_cast<const PNS::LINE*>( aItemB );
698 const int proximityThreshold = std::max( lineA->Width(), lineB->Width() ) * 2;
699
700 BOX2I bboxA = lineA->CLine().BBox();
701 bboxA.Inflate( proximityThreshold );
702
703 return bboxA.Intersects( lineB->CLine().BBox() );
704 };
705
706 // Handle multi-segment lines with segment-by-segment evaluation.
707 if( ( lineANeedsSegmentEval || lineBNeedsSegmentEval ) && linesBBoxOverlap() )
708 {
709 // Get dummy items for non-multi-segment items that need them
710 if( aItemA && !parentA && !lineANeedsSegmentEval )
711 parentA = getBoardItem( aItemA, board_layer, 0 );
712
713 if( aItemB && !parentB && !lineBNeedsSegmentEval )
714 parentB = getBoardItem( aItemB, board_layer, 1 );
715
716 if( lineANeedsSegmentEval && lineBNeedsSegmentEval )
717 {
718 // Both items are multi-segment lines. Evaluate segment pairs, skipping pairs
719 // that are far apart since geometry-dependent rules won't trigger for them.
720 const auto* lineA = static_cast<const PNS::LINE*>( aItemA );
721 const auto* lineB = static_cast<const PNS::LINE*>( aItemB );
722 const SHAPE_LINE_CHAIN& chainA = lineA->CLine();
723 const SHAPE_LINE_CHAIN& chainB = lineB->CLine();
724
725 const int proximityThreshold = std::max( lineA->Width(), lineB->Width() ) * 2;
726
727 PCB_TRACK& dummyA = m_dummyTracks[0];
728 dummyA.SetLayer( board_layer );
729 dummyA.SetNet( static_cast<NETINFO_ITEM*>( aItemA->Net() ) );
730 dummyA.SetWidth( lineA->Width() );
731
732 PCB_TRACK& dummyB = m_dummyTracks[1];
733 dummyB.SetLayer( board_layer );
734 dummyB.SetNet( static_cast<NETINFO_ITEM*>( aItemB->Net() ) );
735 dummyB.SetWidth( lineB->Width() );
736
737 bool done = false;
738 BOX2I bboxA, bboxB;
739
740 for( int i = 0; i < chainA.SegmentCount() && !done; i++ )
741 {
742 const VECTOR2I& ptA1 = chainA.CPoint( i );
743 const VECTOR2I& ptA2 = chainA.CPoint( i + 1 );
744
745 bboxA.SetOrigin( ptA1 );
746 bboxA.SetEnd( ptA2 );
747 bboxA.Normalize();
748 bboxA.Inflate( proximityThreshold );
749
750 dummyA.SetStart( ptA1 );
751 dummyA.SetEnd( ptA2 );
752
753 for( int j = 0; j < chainB.SegmentCount(); j++ )
754 {
755 const VECTOR2I& ptB1 = chainB.CPoint( j );
756 const VECTOR2I& ptB2 = chainB.CPoint( j + 1 );
757
758 bboxB.SetOrigin( ptB1 );
759 bboxB.SetEnd( ptB2 );
760 bboxB.Normalize();
761
762 if( !bboxA.Intersects( bboxB ) )
763 continue;
764
765 dummyB.SetStart( ptB1 );
766 dummyB.SetEnd( ptB2 );
767
768 DRC_CONSTRAINT segConstraint =
769 drcEngine->EvalRules( hostType, &dummyA, &dummyB, board_layer );
770
771 if( pickSmallerConstraint( hostConstraint, segConstraint ) )
772 {
773 done = true;
774 break;
775 }
776 }
777 }
778 }
779 else if( lineANeedsSegmentEval )
780 {
781 hostConstraint = evaluateLineSegments( aItemA, parentB, true, 0 );
782 }
783 else
784 {
785 hostConstraint = evaluateLineSegments( aItemB, parentA, false, 1 );
786 }
787 }
788 else
789 {
790 // Standard path: no multi-segment lines (or lines too far apart), use anchor-based dummies
791 if( aItemA && !parentA )
792 parentA = getBoardItem( aItemA, board_layer, 0 );
793
794 if( aItemB && !parentB )
795 parentB = getBoardItem( aItemB, board_layer, 1 );
796
797 if( parentA )
798 hostConstraint = drcEngine->EvalRules( hostType, parentA, parentB, board_layer );
799 }
800
801 if( hostConstraint.IsNull() )
802 return false;
803
804 if( hostConstraint.GetSeverity() == RPT_SEVERITY_IGNORE
805 && ( !hostConstraint.GetParentRule()->IsImplicit()
807 {
808 aConstraint->m_Value.SetMin( -1 );
809 aConstraint->m_RuleName = hostConstraint.GetName();
810 aConstraint->m_Type = aType;
811 return true;
812 }
813
814 switch ( aType )
815 {
829 aConstraint->m_Value = hostConstraint.GetValue();
830 aConstraint->m_RuleName = hostConstraint.GetName();
831 aConstraint->m_Type = aType;
832 aConstraint->m_IsTimeDomain = hostConstraint.GetOption( DRC_CONSTRAINT::OPTIONS::TIME_DOMAIN );
833 return true;
834
835 default:
836 return false;
837 }
838}
839
840
841void PNS_PCBNEW_RULE_RESOLVER::ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems )
842{
843 if( aItems.empty() )
844 return;
845
846 std::unordered_set<const PNS::ITEM*> dirtyItems( aItems.begin(), aItems.end() );
847
848 std::erase_if( m_clearanceCache,
849 [&dirtyItems]( const auto& entry )
850 {
851 return dirtyItems.contains( entry.first.A ) || dirtyItems.contains( entry.first.B );
852 } );
853
854 std::erase_if( m_hullCache,
855 [&dirtyItems]( const auto& entry )
856 {
857 return dirtyItems.contains( entry.first.item );
858 } );
859}
860
861
869
870
875
876
878 int aClearance,
879 int aWalkaroundThickness,
880 int aLayer )
881{
882 HULL_CACHE_KEY key = { aItem, aClearance, aWalkaroundThickness, aLayer };
883
884 auto it = m_hullCache.find( key );
885
886 if( it != m_hullCache.end() )
887 return it->second;
888
889 SHAPE_LINE_CHAIN hull = aItem->Hull( aClearance, aWalkaroundThickness, aLayer );
890 auto result = m_hullCache.emplace( key, std::move( hull ) );
891
892 return result.first->second;
893}
894
895
897{
898 if( !m_hasUserPhysicalConstraint.has_value() )
899 {
900 if( std::shared_ptr<DRC_ENGINE> drc = m_board->GetDesignSettings().m_DRCEngine )
901 m_hasUserPhysicalConstraint = drc->HasUserDefinedPhysicalConstraint();
902 else
904 }
905
907}
908
909
911 bool aUseClearanceEpsilon )
912{
913 const bool bothOwned = aA && aB && aA->Owner() && aB->Owner();
914
915 if( bothOwned )
916 {
917 // Search cache (used for actual board items)
918 auto it = m_clearanceCache.find( CLEARANCE_CACHE_KEY( aA, aB, aUseClearanceEpsilon ) );
919
920 if( it != m_clearanceCache.end() )
921 return it->second;
922 }
923 else if( aA && aB )
924 {
925 // Search cache (used for temporary items within an algorithm)
926 auto it = m_tempClearanceCache.find( TEMP_CLEARANCE_CACHE_KEY( aA, aB, aUseClearanceEpsilon ) );
927
928 if( it != m_tempClearanceCache.end() )
929 return it->second;
930 }
931
932 PNS::CONSTRAINT constraint;
933 int rv = 0;
934 PNS_LAYER_RANGE layers;
935
936 if( !aB )
937 layers = aA->Layers();
938 else if( isEdge( aA ) )
939 layers = aB->Layers();
940 else if( isEdge( aB ) )
941 layers = aA->Layers();
942 else
943 layers = aA->Layers().Intersection( aB->Layers() );
944
945 // Normalize layer range (no -1 magic numbers)
947
948 const bool sameNet = aA && aB && aA->Net() && aA->Net() == aB->Net();
949 const bool freePad = aA && aB && ( aA->IsFreePad() || aB->IsFreePad() );
950
951 for( int layer = layers.Start(); layer <= layers.End(); ++layer )
952 {
953 if( IsDrilledHole( aA ) && IsDrilledHole( aB ) )
954 {
955 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, aA, aB, layer, &constraint ) )
956 {
957 if( constraint.m_Value.Min() > rv )
958 rv = constraint.m_Value.Min();
959 }
960 }
961 else if( isHole( aA ) || isHole( aB ) )
962 {
963 if( !sameNet )
964 {
965 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_CLEARANCE, aA, aB, layer, &constraint ) )
966 {
967 if( constraint.m_Value.Min() > rv )
968 rv = constraint.m_Value.Min();
969 }
970 }
971 }
972
973 // No 'else'; plated holes get both HOLE_CLEARANCE and CLEARANCE
974 if( isCopper( aA ) && ( !aB || isCopper( aB ) ) && !sameNet && !freePad )
975 {
976 if( !sameNet && !freePad )
977 {
978 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, layer, &constraint ) )
979 {
980 if( constraint.m_Value.Min() > rv )
981 rv = constraint.m_Value.Min();
982 }
983 }
984 }
985
986 if( isEdge( aA ) || isEdge( aB ) )
987 {
988 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_EDGE_CLEARANCE, aA, aB, layer, &constraint ) )
989 {
990 if( constraint.m_Value.Min() > rv )
991 rv = constraint.m_Value.Min();
992 }
993 }
994
995 // Physical clearances are net-blind: a physical_clearance rule applies regardless
996 if( isHole( aA ) || isHole( aB ) )
997 {
998 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_PHYSICAL_HOLE_CLEARANCE, aA, aB, layer, &constraint ) )
999 {
1000 if( constraint.m_Value.Min() > rv )
1001 rv = constraint.m_Value.Min();
1002 }
1003 }
1004
1005 if( QueryConstraint( PNS::CONSTRAINT_TYPE::CT_PHYSICAL_CLEARANCE, aA, aB, layer, &constraint ) )
1006 {
1007 if( constraint.m_Value.Min() > rv )
1008 rv = constraint.m_Value.Min();
1009 }
1010 }
1011
1012 // Same-net pairs short-circuit clearance unless a physical_clearance rule gave a positive value
1013 if( ( sameNet || freePad ) && rv == 0 )
1014 rv = -1;
1015
1016 if( aUseClearanceEpsilon && rv > 0 )
1017 rv = std::max( 0, rv - m_clearanceEpsilon );
1018
1019 // Remember this result so we don't recompute it. Real board items go in the long-lived
1020 // cache. Temporary items the router creates while routing go in a separate cache we can
1021 // clear on their own.
1022 if( bothOwned )
1023 m_clearanceCache[CLEARANCE_CACHE_KEY( aA, aB, aUseClearanceEpsilon )] = rv;
1024 else if( aA && aB )
1025 m_tempClearanceCache[TEMP_CLEARANCE_CACHE_KEY( aA, aB, aUseClearanceEpsilon )] = rv;
1026
1027 return rv;
1028}
1029
1030
1031bool PNS_KICAD_IFACE_BASE::inheritTrackWidthAndDpGap( PNS::ITEM* aItem, const VECTOR2I& aStartPosition, int* aInheritedWidth, int *aInheritedGap )
1032{
1033 VECTOR2I p;
1034
1035 assert( aItem->Owner() != nullptr );
1036
1037 PNS::NET_HANDLE coupledNet = GetRuleResolver()->DpCoupledNet( aItem->Net() );
1038
1039 if( coupledNet && aInheritedGap )
1040 {
1041 PNS::TOPOLOGY topo( m_world );
1042 PNS::DIFF_PAIR dp;
1043 if( topo.AssembleDiffPair( static_cast<PNS::SEGMENT*>( aItem ), dp ) )
1044 {
1045 *aInheritedGap = dp.GuessMostLikelyGap();
1046 }
1047 else
1048 {
1049 return false;
1050 }
1051 }
1052
1053 auto tryGetTrackWidth =
1054 []( PNS::ITEM* aPnsItem ) -> int
1055 {
1056 switch( aPnsItem->Kind() )
1057 {
1058 case PNS::ITEM::SEGMENT_T: return static_cast<PNS::SEGMENT*>( aPnsItem )->Width();
1059 case PNS::ITEM::ARC_T: return static_cast<PNS::ARC*>( aPnsItem )->Width();
1060 default: return -1;
1061 }
1062 };
1063
1064 int itemTrackWidth = tryGetTrackWidth( aItem );
1065
1066 if( itemTrackWidth > 0 )
1067 {
1068 *aInheritedWidth = itemTrackWidth;
1069 return true;
1070 }
1071
1072 switch( aItem->Kind() )
1073 {
1074 case PNS::ITEM::VIA_T: p = static_cast<PNS::VIA*>( aItem )->Pos(); break;
1075 case PNS::ITEM::SOLID_T: p = static_cast<PNS::SOLID*>( aItem )->Pos(); break;
1076 default: return false;
1077 }
1078
1079 const PNS::JOINT* jt = static_cast<const PNS::NODE*>( aItem->Owner() )->FindJoint( p, aItem );
1080
1081 assert( jt != nullptr );
1082
1083 PNS::ITEM_SET linkedSegs( jt->CLinks() );
1085
1086 if( linkedSegs.Empty() )
1087 return false;
1088
1089 // When a start position is provided, find the connected track whose far end is closest to
1090 // the cursor. Since all tracks share the pad/via endpoint, the far-end direction is a proxy
1091 // for which exit stub the user is pointing at.
1092 if( aStartPosition != VECTOR2I() )
1093 {
1094 PNS::ITEM* closestItem = nullptr;
1096
1097 for( PNS::ITEM* item : linkedSegs.Items() )
1098 {
1099 if( item->Layer() != m_startLayer )
1100 continue;
1101
1102 PNS::LINKED_ITEM* li = static_cast<PNS::LINKED_ITEM*>( item );
1103
1104 VECTOR2I anchor0 = li->Anchor( 0 );
1105 VECTOR2I anchor1 = li->Anchor( 1 );
1106
1107 // The "other end" is the anchor farther from the pad/via center
1108 VECTOR2I otherEnd = ( anchor0 - p ).SquaredEuclideanNorm() > ( anchor1 - p ).SquaredEuclideanNorm()
1109 ? anchor0
1110 : anchor1;
1111
1112 SEG::ecoord dist = ( otherEnd - aStartPosition ).SquaredEuclideanNorm();
1113
1114 if( dist < minDist )
1115 {
1116 minDist = dist;
1117 closestItem = item;
1118 }
1119 }
1120
1121 if( closestItem )
1122 {
1123 int w = tryGetTrackWidth( closestItem );
1124
1125 if( w > 0 )
1126 {
1127 *aInheritedWidth = w;
1128 return true;
1129 }
1130 }
1131 }
1132
1133 // Fallback to minimum width when no start position provided or no valid exit stub found
1134 int min_current_layer = INT_MAX;
1135 int min_all_layers = INT_MAX;
1136
1137 for( PNS::ITEM* item : linkedSegs.Items() )
1138 {
1139 int w = tryGetTrackWidth( item );
1140
1141 if( w > 0 )
1142 {
1143 min_all_layers = std::min( w, min_all_layers );
1144
1145 if( item->Layer() == m_startLayer )
1146 min_current_layer = std::min( w, min_current_layer );
1147 }
1148 }
1149
1150 if( min_all_layers == INT_MAX )
1151 return false;
1152
1153 if( min_current_layer < INT_MAX )
1154 *aInheritedWidth = min_current_layer;
1155 else
1156 *aInheritedWidth = min_all_layers;
1157
1158 return true;
1159}
1160
1161
1163 PNS::NET_HANDLE aNet, VECTOR2D aStartPosition )
1164{
1165 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
1166 PNS::CONSTRAINT constraint;
1167
1168 if( aStartItem && m_startLayer < 0 )
1169 m_startLayer = aStartItem->Layer();
1170
1171 aSizes.SetClearance( bds.m_MinClearance );
1172 aSizes.SetMinClearance( bds.m_MinClearance );
1173 aSizes.SetClearanceSource( _( "board minimum clearance" ) );
1174
1175 int startAnchor = 0;
1176 VECTOR2I startPosInt( aStartPosition.x, aStartPosition.y );
1177
1178 if( aStartItem && aStartItem->Kind() == PNS::ITEM::SEGMENT_T )
1179 {
1180 // Find the start anchor which is closest to the start mouse location
1181 double anchor0Distance = startPosInt.Distance( aStartItem->Anchor( 0 ) );
1182 double anchor1Distance = startPosInt.Distance( aStartItem->Anchor( 1 ) );
1183
1184 if( anchor1Distance < anchor0Distance )
1185 startAnchor = 1;
1186 }
1187
1188 if( aStartItem )
1189 {
1190 PNS::SEGMENT dummyTrack;
1191 dummyTrack.SetEnds( aStartItem->Anchor( startAnchor ), aStartItem->Anchor( startAnchor ) );
1192 dummyTrack.SetLayer( m_startLayer );
1193 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
1194
1195 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, &dummyTrack, nullptr,
1196 m_startLayer, &constraint ) )
1197 {
1198 if( constraint.m_Value.Min() >= bds.m_MinClearance )
1199 {
1200 aSizes.SetClearance( constraint.m_Value.Min() );
1201 aSizes.SetClearanceSource( constraint.m_RuleName );
1202 }
1203 }
1204 }
1205
1206 int trackWidth = bds.m_TrackMinWidth;
1207 bool found = false;
1208 aSizes.SetWidthSource( _( "board minimum track width" ) );
1209
1210 if( bds.m_UseConnectedTrackWidth && !bds.m_TempOverrideTrackWidth && aStartItem != nullptr )
1211 {
1212 found = inheritTrackWidthAndDpGap( aStartItem, aStartPosition, &trackWidth, nullptr );
1213
1214 if( found )
1215 aSizes.SetWidthSource( _( "existing track" ) );
1216 }
1217
1218 if( !found && bds.UseNetClassTrack() && aStartItem )
1219 {
1220 PNS::SEGMENT dummyTrack;
1221 dummyTrack.SetEnds( aStartItem->Anchor( startAnchor ), aStartItem->Anchor( startAnchor ) );
1222 dummyTrack.SetLayer( m_startLayer );
1223 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
1224
1225 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, &dummyTrack, nullptr,
1226 m_startLayer, &constraint ) )
1227 {
1228 trackWidth = std::max( trackWidth, constraint.m_Value.PinnedOpt() );
1229 found = true;
1230
1231 if( trackWidth == constraint.m_Value.Opt() )
1232 aSizes.SetWidthSource( constraint.m_RuleName );
1233 }
1234 }
1235
1236 if( !found )
1237 {
1238 trackWidth = std::max( trackWidth, bds.GetCurrentTrackWidth() );
1239
1240 if( bds.UseNetClassTrack() )
1241 aSizes.SetWidthSource( _( "netclass 'Default'" ) );
1242 else if( trackWidth == bds.GetCurrentTrackWidth() )
1243 aSizes.SetWidthSource( _( "user choice" ) );
1244 }
1245
1246 aSizes.SetTrackWidth( trackWidth );
1249
1250 int viaDiameter = bds.m_ViasMinSize;
1251 int viaDrill = bds.m_MinThroughDrill;
1252
1253 PNS::VIA dummyVia, coupledVia;
1254
1255 if( aStartItem )
1256 {
1257 dummyVia.SetNet( aStartItem->Net() );
1258 coupledVia.SetNet( m_ruleResolver->DpCoupledNet( aStartItem->Net() ) );
1259 }
1260
1261 if( bds.UseNetClassVia() && aStartItem ) // netclass value
1262 {
1263 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_DIAMETER, &dummyVia, nullptr,
1264 m_startLayer, &constraint ) )
1265 {
1266 viaDiameter = std::max( viaDiameter, constraint.m_Value.PinnedOpt() );
1267 }
1268
1269 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_HOLE, &dummyVia, nullptr,
1270 m_startLayer, &constraint ) )
1271 {
1272 viaDrill = std::max( viaDrill, constraint.m_Value.PinnedOpt() );
1273 }
1274 }
1275 else
1276 {
1277 viaDiameter = bds.GetCurrentViaSize();
1278 viaDrill = bds.GetCurrentViaDrill();
1279 }
1280
1281 aSizes.SetViaDiameter( viaDiameter );
1282 aSizes.SetViaDrill( viaDrill );
1283
1284 int diffPairWidth = bds.m_TrackMinWidth;
1285 int diffPairGap = bds.m_MinClearance;
1286 int diffPairViaGap = bds.m_MinClearance;
1287
1288 aSizes.SetDiffPairWidthSource( _( "board minimum track width" ) );
1289 aSizes.SetDiffPairGapSource( _( "board minimum clearance" ) );
1290
1291 found = false;
1292
1293 // First try to pick up diff pair width from starting track, if enabled
1294 if( bds.m_UseConnectedTrackWidth && aStartItem )
1295 found = inheritTrackWidthAndDpGap( aStartItem, aStartPosition, &diffPairWidth, &diffPairGap );
1296
1297 // Next, pick up gap from netclass, and width also if we didn't get a starting width above
1298 if( bds.UseNetClassDiffPair() && aStartItem )
1299 {
1300 PNS::NET_HANDLE coupledNet = m_ruleResolver->DpCoupledNet( aStartItem->Net() );
1301
1302 PNS::SEGMENT dummyTrack;
1303 dummyTrack.SetEnds( aStartItem->Anchor( 0 ), aStartItem->Anchor( 0 ) );
1304 dummyTrack.SetLayer( m_startLayer );
1305 dummyTrack.SetNet( static_cast<NETINFO_ITEM*>( aStartItem->Net() ) );
1306
1307 PNS::SEGMENT coupledTrack;
1308 coupledTrack.SetEnds( aStartItem->Anchor( 0 ), aStartItem->Anchor( 0 ) );
1309 coupledTrack.SetLayer( m_startLayer );
1310 coupledTrack.SetNet( static_cast<NETINFO_ITEM*>( coupledNet ) );
1311
1312 if( !found
1313 && m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, &dummyTrack, &coupledTrack,
1314 m_startLayer, &constraint ) )
1315 {
1316 diffPairWidth = std::max( diffPairWidth, constraint.m_Value.Opt() );
1317
1318 if( diffPairWidth == constraint.m_Value.Opt() )
1319 aSizes.SetDiffPairWidthSource( constraint.m_RuleName );
1320 }
1321
1322 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP, &dummyTrack, &coupledTrack,
1323 m_startLayer, &constraint ) )
1324 {
1325 diffPairGap = std::max( diffPairGap, constraint.m_Value.PinnedOpt() );
1326 diffPairViaGap = std::max( diffPairViaGap, constraint.m_Value.PinnedOpt() );
1327
1328 if( diffPairGap == constraint.m_Value.Opt() )
1329 aSizes.SetDiffPairGapSource( constraint.m_RuleName );
1330 }
1331 }
1332 else
1333 {
1334 diffPairWidth = bds.GetCurrentDiffPairWidth();
1335 diffPairGap = bds.GetCurrentDiffPairGap();
1336 diffPairViaGap = bds.GetCurrentDiffPairViaGap();
1337
1338 aSizes.SetDiffPairWidthSource( _( "user choice" ) );
1339 aSizes.SetDiffPairGapSource( _( "user choice" ) );
1340 }
1341
1342 aSizes.SetDiffPairWidth( diffPairWidth );
1343 aSizes.SetDiffPairGap( diffPairGap );
1344 aSizes.SetDiffPairViaGap( diffPairViaGap );
1345 aSizes.SetDiffPairViaGapSameAsTraceGap( false );
1346
1347 int holeToHoleMin = bds.m_HoleToHoleMin;
1348
1349 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, &dummyVia, &dummyVia,
1350 UNDEFINED_LAYER, &constraint ) )
1351 {
1352 holeToHoleMin = constraint.m_Value.Min();
1353 }
1354
1355 aSizes.SetHoleToHole( holeToHoleMin );
1356
1357 if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE, &dummyVia, &coupledVia,
1358 UNDEFINED_LAYER, &constraint ) )
1359 {
1360 holeToHoleMin = constraint.m_Value.Min();
1361 }
1362
1363 aSizes.SetDiffPairHoleToHole( std::max( holeToHoleMin, aSizes.GetHoleToHole() ) );
1364
1365 // Seed with the board hole-to-copper minimum so a null DRC engine still constrains the gap,
1366 // matching how the hole-to-hole block above falls back to bds.m_HoleToHoleMin.
1367 int copperToHole = bds.m_HoleClearance;
1368
1369 // A net-scoped rule may bind the two vias asymmetrically, so query both orderings the way
1370 // the DRC copper-clearance provider tests each hole in turn.
1373 {
1374 if( m_ruleResolver->QueryConstraint( type, &dummyVia, &coupledVia, UNDEFINED_LAYER, &constraint ) )
1375 copperToHole = std::max( copperToHole, constraint.m_Value.Min() );
1376
1377 if( m_ruleResolver->QueryConstraint( type, &coupledVia, &dummyVia, UNDEFINED_LAYER, &constraint ) )
1378 copperToHole = std::max( copperToHole, constraint.m_Value.Min() );
1379 }
1380
1381 aSizes.SetDiffPairCopperToHole( copperToHole );
1382
1383 return true;
1384}
1385
1386
1387int PNS_KICAD_IFACE_BASE::StackupHeight( int aFirstLayer, int aSecondLayer ) const
1388{
1389 if( !m_board || !m_board->GetDesignSettings().m_UseHeightForLengthCalcs )
1390 return 0;
1391
1392 BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
1393
1394 return stackup.GetLayerDistance( GetBoardLayerFromPNSLayer( aFirstLayer ),
1395 GetBoardLayerFromPNSLayer( aSecondLayer ) );
1396}
1397
1398
1400{
1401 return m_board->DpCoupledNet( static_cast<NETINFO_ITEM*>( aNet ) );
1402}
1403
1404
1406{
1407 return m_routerIface->GetNetCode( aNet );
1408}
1409
1410
1412{
1413 return m_routerIface->GetNetName( aNet );
1414}
1415
1416
1418{
1419 wxString refName;
1420
1421 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
1422 refName = net->GetNetname();
1423
1424 wxString dummy1;
1425
1426 return m_board->MatchDpSuffix( refName, dummy1 );
1427}
1428
1429
1431 PNS::NET_HANDLE& aNetN )
1432{
1433 if( !aItem || !aItem->Net() )
1434 return false;
1435
1436 wxString netNameP = static_cast<NETINFO_ITEM*>( aItem->Net() )->GetNetname();
1437 wxString netNameN, netNameCoupled;
1438
1439 int r = m_board->MatchDpSuffix( netNameP, netNameCoupled );
1440
1441 if( r == 0 )
1442 {
1443 return false;
1444 }
1445 else if( r == 1 )
1446 {
1447 netNameN = netNameCoupled;
1448 }
1449 else
1450 {
1451 netNameN = netNameP;
1452 netNameP = netNameCoupled;
1453 }
1454
1455 PNS::NET_HANDLE netInfoP = m_board->FindNet( netNameP );
1456 PNS::NET_HANDLE netInfoN = m_board->FindNet( netNameN );
1457
1458 if( !netInfoP || !netInfoN )
1459 return false;
1460
1461 aNetP = netInfoP;
1462 aNetN = netInfoN;
1463
1464 return true;
1465}
1466
1467
1469{
1470public:
1473 m_iface( aIface ),
1474 m_view( nullptr ),
1475 m_items( nullptr ),
1476 m_depth( 0 )
1477 {}
1478
1480 {
1482
1483 for ( PNS::ITEM* item : m_clonedItems )
1484 {
1485 delete item;
1486 }
1487
1488 delete m_items;
1489 }
1490
1491 void SetView( KIGFX::VIEW* aView )
1492 {
1493 Clear();
1494 delete m_items;
1495 m_items = nullptr;
1496 m_view = aView;
1497
1498 if( m_view == nullptr )
1499 return;
1500
1501 if( m_view->GetGAL() )
1502 m_depth = m_view->GetGAL()->GetMinDepth();
1503
1505 m_items->SetLayer( LAYER_SELECT_OVERLAY ) ;
1506 m_view->Add( m_items );
1507 }
1508
1509 void AddPoint( const VECTOR2I& aP, const KIGFX::COLOR4D& aColor, int aSize, const wxString& aName = wxT( "" ),
1510 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1511
1512 {
1514
1515 sh.SetWidth( 10000 );
1516
1517 sh.Append( aP.x - aSize, aP.y - aSize );
1518 sh.Append( aP.x + aSize, aP.y + aSize );
1519 sh.Append( aP.x, aP.y );
1520 sh.Append( aP.x - aSize, aP.y + aSize );
1521 sh.Append( aP.x + aSize, aP.y - aSize );
1522
1523 AddShape( &sh, aColor, sh.Width(), aName, aSrcLoc );
1524 }
1525
1526 void AddItem( const PNS::ITEM* aItem, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1527 const wxString& aName = wxT( "" ),
1528 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1529 {
1530 if( !m_view || !aItem )
1531 return;
1532
1533 PNS::ITEM* cloned = aItem->Clone();
1534
1535 if( auto line = dyn_cast<PNS::LINE*>( cloned ))
1536 {
1537 line->ClearLinks();
1538 }
1539
1540 m_clonedItems.push_back( cloned );
1541
1542 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( cloned, m_iface, m_view );
1543
1544 pitem->SetColor( aColor.WithAlpha( 0.5 ) );
1545 pitem->SetWidth( aOverrideWidth );
1546 pitem->SetDepth( nextDepth() );
1547
1548 m_items->Add( pitem );
1549 m_view->Update( m_items );
1550 }
1551
1552 void AddShape( const BOX2I& aBox, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1553 const wxString& aName = wxT( "" ),
1554 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1555 {
1557 l.SetWidth( aOverrideWidth );
1558
1559 VECTOR2I o = aBox.GetOrigin();
1560 VECTOR2I s = aBox.GetSize();
1561
1562 l.Append( o );
1563 l.Append( o.x + s.x, o.y );
1564 l.Append( o.x + s.x, o.y + s.y );
1565 l.Append( o.x, o.y + s.y );
1566 l.Append( o );
1567
1568 AddShape( &l, aColor, aOverrideWidth, aName, aSrcLoc );
1569 }
1570
1571 void AddShape( const SHAPE* aShape, const KIGFX::COLOR4D& aColor, int aOverrideWidth = 0,
1572 const wxString& aName = wxT( "" ),
1573 const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1574 {
1575 if( !m_view || !aShape )
1576 return;
1577
1578 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( *aShape, m_iface, m_view );
1579
1580 pitem->SetColor( aColor.WithAlpha( 0.5 ) );
1581 pitem->SetWidth( aOverrideWidth );
1582 pitem->SetDepth( nextDepth() );
1583
1584 m_items->Add( pitem );
1585 m_view->Update( m_items );
1586 }
1587
1588 void Clear() override
1589 {
1590 if( m_view && m_items )
1591 {
1592 m_items->FreeItems();
1593 m_view->Update( m_items );
1594
1595 if( m_view->GetGAL() )
1596 m_depth = m_view->GetGAL()->GetMinDepth();
1597 }
1598
1599 for( PNS::ITEM* item : m_clonedItems )
1600 delete item;
1601
1602 m_clonedItems.clear();
1603 }
1604
1605 virtual void Message( const wxString& msg, const SRC_LOCATION_INFO& aSrcLoc = SRC_LOCATION_INFO() ) override
1606 {
1607 }
1608
1609private:
1610 double nextDepth()
1611 {
1612 // Use different depths so that the transculent shapes won't overwrite each other.
1613
1614 m_depth++;
1615
1616 if( m_depth >= 0 && m_view->GetGAL() )
1617 m_depth = m_view->GetGAL()->GetMinDepth();
1618
1619 return m_depth;
1620 }
1621
1625 std::vector<PNS::ITEM*> m_clonedItems;
1626
1627 double m_depth;
1628};
1629
1630
1635
1636
1638{
1639 m_ruleResolver = nullptr;
1640 m_board = nullptr;
1641 m_world = nullptr;
1642 m_debugDecorator = nullptr;
1643 m_startLayer = -1;
1644}
1645
1646
1648{
1649 m_tool = nullptr;
1650 m_view = nullptr;
1651 m_commitFlags = 0;
1652}
1653
1654
1656{
1657 for( ROUTER_PREVIEW_ITEM* item : m_previewItems )
1658 {
1659 if( m_view )
1660 m_view->Remove( item );
1661
1662 delete item;
1663 }
1664
1665 m_previewItems.clear();
1666}
1667
1668
1670{
1671 if( !aItem )
1672 return;
1673
1674 if( m_view )
1675 m_view->Add( aItem );
1676
1677 m_previewItems.push_back( aItem );
1678}
1679
1680
1686
1687
1692
1693
1694std::vector<std::unique_ptr<PNS::SOLID>> PNS_KICAD_IFACE_BASE::syncPad( PAD* aPad )
1695{
1696 std::vector<std::unique_ptr<PNS::SOLID>> solids;
1697 PNS_LAYER_RANGE layers( 0, aPad->BoardCopperLayerCount() - 1 );
1698 LSEQ lmsk = aPad->GetLayerSet().CuStack();
1699
1700 // ignore non-copper pads except for those with holes
1701 if( lmsk.empty() && aPad->GetDrillSize().x == 0 )
1702 return solids;
1703
1704 switch( aPad->GetAttribute() )
1705 {
1706 case PAD_ATTRIB::PTH:
1707 case PAD_ATTRIB::NPTH:
1708 break;
1709
1710 case PAD_ATTRIB::CONN:
1711 case PAD_ATTRIB::SMD:
1712 {
1713 bool is_copper = false;
1714
1715 if( !lmsk.empty() && aPad->GetAttribute() != PAD_ATTRIB::NPTH )
1716 {
1717 layers = SetLayersFromPCBNew( lmsk.front(), lmsk.front() );
1718 is_copper = true;
1719 }
1720
1721 if( !is_copper )
1722 return solids;
1723
1724 break;
1725 }
1726
1727 default:
1728 wxLogTrace( wxT( "PNS" ), wxT( "unsupported pad type 0x%x" ), aPad->GetAttribute() );
1729 return solids;
1730 }
1731
1732 auto makeSolidFromPadLayer =
1733 [&]( PCB_LAYER_ID aLayer )
1734 {
1735 // For FRONT_INNER_BACK mode, skip creating a SOLID for inner layers when there are
1736 // no inner layers (2-layer board). Otherwise PNS_LAYER_RANGE(1, 0) would be swapped
1737 // to (0, 1) and indexed on both F_Cu and B_Cu, causing incorrect collision checks.
1739 && aLayer != F_Cu && aLayer != B_Cu
1740 && aPad->BoardCopperLayerCount() <= 2 )
1741 {
1742 return;
1743 }
1744
1745 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
1746
1747 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
1748 solid->SetRoutable( false );
1749
1750 if( aPad->Padstack().Mode() == PADSTACK::MODE::CUSTOM )
1751 {
1752 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1753 }
1754 else if( aPad->Padstack().Mode() == PADSTACK::MODE::FRONT_INNER_BACK )
1755 {
1756 if( aLayer == F_Cu || aLayer == B_Cu )
1757 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
1758 else
1759 solid->SetLayers( PNS_LAYER_RANGE( 1, aPad->BoardCopperLayerCount() - 2 ) );
1760 }
1761 else
1762 {
1763 solid->SetLayers( layers );
1764 }
1765
1766 solid->SetNet( aPad->GetNet() );
1767 solid->SetParent( aPad );
1768 solid->SetPadToDie( aPad->GetPadToDieLength() );
1769 solid->SetPadToDieDelay( aPad->GetPadToDieDelay() );
1770 solid->SetOrientation( aPad->GetOrientation() );
1771
1772 if( aPad->IsFreePad() )
1773 solid->SetIsFreePad();
1774
1775 VECTOR2I wx_c = aPad->ShapePos( aLayer );
1776 VECTOR2I offset = aPad->GetOffset( aLayer );
1777
1778 VECTOR2I c( wx_c.x, wx_c.y );
1779
1780 RotatePoint( offset, aPad->GetOrientation() );
1781
1782 solid->SetPos( VECTOR2I( c.x - offset.x, c.y - offset.y ) );
1783 solid->SetOffset( VECTOR2I( offset.x, offset.y ) );
1784
1785 if( aPad->GetDrillSize().x > 0 )
1786 {
1787 solid->SetHole( new PNS::HOLE( aPad->GetEffectiveHoleShape()->Clone() ) );
1788 solid->Hole()->SetLayers( PNS_LAYER_RANGE( 0, aPad->BoardCopperLayerCount() - 1 ) );
1789 }
1790
1791 // We generate a single SOLID for a pad, so we have to treat it as ALWAYS_FLASHED and
1792 // then perform layer-specific flashing tests internally.
1793 const std::shared_ptr<SHAPE>& shape = aPad->GetEffectiveShape( aLayer, FLASHING::ALWAYS_FLASHED );
1794
1795 if( shape->HasIndexableSubshapes() && shape->GetIndexableSubshapeCount() == 1 )
1796 {
1797 std::vector<const SHAPE*> subshapes;
1798 shape->GetIndexableSubshapes( subshapes );
1799
1800 solid->SetShape( subshapes[0]->Clone() );
1801 }
1802 // For anything that's not a single shape we use a polygon. Multiple shapes have a tendency
1803 // to confuse the hull generator. https://gitlab.com/kicad/code/kicad/-/issues/15553
1804 else
1805 {
1806 const std::shared_ptr<SHAPE_POLY_SET>& poly = aPad->GetEffectivePolygon( aLayer, ERROR_OUTSIDE );
1807
1808 wxASSERT_MSG( poly->OutlineCount() <= 1, wxT( "PAD::GetEffectivePolygon() should have fractured "
1809 "the SHAPE_POLY_SET, leaving a single outline." ) );
1810
1811 if( poly->OutlineCount() )
1812 solid->SetShape( new SHAPE_SIMPLE( poly->Outline( 0 ) ) );
1813 }
1814
1815 if( !solid->Shape( 0 ) )
1816 return;
1817
1818 solids.emplace_back( std::move( solid ) );
1819 };
1820
1821 aPad->Padstack().ForEachUniqueLayer( makeSolidFromPadLayer );
1822
1823 return solids;
1824}
1825
1826
1827std::unique_ptr<PNS::SEGMENT> PNS_KICAD_IFACE_BASE::syncTrack( PCB_TRACK* aTrack )
1828{
1829 auto segment = std::make_unique<PNS::SEGMENT>( SEG( aTrack->GetStart(), aTrack->GetEnd() ), aTrack->GetNet() );
1830
1831 segment->SetWidth( aTrack->GetWidth() );
1832 segment->SetLayer( GetPNSLayerFromBoardLayer( aTrack->GetLayer() ) );
1833 segment->SetParent( aTrack );
1834
1835 if( aTrack->IsLocked() )
1836 segment->Mark( PNS::MK_LOCKED );
1837
1838 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aTrack->GetParentGroup() ) )
1839 {
1840 if( !generator->HasFlag( IN_EDIT ) )
1841 segment->Mark( PNS::MK_LOCKED );
1842 }
1843
1844 return segment;
1845}
1846
1847
1848std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE_BASE::syncArc( PCB_ARC* aArc )
1849{
1850 auto arc = std::make_unique<PNS::ARC>( SHAPE_ARC( aArc->GetStart(), aArc->GetMid(),
1851 aArc->GetEnd(), aArc->GetWidth() ),
1852 aArc->GetNet() );
1853
1854 arc->SetLayer( GetPNSLayerFromBoardLayer( aArc->GetLayer() ) );
1855 arc->SetParent( aArc );
1856
1857 if( aArc->IsLocked() )
1858 arc->Mark( PNS::MK_LOCKED );
1859
1860 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aArc->GetParentGroup() ) )
1861 {
1862 if( !generator->HasFlag( IN_EDIT ) )
1863 arc->Mark( PNS::MK_LOCKED );
1864 }
1865
1866 return arc;
1867}
1868
1869
1870std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( PCB_VIA* aVia )
1871{
1872 PCB_LAYER_ID top, bottom;
1873 aVia->LayerPair( &top, &bottom );
1874
1875 /*
1876 * NOTE about PNS via padstacks:
1877 *
1878 * PNS::VIA has no knowledge about how many layers are in the board, and there is no fixed
1879 * reference to the "back layer" in the PNS. That means that there is no way for a VIA to know
1880 * the difference between its bottom layer and the bottom layer of the overall board (i.e. if
1881 * the via is a blind/buried via). For this reason, PNS::VIA::STACK_MODE::FRONT_INNER_BACK
1882 * cannot be used for blind/buried vias. This mode will always assume that the via's top layer
1883 * is the "front" layer and the via's bottom layer is the "back" layer, but from KiCad's point
1884 * of view, at least at the moment, front/inner/back padstack mode is board-scoped, not
1885 * via-scoped, so a buried via would only use the inner layer size even if its padstack mode is
1886 * set to PADSTACK::MODE::FRONT_INNER_BACK and different sizes are defined for front or back.
1887 * For this kind of via, the PNS VIA stack mode will be set to NORMAL because effectively it has
1888 * the same size on every layer it exists on.
1889 */
1890
1891 auto via = std::make_unique<PNS::VIA>( aVia->GetPosition(),
1892 SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ),
1893 0,
1894 aVia->GetDrillValue(),
1895 aVia->GetNet(),
1896 aVia->GetViaType() );
1897 via->SetUnconnectedLayerMode( aVia->Padstack().UnconnectedLayerMode() );
1898
1899 auto syncDiameter =
1900 [&]( PCB_LAYER_ID aLayer )
1901 {
1902 via->SetDiameter( GetPNSLayerFromBoardLayer( aLayer ), aVia->GetWidth( aLayer ) );
1903 };
1904
1905 switch( aVia->Padstack().Mode() )
1906 {
1908 via->SetDiameter( 0, aVia->GetWidth( PADSTACK::TEMP_ALL_LAYERS ) );
1909 break;
1910
1912 if( aVia->GetViaType() == VIATYPE::BLIND || aVia->GetViaType() == VIATYPE::BURIED )
1913 {
1914 via->SetDiameter( 0, aVia->GetWidth( PADSTACK::INNER_LAYERS ) );
1915 }
1916 else
1917 {
1919 aVia->Padstack().ForEachUniqueLayer( syncDiameter );
1920 }
1921
1922 break;
1923
1925 via->SetStackMode( PNS::VIA::STACK_MODE::CUSTOM );
1926 aVia->Padstack().ForEachUniqueLayer( syncDiameter );
1927 }
1928
1929 via->SetParent( aVia );
1930
1931 if( aVia->IsLocked() )
1932 via->Mark( PNS::MK_LOCKED );
1933
1934 if( PCB_GENERATOR* generator = dynamic_cast<PCB_GENERATOR*>( aVia->GetParentGroup() ) )
1935 {
1936 if( !generator->HasFlag( IN_EDIT ) )
1937 via->Mark( PNS::MK_LOCKED );
1938 }
1939
1940 via->SetIsFree( aVia->GetIsFree() );
1941 via->SetHole( PNS::HOLE::MakeCircularHole( aVia->GetPosition(),
1942 aVia->GetDrillValue() / 2,
1943 SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) ) );
1944
1945 PCB_LAYER_ID primaryStart = aVia->GetPrimaryDrillStartLayer();
1946 PCB_LAYER_ID primaryEnd = aVia->GetPrimaryDrillEndLayer();
1947
1948 if( primaryStart != UNDEFINED_LAYER && primaryEnd != UNDEFINED_LAYER )
1949 via->SetHoleLayers( SetLayersFromPCBNew( primaryStart, primaryEnd ) );
1950 else
1951 via->SetHoleLayers( SetLayersFromPCBNew( aVia->TopLayer(), aVia->BottomLayer() ) );
1952
1953 via->SetHolePostMachining( aVia->GetFrontPostMachining() );
1954 via->SetSecondaryDrill( aVia->GetSecondaryDrillSize() );
1955
1956 std::optional<PNS_LAYER_RANGE> secondaryLayers;
1957
1960 {
1961 secondaryLayers = SetLayersFromPCBNew( aVia->GetSecondaryDrillStartLayer(),
1962 aVia->GetSecondaryDrillEndLayer() );
1963 }
1964
1965 via->SetSecondaryHoleLayers( secondaryLayers );
1966 via->SetSecondaryHolePostMachining( std::nullopt );
1967
1968 return via;
1969}
1970
1971
1972bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE* aZone, SHAPE_POLY_SET* aBoardOutline )
1973{
1974 // If this ever becomes multi-threaded, we'll need to lose the 'static's. But for now they
1975 // will help performance a tiny bit.
1976 static wxString msg;
1977 static SHAPE_POLY_SET polyStorage;
1978 SHAPE_POLY_SET* poly = &polyStorage;
1979
1980 if( !aZone->GetIsRuleArea() || !aZone->HasKeepoutParametersSet() )
1981 return false;
1982
1983 LSET layers = aZone->GetLayerSet();
1984
1985 // GetBoardOutline() is expensive. Only use it in the router where we have to.
1986 if( aZone->GetParentFootprint() )
1987 polyStorage = aZone->GetBoardOutline();
1988 else
1989 poly = aZone->Outline();
1990
1991 poly->CacheTriangulation();
1992
1993 if( !poly->IsTriangulationUpToDate() )
1994 {
1995 UNITS_PROVIDER unitsProvider( pcbIUScale, GetUnits() );
1996 msg.Printf( _( "%s is malformed." ), aZone->GetItemDescription( &unitsProvider, true ) );
1997
1998 KIDIALOG dlg( nullptr, msg, KIDIALOG::KD_WARNING );
1999 dlg.ShowDetailedText( _( "This zone cannot be handled by the router.\n"
2000 "Please verify it is not a self-intersecting polygon." ) );
2001 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
2002 dlg.ShowModal();
2003
2004 return false;
2005 }
2006
2007 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, m_board->GetCopperLayerCount() ) )
2008 {
2009 if( !layers[ layer ] )
2010 continue;
2011
2012 for( unsigned int polyId = 0; polyId < poly->TriangulatedPolyCount(); polyId++ )
2013 {
2014 const SHAPE_POLY_SET::TRIANGULATED_POLYGON* tri = poly->TriangulatedPolygon( polyId );
2015
2016 for( size_t i = 0; i < tri->GetTriangleCount(); i++)
2017 {
2018 VECTOR2I a, b, c;
2019 tri->GetTriangle( i, a, b, c );
2020 SHAPE_SIMPLE* triShape = new SHAPE_SIMPLE;
2021
2022 triShape->Append( a );
2023 triShape->Append( b );
2024 triShape->Append( c );
2025
2026 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2027
2028 solid->SetLayer( GetPNSLayerFromBoardLayer( layer ) );
2029 solid->SetNet( nullptr );
2030 solid->SetParent( aZone );
2031 solid->SetShape( triShape );
2032 solid->SetIsCompoundShapePrimitive();
2033 solid->SetRoutable( false );
2034
2035 aWorld->Add( std::move( solid ) );
2036 }
2037 }
2038 }
2039
2040 return true;
2041}
2042
2043
2045{
2046 if( !IsKicadCopperLayer( aLayer ) )
2047 return false;
2048
2049 if( aItem->Type() == PCB_FIELD_T && !static_cast<PCB_FIELD*>( aItem )->IsVisible() )
2050 return false;
2051
2052 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2053 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
2054
2055 solid->SetLayer( GetPNSLayerFromBoardLayer( aLayer ) );
2056 solid->SetNet( nullptr );
2057 solid->SetParent( aItem );
2058 solid->SetShape( shape ); // takes ownership
2059 solid->SetRoutable( false );
2060
2061 SHAPE_POLY_SET cornerBuffer;
2062
2063 aItem->TransformShapeToPolygon( cornerBuffer, aItem->GetLayer(), 0, aItem->GetMaxError(), ERROR_OUTSIDE );
2064
2065 cornerBuffer.Simplify();
2066
2067 if( !cornerBuffer.OutlineCount() )
2068 return false;
2069
2070 for( const VECTOR2I& pt : cornerBuffer.Outline( 0 ).CPoints() )
2071 shape->Append( pt );
2072
2073 aWorld->Add( std::move( solid ) );
2074
2075 return true;
2076}
2077
2078
2080{
2081 if( !IsKicadCopperLayer( aDimension->GetLayer() ) )
2082 return false;
2083
2084 auto addPolysToWorld =
2085 [&]( const SHAPE_POLY_SET& aPolys )
2086 {
2087 for( int ii = 0; ii < aPolys.OutlineCount(); ++ii )
2088 {
2089 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2090 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
2091
2092 solid->SetLayer( GetPNSLayerFromBoardLayer( aDimension->GetLayer() ) );
2093 solid->SetNet( nullptr );
2094 solid->SetParent( aDimension );
2095 solid->SetShape( shape ); // takes ownership
2096 solid->SetRoutable( false );
2097
2098 for( const VECTOR2I& pt : aPolys.Outline( ii ).CPoints() )
2099 shape->Append( pt );
2100
2101 aWorld->Add( std::move( solid ) );
2102 }
2103 };
2104
2105 SHAPE_POLY_SET cornerBuffer;
2106
2107 aDimension->TransformShapeToPolygon( cornerBuffer, aDimension->GetLayer(), 0,
2108 aDimension->GetMaxError(), ERROR_OUTSIDE );
2109
2110 cornerBuffer.Simplify();
2111
2112 if( cornerBuffer.OutlineCount() )
2113 addPolysToWorld( cornerBuffer );
2114
2115 // Footprints can have hidden dimensions
2116 if( aDimension->IsVisible() && !aDimension->GetText().IsEmpty() )
2117 {
2118 SHAPE_POLY_SET textBuffer;
2119
2120 aDimension->PCB_TEXT::TransformShapeToPolygon( textBuffer, aDimension->GetLayer(), 0,
2121 aDimension->GetMaxError(), ERROR_OUTSIDE );
2122
2123 textBuffer.Simplify();
2124
2125 if( textBuffer.OutlineCount() )
2126 addPolysToWorld( textBuffer );
2127 }
2128
2129 return cornerBuffer.OutlineCount() || !aDimension->GetText().IsEmpty();
2130}
2131
2132
2134{
2135 if( aItem->GetLayer() == Edge_Cuts
2136 || aItem->GetLayer() == Margin
2137 || IsKicadCopperLayer( aItem->GetLayer() ) )
2138 {
2139 std::vector<SHAPE*> shapes = aItem->MakeEffectiveShapesWithLineEndings( aItem->GetEffectiveWidth() );
2140
2141 for( SHAPE* shape : shapes )
2142 {
2143 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2144
2145 if( aItem->GetLayer() == Edge_Cuts || aItem->GetLayer() == Margin )
2146 {
2147 solid->SetLayers( PNS_LAYER_RANGE( 0, m_board->GetCopperLayerCount() - 1 ) );
2148 solid->SetRoutable( false );
2149 }
2150 else
2151 {
2152 solid->SetLayer( GetPNSLayerFromBoardLayer( aItem->GetLayer() ) );
2153 solid->SetRoutable( aItem->Type() != PCB_TABLECELL_T );
2154 }
2155
2156 if( aItem->GetLayer() == Edge_Cuts )
2157 {
2158 switch( shape->Type() )
2159 {
2160 case SH_SEGMENT: static_cast<SHAPE_SEGMENT*>( shape )->SetWidth( 0 ); break;
2161 case SH_ARC: static_cast<SHAPE_ARC*>( shape )->SetWidth( 0 ); break;
2162 case SH_LINE_CHAIN: static_cast<SHAPE_LINE_CHAIN*>( shape )->SetWidth( 0 ); break;
2163 default: /* remaining shapes don't have width */ break;
2164 }
2165 }
2166
2167 solid->SetAnchorPoints( aItem->GetConnectionPoints() );
2168 solid->SetNet( aItem->GetNet() );
2169 solid->SetParent( aItem );
2170 solid->SetShape( shape ); // takes ownership
2171
2172 if( shapes.size() > 1 )
2173 solid->SetIsCompoundShapePrimitive();
2174
2175 aWorld->Add( std::move( solid ) );
2176 }
2177
2178 return true;
2179 }
2180
2181 return false;
2182}
2183
2184
2186{
2187 if( IsKicadCopperLayer( aBarcode->GetLayer() ) )
2188 {
2189 SHAPE_POLY_SET cornerBuffer;
2190
2191 aBarcode->GetBoundingHull( cornerBuffer, aBarcode->GetLayer(), 0, aBarcode->GetMaxError(), ERROR_OUTSIDE );
2192
2193 if( !cornerBuffer.OutlineCount() )
2194 return false;
2195
2196 for( int ii = 0; ii < cornerBuffer.OutlineCount(); ++ii )
2197 {
2198 std::unique_ptr<PNS::SOLID> solid = std::make_unique<PNS::SOLID>();
2199 SHAPE_SIMPLE* shape = new SHAPE_SIMPLE;
2200
2201 solid->SetLayer( GetPNSLayerFromBoardLayer( aBarcode->GetLayer() ) );
2202 solid->SetNet( nullptr );
2203 solid->SetParent( aBarcode );
2204 solid->SetShape( shape ); // takes ownership
2205 solid->SetRoutable( false );
2206
2207 for( const VECTOR2I& pt : cornerBuffer.Outline( ii ).CPoints() )
2208 shape->Append( pt );
2209
2210 aWorld->Add( std::move( solid ) );
2211 }
2212
2213 return true;
2214 }
2215
2216 return false;
2217}
2218
2219
2221{
2222 m_board = aBoard;
2223 wxLogTrace( wxT( "PNS" ), wxT( "m_board = %p" ), m_board );
2224}
2225
2226
2228{
2229 return ::IsCopperLayer( GetBoardLayerFromPNSLayer( aPNSLayer ) );
2230}
2231
2232
2233
2235{
2236 return ::IsCopperLayer( aKicadLayer );
2237}
2238
2239
2241{
2242 if( !m_view )
2243 return false;
2244
2245 for( int i = aLayer.Start(); i <= aLayer.End(); i++ )
2246 {
2247 if( m_view->IsLayerVisible( GetBoardLayerFromPNSLayer( i ) ) )
2248 return true;
2249 }
2250
2251 return false;
2252}
2253
2254
2255bool PNS_KICAD_IFACE_BASE::IsFlashedOnLayer( const PNS::ITEM* aItem, int aLayer ) const
2256{
2258 if( aLayer < 0 )
2259 return true;
2260
2261 if( aItem->Parent() )
2262 {
2263 switch( aItem->Parent()->Type() )
2264 {
2265 case PCB_VIA_T:
2266 {
2267 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
2268
2269 return via->FlashLayer( GetBoardLayerFromPNSLayer( aLayer ) );
2270 }
2271
2272 case PCB_PAD_T:
2273 {
2274 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
2275
2276 return pad->FlashLayer( GetBoardLayerFromPNSLayer( aLayer ) );
2277 }
2278
2279 default:
2280 break;
2281 }
2282 }
2283
2284 if( aItem->OfKind( PNS::ITEM::VIA_T ) )
2285 return static_cast<const PNS::VIA*>( aItem )->ConnectsLayer( aLayer );
2286
2287 return aItem->Layers().Overlaps( aLayer );
2288}
2289
2290
2292{
2293 PNS_LAYER_RANGE test = aItem->Layers().Intersection( aLayer );
2294
2295 if( aItem->Parent() )
2296 {
2297 switch( aItem->Parent()->Type() )
2298 {
2299 case PCB_VIA_T:
2300 {
2301 const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem->Parent() );
2302
2303 for( int layer = test.Start(); layer <= test.End(); ++layer )
2304 {
2305 if( via->FlashLayer( GetBoardLayerFromPNSLayer( layer ) ) )
2306 return true;
2307 }
2308
2309 return false;
2310 }
2311
2312 case PCB_PAD_T:
2313 {
2314 const PAD* pad = static_cast<const PAD*>( aItem->Parent() );
2315
2316 for( int layer = test.Start(); layer <= test.End(); ++layer )
2317 {
2318 if( pad->FlashLayer( GetBoardLayerFromPNSLayer( layer ) ) )
2319 return true;
2320 }
2321
2322 return false;
2323 }
2324
2325 default:
2326 break;
2327 }
2328 }
2329
2330 if( aItem->OfKind( PNS::ITEM::VIA_T ) )
2331 {
2332 const PNS::VIA* via = static_cast<const PNS::VIA*>( aItem );
2333
2334 for( int layer = test.Start(); layer <= test.End(); ++layer )
2335 {
2336 if( via->ConnectsLayer( layer ) )
2337 return true;
2338 }
2339
2340 return false;
2341 }
2342
2343 return test.Start() <= test.End();
2344}
2345
2346
2348{
2349 // by default, all items are visible (new ones created by the router have parent == NULL
2350 // as they have not been committed yet to the BOARD)
2351 if( !m_view || !aItem->Parent() )
2352 return true;
2353
2354 BOARD_ITEM* item = aItem->Parent();
2355 bool isOnVisibleLayer = true;
2356 RENDER_SETTINGS* settings = m_view->GetPainter()->GetSettings();
2357
2358 if( settings->GetHighContrast() )
2359 isOnVisibleLayer = item->IsOnLayer( settings->GetPrimaryHighContrastLayer() );
2360
2361 if( m_view->IsVisible( item ) && isOnVisibleLayer )
2362 {
2363 for( PCB_LAYER_ID layer : item->GetLayerSet() )
2364 {
2365 if( item->ViewGetLOD( layer, m_view ) < m_view->GetScale() )
2366 return true;
2367 }
2368 }
2369
2370 // Items hidden in the router are not hidden on the board
2371 if( m_hiddenItems.find( item ) != m_hiddenItems.end() )
2372 return true;
2373
2374 return false;
2375}
2376
2377
2379{
2380 if( !m_board )
2381 {
2382 wxLogTrace( wxT( "PNS" ), wxT( "No board attached, aborting sync." ) );
2383 return;
2384 }
2385
2386 int worstClearance = m_board->GetMaxClearanceValue();
2387
2388 m_world = aWorld;
2389
2390 for( BOARD_ITEM* gitem : m_board->Drawings() )
2391 {
2392 switch( gitem->Type() )
2393 {
2394 case PCB_SHAPE_T:
2395 case PCB_TEXTBOX_T:
2396 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( gitem ) );
2397 break;
2398
2399 case PCB_TEXT_T:
2400 syncTextItem( aWorld, static_cast<PCB_TEXT*>( gitem ), gitem->GetLayer() );
2401 break;
2402
2403 case PCB_TABLE_T:
2404 case PCB_DRILL_CHART_T:
2405 syncTextItem( aWorld, static_cast<PCB_TABLE*>( gitem ), gitem->GetLayer() );
2406 break;
2407
2408 case PCB_BARCODE_T:
2409 syncBarcode( aWorld, static_cast<PCB_BARCODE*>( gitem ) );
2410 break;
2411
2412 case PCB_DIM_ALIGNED_T:
2413 case PCB_DIM_CENTER_T:
2414 case PCB_DIM_RADIAL_T:
2416 case PCB_DIM_LEADER_T:
2417 syncDimension( aWorld, static_cast<PCB_DIMENSION_BASE*>( gitem ) );
2418 break;
2419
2420 case PCB_REFERENCE_IMAGE_T: // ignore
2421 case PCB_TARGET_T:
2422 case PCB_GRID_ITEM_T:
2423 break;
2424
2425 default:
2426 UNIMPLEMENTED_FOR( gitem->GetClass() );
2427 break;
2428 }
2429 }
2430
2431 SHAPE_POLY_SET buffer;
2432 SHAPE_POLY_SET* boardOutline = nullptr;
2433
2434 if( m_board->GetBoardPolygonOutlines( buffer, true ) )
2435 boardOutline = &buffer;
2436
2437 for( ZONE* zone : m_board->Zones() )
2438 {
2439 syncZone( aWorld, zone, boardOutline );
2440 }
2441
2442 for( FOOTPRINT* footprint : m_board->Footprints() )
2443 {
2444 for( PAD* pad : footprint->Pads() )
2445 {
2446 std::vector<std::unique_ptr<PNS::SOLID>> solids = syncPad( pad );
2447
2448 for( std::unique_ptr<PNS::SOLID>& solid : solids )
2449 aWorld->Add( std::move( solid ) );
2450
2451 std::optional<int> clearanceOverride = pad->GetClearanceOverrides( nullptr );
2452
2453 if( clearanceOverride.has_value() )
2454 worstClearance = std::max( worstClearance, clearanceOverride.value() );
2455
2456 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
2457 {
2458 std::unique_ptr<SHAPE> hole;
2459 hole.reset( pad->GetEffectiveHoleShape()->Clone() );
2460 aWorld->AddEdgeExclusion( std::move( hole ) );
2461 }
2462 }
2463
2464 syncTextItem( aWorld, &footprint->Reference(), footprint->Reference().GetLayer() );
2465 syncTextItem( aWorld, &footprint->Value(), footprint->Value().GetLayer() );
2466
2467 for( ZONE* zone : footprint->Zones() )
2468 syncZone( aWorld, zone, boardOutline );
2469
2470 for( PCB_FIELD* field : footprint->GetFields() )
2471 syncTextItem( aWorld, static_cast<PCB_TEXT*>( field ), field->GetLayer() );
2472
2473 for( BOARD_ITEM* item : footprint->GraphicalItems() )
2474 {
2475 switch( item->Type() )
2476 {
2477 case PCB_SHAPE_T:
2478 case PCB_TEXTBOX_T:
2479 syncGraphicalItem( aWorld, static_cast<PCB_SHAPE*>( item ) );
2480 break;
2481
2482 case PCB_TEXT_T:
2483 syncTextItem( aWorld, static_cast<PCB_TEXT*>( item ), item->GetLayer() );
2484 break;
2485
2486 case PCB_TABLE_T:
2487 syncTextItem( aWorld, static_cast<PCB_TABLE*>( item ), item->GetLayer() );
2488 break;
2489
2490 case PCB_BARCODE_T:
2491 syncBarcode( aWorld, static_cast<PCB_BARCODE*>( item ) );
2492 break;
2493
2494 case PCB_DIM_ALIGNED_T:
2495 case PCB_DIM_CENTER_T:
2496 case PCB_DIM_RADIAL_T:
2498 case PCB_DIM_LEADER_T:
2499 syncDimension( aWorld, static_cast<PCB_DIMENSION_BASE*>( item ) );
2500 break;
2501
2502 case PCB_REFERENCE_IMAGE_T: // ignore
2503 break;
2504
2505 default:
2506 UNIMPLEMENTED_FOR( item->GetClass() );
2507 break;
2508 }
2509 }
2510 }
2511
2512 for( PCB_TRACK* t : m_board->Tracks() )
2513 {
2514 KICAD_T type = t->Type();
2515
2516 if( type == PCB_TRACE_T )
2517 {
2518 if( std::unique_ptr<PNS::SEGMENT> segment = syncTrack( t ) )
2519 aWorld->Add( std::move( segment ), true );
2520 }
2521 else if( type == PCB_ARC_T )
2522 {
2523 if( std::unique_ptr<PNS::ARC> arc = syncArc( static_cast<PCB_ARC*>( t ) ) )
2524 aWorld->Add( std::move( arc ), true );
2525 }
2526 else if( type == PCB_VIA_T )
2527 {
2528 if( std::unique_ptr<PNS::VIA> via = syncVia( static_cast<PCB_VIA*>( t ) ) )
2529 aWorld->Add( std::move( via ) );
2530 }
2531 }
2532
2533 // NB: if this were ever to become a long-lived object we would need to dirty its
2534 // clearance cache here....
2535 delete m_ruleResolver;
2537
2539 aWorld->SetMaxClearance( worstClearance + m_ruleResolver->ClearanceEpsilon() );
2540}
2541
2542
2544{
2545 for( BOARD_ITEM* item : m_hiddenItems )
2546 m_view->SetVisible( item, true );
2547
2548 m_hiddenItems.clear();
2549
2551
2552 if( m_debugDecorator )
2553 m_debugDecorator->Clear();
2554}
2555
2556
2561
2562
2563void PNS_KICAD_IFACE::DisplayItem( const PNS::ITEM* aItem, int aClearance, bool aEdit, int aFlags )
2564{
2565 if( aItem->IsVirtual() )
2566 return;
2567
2568 if( ZONE* zone = dynamic_cast<ZONE*>( aItem->Parent() ) )
2569 {
2570 if( zone->GetIsRuleArea() )
2571 aFlags |= PNS_SEMI_SOLID;
2572 }
2573
2574 // Note: SEGMENT_T is used for placed tracks; LINE_T is used for the routing head
2576 static int tracksOrVias = tracks | PNS::ITEM::VIA_T;
2577
2578 bool showClearance = false;
2579
2580 if( aClearance >= 0 )
2581 {
2582 PCBNEW_SETTINGS* settings =
2583 static_cast<PCBNEW_SETTINGS*>( m_tool->GetManager()->GetSettings() );
2584
2585 switch( settings->m_Display.m_TrackClearance )
2586 {
2589 showClearance = aItem->OfKind( tracksOrVias );
2590 break;
2591
2593 showClearance = aItem->OfKind( tracksOrVias ) && !aEdit;
2594 break;
2595
2596 case SHOW_WHILE_ROUTING:
2597 showClearance = aItem->OfKind( tracks ) && !aEdit;
2598 break;
2599
2600 default:
2601 break;
2602 }
2603 }
2604
2605 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aItem, this, m_view, aFlags,
2607
2608 // A colliding item always shows its halo so the user sees why routing was refused
2609 const bool itemCollision = pitem->IsCollisionFlagged();
2610
2611 addPreviewItem( pitem );
2612
2613 // A separate item puts the halo on LAYER_ROUTER_PREVIEW_SHADOW, behind board copper
2614 if( aClearance > 0 && ( showClearance || itemCollision ) )
2615 {
2616 ROUTER_PREVIEW_ITEM* shadow = new ROUTER_PREVIEW_ITEM( aItem, this, m_view, aFlags,
2618 shadow->SetClearance( aClearance );
2619
2620 addPreviewItem( shadow );
2621 }
2622}
2623
2624
2625void PNS_KICAD_IFACE::DisplayPathLine( const SHAPE_LINE_CHAIN& aLine, int aImportance )
2626{
2627 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aLine, this, m_view );
2629
2630 COLOR4D color;
2631
2632 if( aImportance >= 1 )
2633 color = COLOR4D( 1.0, 1.0, 0.0, 0.6 );
2634 else if( aImportance == 0 )
2635 color = COLOR4D( 0.7, 0.7, 0.7, 0.6 );
2636
2637 pitem->SetColor( color );
2638
2639 addPreviewItem( pitem );
2640}
2641
2642
2644{
2645 ROUTER_PREVIEW_ITEM* pitem = new ROUTER_PREVIEW_ITEM( aRatline, this, m_view );
2646
2647 KIGFX::RENDER_SETTINGS* renderSettings = m_view->GetPainter()->GetSettings();
2648 KIGFX::PCB_RENDER_SETTINGS* rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( renderSettings );
2649 bool colorByNet = rs->GetNetColorMode() != NET_COLOR_MODE::OFF;
2650 COLOR4D defaultColor = rs->GetColor( nullptr, LAYER_RATSNEST );
2651 COLOR4D color = defaultColor;
2652
2653 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
2654 std::set<int> highlightedNets = rs->GetHighlightNetCodes();
2655 std::map<int, KIGFX::COLOR4D>& netColors = rs->GetNetColorMap();
2656 int netCode = -1;
2657
2658 if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
2659 netCode = net->GetNetCode();
2660
2661 const NETCLASS* nc = nullptr;
2662 const NET_SETTINGS* netSettings = connectivity->GetNetSettings();
2663
2664 if( connectivity->HasNetNameForNetCode( netCode ) )
2665 {
2666 const wxString& netName = connectivity->GetNetNameForNetCode( netCode );
2667
2668 if( netSettings && netSettings->HasEffectiveNetClass( netName ) )
2669 nc = netSettings->GetCachedEffectiveNetClass( netName ).get();
2670 }
2671
2672 if( colorByNet && netColors.count( netCode ) )
2673 color = netColors.at( netCode );
2674 else if( colorByNet && nc && nc->HasPcbColor() )
2675 color = nc->GetPcbColor();
2676 else
2677 color = defaultColor;
2678
2679 if( color == COLOR4D::UNSPECIFIED )
2680 color = defaultColor;
2681
2682 pitem->SetColor( color.Brightened( 0.5 ).WithAlpha( std::min( 1.0, color.a + 0.4 ) ) );
2683
2684 addPreviewItem( pitem );
2685}
2686
2687
2689{
2690 BOARD_ITEM* parent = aItem->Parent();
2691
2692 if( parent )
2693 {
2694 if( m_view->IsVisible( parent ) )
2695 m_hiddenItems.insert( parent );
2696
2697 m_view->SetVisible( parent, false );
2698 m_view->Update( parent, KIGFX::APPEARANCE );
2699
2700 for( ZONE* td : m_board->Zones() )
2701 {
2702 if( td->IsTeardropArea()
2703 && td->GetBoundingBox().Intersects( aItem->Parent()->GetBoundingBox() )
2704 && td->Outline()->Collide( aItem->Shape( td->GetLayer() ) ) )
2705 {
2706 m_view->SetVisible( td, false );
2707 m_view->Update( td, KIGFX::APPEARANCE );
2708 }
2709 }
2710 }
2711}
2712
2713
2717
2718
2720{
2721 BOARD_ITEM* parent = aItem->Parent();
2722
2723 if( aItem->OfKind( PNS::ITEM::SOLID_T ) && parent->Type() == PCB_PAD_T )
2724 {
2725 PAD* pad = static_cast<PAD*>( parent );
2726 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2727
2728 m_fpOffsets[ pad ].p_old = pos;
2729 return;
2730 }
2731
2732 if( parent )
2733 {
2734 if( EDA_GROUP* group = parent->GetParentGroup() )
2735 m_itemGroups[parent] = group;
2736
2737 m_commit->Remove( parent );
2738 }
2739}
2740
2741
2745
2746
2748{
2749 BOARD_ITEM* board_item = aItem->Parent();
2750
2751 switch( aItem->Kind() )
2752 {
2753 case PNS::ITEM::ARC_T:
2754 {
2755 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
2756 PCB_ARC* arc_board = static_cast<PCB_ARC*>( board_item );
2757 const SHAPE_ARC* arc_shape = static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) );
2758
2759 aCommit.Modify( arc_board );
2760
2761 arc_board->SetStart( VECTOR2I( arc_shape->GetP0() ) );
2762 arc_board->SetEnd( VECTOR2I( arc_shape->GetP1() ) );
2763 arc_board->SetMid( VECTOR2I( arc_shape->GetArcMid() ) );
2764 arc_board->SetWidth( arc->Width() );
2765 break;
2766 }
2767
2769 {
2770 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
2771 PCB_TRACK* track = static_cast<PCB_TRACK*>( board_item );
2772 const SEG& s = seg->Seg();
2773
2774 aCommit.Modify( track );
2775
2776 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
2777 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
2778 track->SetWidth( seg->Width() );
2779 break;
2780 }
2781
2782 case PNS::ITEM::VIA_T:
2783 {
2784 PCB_VIA* via_board = static_cast<PCB_VIA*>( board_item );
2785 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
2786
2787 aCommit.Modify( via_board );
2788
2789 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
2790 via_board->SetWidth( PADSTACK::TEMP_ALL_LAYERS, via->Diameter( 0 ) );
2791 via_board->SetDrill( via->Drill() );
2792 via_board->SetNet( static_cast<NETINFO_ITEM*>( via->Net() ) );
2793 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
2794 via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
2795 via_board->SetIsFree( via->IsFree() );
2796 // A via holds its copper span in the primary drill layers, so this call is the only
2797 // writer of both; a write back from the PNS hole layers can only repeat or corrupt it
2798 via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
2799 GetBoardLayerFromPNSLayer( via->Layers().End() ) );
2800
2801 via_board->SetFrontPostMachining( via->HolePostMachining() );
2802 via_board->SetSecondaryDrillSize( via->SecondaryDrill() );
2803
2804 if( std::optional<PNS_LAYER_RANGE> secondaryLayers = via->SecondaryHoleLayers() )
2805 {
2806 via_board->SetSecondaryDrillStartLayer( GetBoardLayerFromPNSLayer( secondaryLayers->Start() ) );
2807 via_board->SetSecondaryDrillEndLayer( GetBoardLayerFromPNSLayer( secondaryLayers->End() ) );
2808 }
2809 else
2810 {
2813 }
2814
2815 break;
2816 }
2817
2818 case PNS::ITEM::SOLID_T:
2819 {
2820 if( aItem->Parent()->Type() == PCB_PAD_T )
2821 {
2822 PAD* pad = static_cast<PAD*>( aItem->Parent() );
2823 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2824
2825 // Don't add to commit; we'll add the parent footprints when processing the m_fpOffsets
2826
2827 m_fpOffsets[pad].p_old = pad->GetPosition();
2828 m_fpOffsets[pad].p_new = pos;
2829 }
2830 break;
2831 }
2832
2833 default:
2834 aCommit.Modify( aItem->Parent() );
2835 break;
2836 }
2837}
2838
2839
2841{
2842 wxCHECK_RET( m_commit, wxS( "Cannot update a router item without a commit" ) );
2843 modifyBoardItem( aItem, *m_commit );
2844}
2845
2846
2848{
2849}
2850
2851
2853{
2854 BOARD_CONNECTED_ITEM* newBoardItem = nullptr;
2855 NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aItem->Net() );
2856
2857 if( !net )
2859
2860 switch( aItem->Kind() )
2861 {
2862 case PNS::ITEM::ARC_T:
2863 {
2864 PNS::ARC* arc = static_cast<PNS::ARC*>( aItem );
2865 PCB_ARC* new_arc = new PCB_ARC( m_board, static_cast<const SHAPE_ARC*>( arc->Shape( -1 ) ) );
2866 new_arc->SetWidth( arc->Width() );
2867 new_arc->SetLayer( GetBoardLayerFromPNSLayer( arc->Layers().Start() ) );
2868 new_arc->SetNet( net );
2869
2870 if( aItem->GetSourceItem() && aItem->GetSourceItem()->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
2871 {
2872 PCB_TRACK* sourceTrack = static_cast<PCB_TRACK*>( aItem->GetSourceItem() );
2873 new_arc->SetHasSolderMask( sourceTrack->HasSolderMask() );
2874 new_arc->SetLocalSolderMaskMargin( sourceTrack->GetLocalSolderMaskMargin() );
2875 }
2876
2877 newBoardItem = new_arc;
2878 break;
2879 }
2880
2882 {
2883 PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
2884 PCB_TRACK* track = new PCB_TRACK( m_board );
2885 const SEG& s = seg->Seg();
2886 track->SetStart( VECTOR2I( s.A.x, s.A.y ) );
2887 track->SetEnd( VECTOR2I( s.B.x, s.B.y ) );
2888 track->SetWidth( seg->Width() );
2889 track->SetLayer( GetBoardLayerFromPNSLayer( seg->Layers().Start() ) );
2890 track->SetNet( net );
2891
2892 if( aItem->GetSourceItem() && aItem->GetSourceItem()->IsType( { PCB_TRACE_T, PCB_ARC_T } ) )
2893 {
2894 PCB_TRACK* sourceTrack = static_cast<PCB_TRACK*>( aItem->GetSourceItem() );
2895 track->SetHasSolderMask( sourceTrack->HasSolderMask() );
2896 track->SetLocalSolderMaskMargin( sourceTrack->GetLocalSolderMaskMargin() );
2897 }
2898
2899 newBoardItem = track;
2900 break;
2901 }
2902
2903 case PNS::ITEM::VIA_T:
2904 {
2905 PCB_VIA* via_board = new PCB_VIA( m_board );
2906 PNS::VIA* via = static_cast<PNS::VIA*>( aItem );
2907 via_board->SetPosition( VECTOR2I( via->Pos().x, via->Pos().y ) );
2908 via_board->SetWidth( PADSTACK::TEMP_ALL_LAYERS, via->Diameter( 0 ) );
2909 via_board->SetDrill( via->Drill() );
2910 via_board->SetNet( net );
2911 via_board->SetViaType( via->ViaType() ); // MUST be before SetLayerPair()
2912 via_board->Padstack().SetUnconnectedLayerMode( via->UnconnectedLayerMode() );
2913 via_board->SetIsFree( via->IsFree() );
2914 // A via holds its copper span in the primary drill layers, so this call is the only
2915 // writer of both; a write back from the PNS hole layers can only repeat or corrupt it
2916 via_board->SetLayerPair( GetBoardLayerFromPNSLayer( via->Layers().Start() ),
2917 GetBoardLayerFromPNSLayer( via->Layers().End() ) );
2918
2919 via_board->SetFrontPostMachining( via->HolePostMachining() );
2920 via_board->SetSecondaryDrillSize( via->SecondaryDrill() );
2921
2922 if( std::optional<PNS_LAYER_RANGE> secondaryLayers = via->SecondaryHoleLayers() )
2923 {
2924 via_board->SetSecondaryDrillStartLayer( GetBoardLayerFromPNSLayer( secondaryLayers->Start() ) );
2925 via_board->SetSecondaryDrillEndLayer( GetBoardLayerFromPNSLayer( secondaryLayers->End() ) );
2926 }
2927 else
2928 {
2931 }
2932
2933 if( aItem->GetSourceItem() && aItem->GetSourceItem()->Type() == PCB_VIA_T )
2934 {
2935 PCB_VIA* sourceVia = static_cast<PCB_VIA*>( aItem->GetSourceItem() );
2936 via_board->SetFrontTentingMode( sourceVia->GetFrontTentingMode() );
2937 via_board->SetBackTentingMode( sourceVia->GetBackTentingMode() );
2938 }
2939
2940 newBoardItem = via_board;
2941 break;
2942 }
2943
2944 case PNS::ITEM::SOLID_T:
2945 {
2946 PAD* pad = static_cast<PAD*>( aItem->Parent() );
2947 VECTOR2I pos = static_cast<PNS::SOLID*>( aItem )->Pos();
2948
2949 m_fpOffsets[pad].p_new = pos;
2950 return nullptr;
2951 }
2952
2953 default:
2954 return nullptr;
2955 }
2956
2957 if( net->GetNetCode() <= 0 )
2958 {
2959 NETINFO_ITEM* newNetInfo = newBoardItem->GetNet();
2960
2961 newNetInfo->SetParent( m_board );
2962 newNetInfo->SetNetClass( m_board->GetDesignSettings().m_NetSettings->GetDefaultNetclass() );
2963 }
2964
2965 if( newBoardItem )
2966 {
2967 if( aItem->IsLocked() )
2968 newBoardItem->SetLocked( true );
2969
2970 if( BOARD_ITEM* src = aItem->GetSourceItem() )
2971 {
2972 if( !m_itemGroups.contains( src ) )
2973 {
2974 if( EDA_GROUP* group = src->GetParentGroup() )
2975 m_itemGroups[src] = group;
2976 }
2977
2978 if( m_itemGroups.contains( src ) )
2979 m_replacementMap[src].push_back( newBoardItem );
2980 }
2981 else
2982 {
2983 // This is a new item, which goes in the entered group (if any)
2984 m_replacementMap[ENTERED_GROUP_MAGIC_NUMBER].push_back( newBoardItem );
2985 }
2986 }
2987
2988 return newBoardItem;
2989}
2990
2991
2993{
2994 BOARD_CONNECTED_ITEM* boardItem = createBoardItem( aItem );
2995
2996 if( boardItem )
2997 {
2998 aItem->SetParent( boardItem );
2999 boardItem->ClearFlags();
3000
3001 m_commit->Add( boardItem );
3002 }
3003}
3004
3005
3007{
3008 PCB_SELECTION_TOOL* selTool = m_tool->GetManager()->GetTool<PCB_SELECTION_TOOL>();
3009 std::set<FOOTPRINT*> processedFootprints;
3010
3011 EraseView();
3012
3013 for( const auto& [ pad, fpOffset ] : m_fpOffsets )
3014 {
3015 VECTOR2I offset = fpOffset.p_new - fpOffset.p_old;
3016
3017 if( m_independentPads.count( pad ) )
3018 {
3019 m_commit->Modify( pad );
3020 pad->Move( offset );
3021 continue;
3022 }
3023
3024 FOOTPRINT* footprint = pad->GetParentFootprint();
3025 VECTOR2I p_orig = footprint->GetPosition();
3026 VECTOR2I p_new = p_orig + offset;
3027
3028 if( processedFootprints.find( footprint ) != processedFootprints.end() )
3029 continue;
3030
3031 processedFootprints.insert( footprint );
3032 m_commit->Modify( footprint );
3033 footprint->SetPosition( p_new );
3034 }
3035
3036 m_fpOffsets.clear();
3037 m_independentPads.clear();
3038
3039 for( const auto& [ src, items ] : m_replacementMap )
3040 {
3041 EDA_GROUP* group = nullptr;
3042
3043 if( src == ENTERED_GROUP_MAGIC_NUMBER )
3044 group = selTool ? selTool->GetEnteredGroup() : nullptr;
3045 else if( auto it = m_itemGroups.find( src ); it != m_itemGroups.end() )
3046 group = it->second;
3047
3048 if( group )
3049 {
3050 m_commit->Modify( group->AsEdaItem(), nullptr, RECURSE_MODE::NO_RECURSE );
3051
3052 for( BOARD_ITEM* bi : items )
3053 group->AddItem( bi );
3054 }
3055 }
3056
3057 m_itemGroups.clear();
3058 m_replacementMap.clear();
3059
3060 m_commit->Push( _( "Routing" ), m_commitFlags | SKIP_ENTERED_GROUP );
3061 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
3062}
3063
3064
3066{
3067 return static_cast<EDA_UNITS>( m_tool->GetManager()->GetSettings()->m_System.units );
3068}
3069
3070
3072{
3073 wxLogTrace( wxT( "PNS" ), wxT( "SetView %p" ), aView );
3074
3076 m_view = aView;
3077
3078 delete m_debugDecorator;
3079
3080 auto dec = new PNS_PCBNEW_DEBUG_DECORATOR( this );
3081 m_debugDecorator = dec;
3082
3083 dec->SetDebugEnabled( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics );
3084
3085 if( ADVANCED_CFG::GetCfg().m_ShowRouterDebugGraphics )
3086 dec->SetView( m_view );
3087}
3088
3089
3091{
3092 if( aNet )
3093 return static_cast<NETINFO_ITEM*>( aNet )->GetNetCode();
3094 else
3095 return -1;
3096}
3097
3098
3100{
3101 if( aNet )
3102 return static_cast<NETINFO_ITEM*>( aNet )->GetNetname();
3103 else
3104 return wxEmptyString;
3105}
3106
3107
3109{
3110 wxLogTrace( wxT( "PNS" ), wxT( "Update-net %s" ), GetNetName( aNet ) );
3111}
3112
3113
3118
3119
3124
3125
3127{
3128 m_tool = aTool;
3129 m_commit = std::make_unique<BOARD_COMMIT>( m_tool );
3130}
3131
3132
3134{
3135 if( aLayer < 0 || aLayer >= m_board->GetCopperLayerCount() )
3137
3138 if( aLayer == 0 )
3139 return F_Cu;
3140
3141 if( aLayer == m_board->GetCopperLayerCount() - 1 )
3142 return B_Cu;
3143
3144 return static_cast<PCB_LAYER_ID>( ( aLayer + 1 ) * 2 );
3145}
3146
3147
3149{
3150 if( aLayer < 0 )
3151 return -1;
3152
3153 if( aLayer == F_Cu )
3154 return 0;
3155
3156 if( aLayer == B_Cu )
3157 return m_board->GetCopperLayerCount() - 1;
3158
3159 return ( aLayer / 2 ) - 1;
3160}
3161
3163 long long& aExtraLength, long long& aExtraDelay ) const
3164{
3165 aExtraLength = 0;
3166 aExtraDelay = 0;
3167 if( !m_board || !aNetP || !aNetN )
3168 return false;
3169
3170 auto* netP = static_cast<NETINFO_ITEM*>( aNetP );
3171 auto* netN = static_cast<NETINFO_ITEM*>( aNetN );
3172 wxString sig = netP->GetNetChain();
3173 if( sig.IsEmpty() || sig != netN->GetNetChain() )
3174 return false;
3175
3176 // Build the set of net codes to exclude (the nets the caller is already accounting for).
3177 std::set<int> exclude;
3178 exclude.insert( netP->GetNetCode() );
3179 if( netP != netN )
3180 exclude.insert( netN->GetNetCode() );
3181
3182 // Sum routed length/delay of every other net in the chain.
3183 for( NETINFO_ITEM* net : m_board->GetNetInfo() )
3184 {
3185 if( net->GetNetChain() != sig )
3186 continue;
3187 if( exclude.count( net->GetNetCode() ) )
3188 continue;
3189
3190 PCB_TRACK* rep = nullptr;
3191
3192 for( BOARD_ITEM* bi : m_board->Tracks() )
3193 {
3194 if( auto tr = dynamic_cast<PCB_TRACK*>( bi ) )
3195 {
3196 if( tr->GetNetCode() == net->GetNetCode() )
3197 {
3198 rep = tr;
3199 break;
3200 }
3201 }
3202 }
3203
3204 if( rep )
3205 {
3206 int count = 0; double trk = 0, pad = 0, tDelay = 0, padDelay = 0;
3207 std::tie( count, trk, pad, tDelay, padDelay ) = m_board->GetTrackLength( *rep );
3208 aExtraLength += KiROUND<double, long long>( trk + pad );
3209
3210 if( tDelay > 0.0 || padDelay > 0.0 )
3211 aExtraDelay += KiROUND<double, long long>( tDelay + padDelay );
3212 }
3213 }
3214
3215 // Chain is valid; return true even if no sibling nets carry routed length yet so the
3216 // placer applies the full chain budget to the net being routed first.
3217 return true;
3218}
3219
3221 long long& aExtraLength, long long& aExtraDelay ) const
3222{
3223 return PNS_KICAD_IFACE_BASE::GetSignalAggregate( aNetP, aNetN, aExtraLength, aExtraDelay );
3224}
3225
3226
3228{
3229 if( !m_board || !aNet )
3230 return 0;
3231
3232 auto* ni = static_cast<NETINFO_ITEM*>( aNet );
3233
3234 for( BOARD_ITEM* bi : m_board->Tracks() )
3235 {
3236 if( auto tr = dynamic_cast<PCB_TRACK*>( bi ) )
3237 {
3238 if( tr->GetNetCode() == ni->GetNetCode() )
3239 {
3240 int count = 0; double trk = 0, pad = 0, tDelay = 0, padDelay = 0;
3241 std::tie( count, trk, pad, tDelay, padDelay ) = m_board->GetTrackLength( *tr );
3242 return KiROUND<double, long long>( trk + pad );
3243 }
3244 }
3245 }
3246
3247 return 0;
3248}
3249
3250
3251void PNS_KICAD_IFACE_BASE::RemoveBoardConnected( const std::vector<const PNS::ITEM*>& aJoined,
3252 std::set<PNS::ITEM*>& aItems ) const
3253{
3254 if( !m_board )
3255 return;
3256
3257 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_board->GetConnectivity();
3258 std::set<const BOARD_ITEM*> boardJoined;
3259
3260 for( const PNS::ITEM* item : aJoined )
3261 {
3262 BOARD_ITEM* parent = item->Parent();
3263
3264 if( !parent || !parent->IsConnected() || !boardJoined.insert( parent ).second )
3265 continue;
3266
3267 for( BOARD_CONNECTED_ITEM* connected :
3268 connectivity->GetConnectedItems( static_cast<BOARD_CONNECTED_ITEM*>( parent ) ) )
3269 {
3270 boardJoined.insert( connected );
3271 }
3272 }
3273
3274 std::erase_if( aItems,
3275 [&]( PNS::ITEM* aItem )
3276 {
3277 return aItem->Parent() && boardJoined.count( aItem->Parent() );
3278 } );
3279}
3280
3281
3283{
3284 if( !m_board || !aItem || !aItem->Net() )
3285 return true;
3286
3287 PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( aItem->Layer() );
3288 const SHAPE* shape = aItem->Shape( aItem->Layer() );
3289
3290 if( layer == UNDEFINED_LAYER || !shape )
3291 return true;
3292
3293 const BOX2I bbox = shape->BBox();
3294
3295 // Teardrops hug existing joints and carry no connectivity of their own
3296 auto touches = [&]( const ZONE* aZone )
3297 {
3298 return !aZone->GetIsRuleArea() && !aZone->IsTeardropArea() && aZone->GetNet() == aItem->Net()
3299 && aZone->IsOnLayer( layer ) && aZone->GetBoundingBox().Intersects( bbox )
3300 && aZone->Outline()->Collide( shape );
3301 };
3302
3303 for( const ZONE* zone : m_board->Zones() )
3304 {
3305 if( touches( zone ) )
3306 return true;
3307 }
3308
3309 for( const FOOTPRINT* footprint : m_board->Footprints() )
3310 {
3311 for( const ZONE* zone : footprint->Zones() )
3312 {
3313 if( touches( zone ) )
3314 return true;
3315 }
3316 }
3317
3318 return false;
3319}
3320
3321
3326
3327
3332
3333
3335 const PNS::SOLID* aEndPad, const NETCLASS* aNetClass )
3336{
3337 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems = GetLengthDelayCalculationItems( aLine, aNetClass );
3338
3339 const PAD* startPad = nullptr;
3340 const PAD* endPad = nullptr;
3341
3342 if( aStartPad )
3343 startPad = static_cast<PAD*>( aStartPad->Parent() );
3344
3345 if( aEndPad )
3346 endPad = static_cast<PAD*>( aEndPad->Parent() );
3347
3348 constexpr PATH_OPTIMISATIONS opts = {
3349 .OptimiseVias = false,
3350 .MergeTracks = false,
3351 .OptimiseTracesInPads = false,
3352 .InferViaInPad = true
3353 };
3354 const BOARD* board = GetBoard();
3355 return board->GetLengthCalculation()->CalculateLength( lengthItems, opts, startPad, endPad );
3356}
3357
3358
3360 const PNS::SOLID* aEndPad, const NETCLASS* aNetClass )
3361{
3362 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems = GetLengthDelayCalculationItems( aLine, aNetClass );
3363
3364 const PAD* startPad = nullptr;
3365 const PAD* endPad = nullptr;
3366
3367 if( aStartPad )
3368 startPad = static_cast<PAD*>( aStartPad->Parent() );
3369
3370 if( aEndPad )
3371 endPad = static_cast<PAD*>( aEndPad->Parent() );
3372
3373 constexpr PATH_OPTIMISATIONS opts = {
3374 .OptimiseVias = false,
3375 .MergeTracks = false,
3376 .OptimiseTracesInPads = false,
3377 .InferViaInPad = true
3378 };
3379 const BOARD* board = GetBoard();
3380 return board->GetLengthCalculation()->CalculateDelay( lengthItems, opts, startPad, endPad );
3381}
3382
3383
3384int64_t PNS_KICAD_IFACE_BASE::CalculateLengthForDelay( int64_t aDesiredDelay, const int aWidth,
3385 const bool aIsDiffPairCoupled, const int aDiffPairCouplingGap,
3386 const int aPNSLayer, const NETCLASS* aNetClass )
3387{
3389 ctx.NetClass = aNetClass;
3390 ctx.Width = aWidth;
3391 ctx.IsDiffPairCoupled = aIsDiffPairCoupled;
3392 ctx.DiffPairCouplingGap = aDiffPairCouplingGap;
3393 ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer );
3394
3395 const BOARD* board = GetBoard();
3396 return board->GetLengthCalculation()->CalculateLengthForDelay( aDesiredDelay, ctx );
3397}
3398
3399
3401 bool aIsDiffPairCoupled, int aDiffPairCouplingGap,
3402 int aPNSLayer, const NETCLASS* aNetClass )
3403{
3405 ctx.NetClass = aNetClass;
3406 ctx.Width = aWidth;
3407 ctx.IsDiffPairCoupled = aIsDiffPairCoupled;
3408 ctx.DiffPairCouplingGap = aDiffPairCouplingGap;
3409 ctx.Layer = GetBoardLayerFromPNSLayer( aPNSLayer );
3410
3411 const BOARD* board = GetBoard();
3413}
3414
3415
3416std::vector<LENGTH_DELAY_CALCULATION_ITEM>
3418{
3419 std::vector<LENGTH_DELAY_CALCULATION_ITEM> lengthItems;
3420
3421 for( int idx = 0; idx < aLine.Size(); idx++ )
3422 {
3423 const PNS::ITEM* lineItem = aLine[idx];
3424
3425 if( const PNS::LINE* l = dyn_cast<const PNS::LINE*>( lineItem ) )
3426 {
3428 item.SetLine( l->CLine() );
3429
3430 const PCB_LAYER_ID layer = GetBoardLayerFromPNSLayer( lineItem->Layer() );
3431 item.SetLayers( layer );
3432 item.SetEffectiveNetClass( aNetClass );
3433 item.SetWidth( l->Width() );
3434
3435 lengthItems.emplace_back( std::move( item ) );
3436 }
3437 else if( lineItem->OfKind( PNS::ITEM::VIA_T ) && idx > 0 && idx < aLine.Size() - 1 )
3438 {
3439 const int layerPrev = aLine[idx - 1]->Layer();
3440 const int layerNext = aLine[idx + 1]->Layer();
3441 const PCB_LAYER_ID pcbLayerPrev = GetBoardLayerFromPNSLayer( layerPrev );
3442 const PCB_LAYER_ID pcbLayerNext = GetBoardLayerFromPNSLayer( layerNext );
3443
3444 if( layerPrev != layerNext )
3445 {
3447 item.SetVia( static_cast<PCB_VIA*>( lineItem->GetSourceItem() ) );
3448 item.SetLayers( pcbLayerPrev, pcbLayerNext ); // TODO: BUG IS HERE!!!
3449 item.SetEffectiveNetClass( aNetClass );
3450 lengthItems.emplace_back( std::move( item ) );
3451 }
3452 }
3453 }
3454
3455 return lengthItems;
3456}
@ ERROR_OUTSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
#define SKIP_ENTERED_GROUP
@ OFF
Net (and netclass) colors are not shown.
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
NETINFO_ITEM * GetNet() const
Return NETINFO_ITEM object for a given item.
Container for design settings for a BOARD object.
bool UseNetClassVia() const
Return true if netclass values should be used to obtain appropriate via size.
bool UseNetClassTrack() const
Return true if netclass values should be used to obtain appropriate track width.
bool UseNetClassDiffPair() const
Return true if netclass values should be used to obtain appropriate diff pair dimensions.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:85
void SetLocked(bool aLocked) override
Definition board_item.h:427
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition board_item.h:173
bool IsLocked() const override
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const
Convert the item shape to a closed polygon.
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
Definition board_item.h:418
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:355
virtual bool HasDrilledHole() const
Definition board_item.h:213
virtual int BoardCopperLayerCount() const
Return the total number of copper layers for the board that this item resides on.
virtual bool IsOnCopperLayer() const
Definition board_item.h:190
int GetMaxError() const
Manage layers needed to make a physical board.
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
LENGTH_DELAY_CALCULATION * GetLengthCalculation() const
Returns the track length calculator.
Definition board.h:1679
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:234
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr const SizeVec & GetSize() const
Definition box2.h:203
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:294
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:400
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
wxString GetName() const
Definition drc_rule.h:162
SEVERITY GetSeverity() const
Definition drc_rule.h:181
const MINOPTMAX< int > & GetValue() const
Definition drc_rule.h:129
MINOPTMAX< int > m_Value
Definition drc_rule.h:204
bool GetOption(OPTIONS option) const
Definition drc_rule.h:193
DRC_RULE * GetParentRule() const
Definition drc_rule.h:147
bool IsNull() const
Definition drc_rule.h:122
Design Rule Checker object that performs all the DRC tests.
Definition drc_engine.h:129
bool IsNetTieExclusion(int aTrackNetCode, PCB_LAYER_ID aTrackLayer, const VECTOR2I &aCollisionPos, BOARD_ITEM *aCollidingItem)
Check if the given collision between a track and another item occurs during the track's entry into a ...
bool IsImplicit() const
Definition drc_rule.h:70
DRC_IMPLICIT_SOURCE GetImplicitSource() const
Definition drc_rule.h:74
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:43
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:270
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:116
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:160
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:214
std::vector< SHAPE * > MakeEffectiveShapesWithLineEndings(int aLineWidth) const
Make effective geometry for the shape body shortened for line endings plus the line-ending geometry i...
virtual int GetEffectiveWidth() const
Definition eda_shape.h:166
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:118
virtual bool IsVisible() const
Definition eda_text.h:226
void SetPosition(const VECTOR2I &aPos) override
bool IsNetTie() const
Definition footprint.h:525
VECTOR2I GetPosition() const override
Definition footprint.h:379
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
@ KD_WARNING
Definition kidialog.h:43
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:51
int ShowModal() override
Definition kidialog.cpp:89
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition color4d.h:309
double a
Alpha component.
Definition color4d.h:394
COLOR4D Brightened(double aFactor) const
Return a color that is brighter by a given factor, without modifying object.
Definition color4d.h:265
PCB specific render settings.
Definition pcb_painter.h:94
NET_COLOR_MODE GetNetColorMode() const
COLOR4D GetColor(const VIEW_ITEM *aItem, int aLayer) const override
Returns the color that should be used to draw the specific VIEW_ITEM on the specific layer using curr...
std::map< int, KIGFX::COLOR4D > & GetNetColorMap()
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > & GetHighlightNetCodes() const
Return the netcode of currently highlighted net.
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
Extend VIEW_ITEM by possibility of grouping items into a single object.
Definition view_group.h:39
virtual double ViewGetLOD(int aLayer, const VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition view_item.h:151
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:68
Lightweight class which holds a pad, via, or a routed trace outline.
void SetLine(const SHAPE_LINE_CHAIN &aLine)
Sets the source SHAPE_LINE_CHAIN of this item.
void SetVia(const PCB_VIA *aVia)
Sets the VIA associated with this item.
void SetWidth(const int aWidth)
Sets the line width.
void SetEffectiveNetClass(const NETCLASS *aNetClass)
Sets the effective net class for the item.
void SetLayers(const PCB_LAYER_ID aStart, const PCB_LAYER_ID aEnd=PCB_LAYER_ID::UNDEFINED_LAYER)
Sets the first and last layers associated with this item.
int64_t CalculateLengthForDelay(int64_t aDesiredDelay, const TUNING_PROFILE_GEOMETRY_CONTEXT &aCtx) const
Calculates the length of track required for the given delay in a specific geometry context.
int64_t CalculatePropagationDelayForShapeLineChain(const SHAPE_LINE_CHAIN &aShape, const TUNING_PROFILE_GEOMETRY_CONTEXT &aCtx) const
Gets the propagation delay for the given shape line chain.
int64_t CalculateDelay(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical propagation delay of the given items.
int64_t CalculateLength(std::vector< LENGTH_DELAY_CALCULATION_ITEM > &aItems, PATH_OPTIMISATIONS aOptimisations, const PAD *aStartPad=nullptr, const PAD *aEndPad=nullptr) const
Calculates the electrical length of the given items.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:259
T Min() const
Definition minoptmax.h:29
void SetMin(T v)
Definition minoptmax.h:41
T PinnedOpt() const
Definition minoptmax.h:32
bool HasMin() const
Definition minoptmax.h:37
T Opt() const
Definition minoptmax.h:31
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:44
COLOR4D GetPcbColor(bool aIsForSave=false) const
Definition netclass.h:214
bool HasPcbColor() const
Definition netclass.h:213
Handle the data for a net.
Definition netinfo.h:50
const wxString & GetNetChain() const
Definition netinfo.h:122
const wxString & GetNetname() const
Definition netinfo.h:110
int GetNetCode() const
Definition netinfo.h:104
void SetParent(BOARD *aParent)
Definition netinfo.h:176
void SetNetClass(const std::shared_ptr< NETCLASS > &aNetClass)
static NETINFO_ITEM * OrphanedItem()
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
Definition netinfo.h:289
NET_SETTINGS stores various net-related settings in a project context.
bool HasEffectiveNetClass(const wxString &aNetName) const
Determines if an effective netclass for the given net name has been cached.
std::shared_ptr< NETCLASS > GetCachedEffectiveNetClass(const wxString &aNetName) const
Returns an already cached effective netclass for the given net name.
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
void SetUnconnectedLayerMode(UNCONNECTED_LAYER_MODE aMode)
Definition padstack.h:376
UNCONNECTED_LAYER_MODE UnconnectedLayerMode() const
Definition padstack.h:375
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
@ CUSTOM
Shapes can be defined on arbitrary layers.
Definition padstack.h:172
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:171
MODE Mode() const
Definition padstack.h:346
static constexpr PCB_LAYER_ID TEMP_ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:176
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:182
Definition pad.h:61
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:557
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition pad.cpp:1361
PAD_ATTRIB GetAttribute() const
Definition pad.h:560
VECTOR2I GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.cpp:837
VECTOR2I GetDrillSize() const
Definition pad.h:320
int GetPadToDieDelay() const
Definition pad.h:581
const PADSTACK & Padstack() const
Definition pad.h:331
bool IsFreePad() const
Definition pad.cpp:609
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.cpp:1795
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:1239
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition pad.cpp:1252
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1906
int GetPadToDieLength() const
Definition pad.h:578
DISPLAY_OPTIONS m_Display
void SetMid(const VECTOR2I &aMid)
Definition pcb_track.h:299
const VECTOR2I & GetMid() const
Definition pcb_track.h:300
void GetBoundingHull(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Add two rectangular polygons separately bounding the barcode's symbol and the barcode's text.
Abstract dimension API.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
The selection tool: currently supports:
PCB_GROUP * GetEnteredGroup()
std::vector< VECTOR2I > GetConnectionPoints() const
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:70
void SetHasSolderMask(bool aVal)
Definition pcb_track.h:121
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:94
bool HasSolderMask() const
Definition pcb_track.h:122
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:97
void SetLocalSolderMaskMargin(std::optional< int > aMargin)
Definition pcb_track.h:124
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_track.h:125
const VECTOR2I & GetStart() const
Definition pcb_track.h:98
const VECTOR2I & GetEnd() const
Definition pcb_track.h:95
virtual void SetWidth(int aWidth)
Definition pcb_track.h:91
virtual int GetWidth() const
Definition pcb_track.h:92
bool GetIsFree() const
Check if the via is a free via (as opposed to one created on a track by the router).
Definition pcb_track.h:860
PCB_LAYER_ID BottomLayer() const
VECTOR2I GetPosition() const override
Definition pcb_track.h:603
const PADSTACK & Padstack() const
Definition pcb_track.h:431
void SetFrontTentingMode(TENTING_MODE aMode)
TENTING_MODE GetFrontTentingMode() const
std::optional< int > GetSecondaryDrillSize() const
void SetSecondaryDrillStartLayer(PCB_LAYER_ID aLayer)
std::optional< PAD_DRILL_POST_MACHINING_MODE > GetFrontPostMachining() const
Definition pcb_track.h:727
void SetDrill(int aDrill)
Definition pcb_track.h:801
PCB_LAYER_ID GetSecondaryDrillEndLayer() const
Definition pcb_track.h:834
void SetBackTentingMode(TENTING_MODE aMode)
void SetIsFree(bool aFree=true)
Definition pcb_track.h:861
PCB_LAYER_ID GetPrimaryDrillStartLayer() const
Definition pcb_track.h:721
void SetFrontPostMachining(const std::optional< PAD_DRILL_POST_MACHINING_MODE > &aMode)
void SetSecondaryDrillEndLayer(PCB_LAYER_ID aLayer)
PCB_LAYER_ID GetPrimaryDrillEndLayer() const
Definition pcb_track.h:724
void SetPosition(const VECTOR2I &aPoint) override
Definition pcb_track.h:604
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
For a via m_layer contains the top layer, the other layer is in m_bottomLayer/.
int GetWidth() const override
void SetViaType(VIATYPE aViaType)
Definition pcb_track.h:423
TENTING_MODE GetBackTentingMode() const
PCB_LAYER_ID TopLayer() const
void SetSecondaryDrillSize(const VECTOR2I &aSize)
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
VIATYPE GetViaType() const
Definition pcb_track.h:422
PCB_LAYER_ID GetSecondaryDrillStartLayer() const
Definition pcb_track.h:831
void SetWidth(int aWidth) override
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Return the 2 layers used by the via (the via actually uses all layers between these 2 layers)
int Width() const override
Definition pns_arc.h:88
const SHAPE * Shape(int aLayer) const override
Return the geometrical shape of the item.
Definition pns_arc.h:78
Basic class for a differential pair.
int GuessMostLikelyGap() const
static HOLE * MakeCircularHole(const VECTOR2I &pos, int radius, PNS_LAYER_RANGE aLayers)
Definition pns_hole.cpp:131
bool Empty() const
Definition pns_itemset.h:90
int Size() const
ITEM_SET & ExcludeItem(const ITEM *aItem)
ITEM_SET & FilterKinds(int aKindMask, bool aInvert=false)
std::vector< ITEM * > & Items()
Definition pns_itemset.h:95
Base class for PNS router board items.
Definition pns_item.h:98
BOARD_ITEM * Parent() const
Definition pns_item.h:199
bool IsFreePad() const
Definition pns_item.h:292
virtual ITEM * ParentPadVia() const
Definition pns_item.h:297
virtual const SHAPE * Shape(int aLayer) const
Return the geometrical shape of the item.
Definition pns_item.h:246
const PNS_LAYER_RANGE & Layers() const
Definition pns_item.h:212
virtual NET_HANDLE Net() const
Definition pns_item.h:210
PnsKind Kind() const
Return the type (kind) of the item.
Definition pns_item.h:173
virtual ITEM * Clone() const =0
Return a deep copy of the item.
void SetNet(NET_HANDLE aNet)
Definition pns_item.h:209
BOARD_ITEM * GetSourceItem() const
Definition pns_item.h:202
virtual int Layer() const
Definition pns_item.h:216
void SetLayer(int aLayer)
Definition pns_item.h:215
void SetParent(BOARD_ITEM *aParent)
Definition pns_item.h:191
bool OfKind(int aKindMask) const
Definition pns_item.h:181
bool IsVirtual() const
Definition pns_item.h:299
virtual VECTOR2I Anchor(int n) const
Definition pns_item.h:272
virtual const SHAPE_LINE_CHAIN Hull(int aClearance=0, int aWalkaroundThickness=0, int aLayer=-1) const
Definition pns_item.h:164
virtual BOARD_ITEM * BoardItem() const
Definition pns_item.h:207
bool IsLocked() const
Definition pns_item.h:282
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
const ITEM_SET & CLinks() const
Definition pns_joint.h:312
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition pns_line.h:62
const SHAPE_LINE_CHAIN & CLine() const
Definition pns_line.h:149
int Width() const
Return line width.
Definition pns_line.h:169
Keep the router "world" - i.e.
Definition pns_node.h:244
void SetMaxClearance(int aClearance)
Set the worst-case clearance between any pair of items.
Definition pns_node.h:282
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.
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
Definition pns_node.cpp:753
void SetRuleResolver(RULE_RESOLVER *aFunc)
Assign a clearance resolution function object.
Definition pns_node.h:288
void AddEdgeExclusion(std::unique_ptr< SHAPE > aShape)
Definition pns_node.cpp:797
const ITEM_OWNER * Owner() const
Return the owner of this item, or NULL if there's none.
Definition pns_item.h:72
virtual NET_HANDLE DpCoupledNet(NET_HANDLE aNet)=0
const SEG & Seg() const
void SetEnds(const VECTOR2I &a, const VECTOR2I &b)
int Width() const override
Definition pns_segment.h:96
void SetTrackWidth(int aWidth)
void SetBoardMinTrackWidth(int aWidth)
void SetDiffPairViaGapSameAsTraceGap(bool aEnable)
void SetDiffPairWidth(int aWidth)
void SetDiffPairCopperToHole(int aCopperToHole)
void SetDiffPairWidthSource(const wxString &aSource)
void SetDiffPairGapSource(const wxString &aSource)
void SetDiffPairGap(int aGap)
void SetHoleToHole(int aHoleToHole)
void SetViaDrill(int aDrill)
void SetDiffPairViaGap(int aGap)
void SetDiffPairHoleToHole(int aHoleToHole)
void SetMinClearance(int aClearance)
void SetClearance(int aClearance)
void SetViaDiameter(int aDiameter)
void SetClearanceSource(const wxString &aSource)
void SetWidthSource(const wxString &aSource)
void SetTrackWidthIsExplicit(bool aIsExplicit)
const DIFF_PAIR AssembleDiffPair(SEGMENT *aStart)
bool syncGraphicalItem(PNS::NODE *aWorld, PCB_SHAPE *aItem)
void AddItem(PNS::ITEM *aItem) override
bool syncDimension(PNS::NODE *aWorld, PCB_DIMENSION_BASE *aDimension)
virtual EDA_UNITS GetUnits() const
PNS::DEBUG_DECORATOR * m_debugDecorator
void SetDebugDecorator(PNS::DEBUG_DECORATOR *aDec)
bool syncZone(PNS::NODE *aWorld, ZONE *aZone, SHAPE_POLY_SET *aBoardOutline)
void SetBoard(BOARD *aBoard)
long long int CalculateRoutedPathLength(const PNS::ITEM_SET &aLine, const PNS::SOLID *aStartPad, const PNS::SOLID *aEndPad, const NETCLASS *aNetClass) override
int64_t CalculateRoutedPathDelay(const PNS::ITEM_SET &aLine, const PNS::SOLID *aStartPad, const PNS::SOLID *aEndPad, const NETCLASS *aNetClass) override
void RemoveBoardConnected(const std::vector< const PNS::ITEM * > &aJoined, std::set< PNS::ITEM * > &aItems) const override
Remove from aItems every item the board already joins to one of aJoined through objects the router do...
std::unique_ptr< PNS::ARC > syncArc(PCB_ARC *aArc)
void RemoveItem(PNS::ITEM *aItem) override
bool GetSignalAggregate(PNS::NET_HANDLE aNetP, PNS::NET_HANDLE aNetN, long long &aExtraLength, long long &aExtraDelay) const override
bool IsPNSCopperLayer(int aPNSLayer) const override
int64_t CalculateLengthForDelay(int64_t aDesiredDelay, int aWidth, bool aIsDiffPairCoupled, int aDiffPairCouplingGap, int aPNSLayer, const NETCLASS *aNetClass) override
PNS::RULE_RESOLVER * GetRuleResolver() override
bool TouchesCopperZone(const PNS::ITEM *aItem) const override
Copper zones are absent from NODE joints, so tail pruning must keep items that touch one.
bool syncTextItem(PNS::NODE *aWorld, BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
bool IsKicadCopperLayer(PCB_LAYER_ID aPcbnewLayer) const
bool inheritTrackWidthAndDpGap(PNS::ITEM *aItem, const VECTOR2I &aStartPosition, int *aInheritedWidth, int *aInheritedGap)
std::vector< std::unique_ptr< PNS::SOLID > > syncPad(PAD *aPad)
void SetStartLayerFromPCBNew(PCB_LAYER_ID aLayer)
bool syncBarcode(PNS::NODE *aWorld, PCB_BARCODE *aBarcode)
bool IsFlashedOnLayer(const PNS::ITEM *aItem, int aLayer) const override
long long GetNetBoardLength(PNS::NET_HANDLE aNet) const override
PCB_LAYER_ID GetBoardLayerFromPNSLayer(int aLayer) const override
BOARD * GetBoard() const
void SyncWorld(PNS::NODE *aWorld) override
int StackupHeight(int aFirstLayer, int aSecondLayer) const override
int64_t CalculateDelayForShapeLineChain(const SHAPE_LINE_CHAIN &aShape, int aWidth, bool aIsDiffPairCoupled, int aDiffPairCouplingGap, int aPNSLayer, const NETCLASS *aNetClass) override
PNS::DEBUG_DECORATOR * GetDebugDecorator() override
std::unique_ptr< PNS::SEGMENT > syncTrack(PCB_TRACK *aTrack)
PNS_PCBNEW_RULE_RESOLVER * m_ruleResolver
PNS::NET_HANDLE GetOrphanedNetHandle() override
std::unique_ptr< PNS::VIA > syncVia(PCB_VIA *aVia)
int GetPNSLayerFromBoardLayer(PCB_LAYER_ID aLayer) const override
PNS_LAYER_RANGE SetLayersFromPCBNew(PCB_LAYER_ID aStartLayer, PCB_LAYER_ID aEndLayer)
std::vector< LENGTH_DELAY_CALCULATION_ITEM > GetLengthDelayCalculationItems(const PNS::ITEM_SET &aLine, const NETCLASS *aNetClass) const
void UpdateItem(PNS::ITEM *aItem) override
bool ImportSizes(PNS::SIZES_SETTINGS &aSizes, PNS::ITEM *aStartItem, PNS::NET_HANDLE aNet, VECTOR2D aStartPosition) override
std::vector< ROUTER_PREVIEW_ITEM * > m_previewItems
Each preview item is in the view directly so it draws at its own layer's place.
void SetView(KIGFX::VIEW *aView)
void RemoveItem(PNS::ITEM *aItem) override
void AddItem(PNS::ITEM *aItem) override
void UpdateItem(PNS::ITEM *aItem) override
std::map< PAD *, OFFSET > m_fpOffsets
int GetNetCode(PNS::NET_HANDLE aNet) const override
virtual void SetHostTool(PCB_TOOL_BASE *aTool)
void DisplayItem(const PNS::ITEM *aItem, int aClearance, bool aEdit=false, int aFlags=0) override
std::unique_ptr< BOARD_COMMIT > m_commit
void addPreviewItem(ROUTER_PREVIEW_ITEM *aItem)
Add a preview item to the view and take ownership of it.
void modifyBoardItem(PNS::ITEM *aItem, BOARD_COMMIT &aCommit)
void EraseView() override
void HideItem(PNS::ITEM *aItem) override
void UpdateNet(PNS::NET_HANDLE aNet) override
BOARD_CONNECTED_ITEM * createBoardItem(PNS::ITEM *aItem)
KIGFX::VIEW * m_view
std::set< PAD * > m_independentPads
void DisplayPathLine(const SHAPE_LINE_CHAIN &aLine, int aImportance) override
std::unordered_map< BOARD_ITEM *, EDA_GROUP * > m_itemGroups
bool IsItemVisible(const PNS::ITEM *aItem) const override
std::unordered_set< BOARD_ITEM * > m_hiddenItems
EDA_UNITS GetUnits() const override
bool IsAnyLayerVisible(const PNS_LAYER_RANGE &aLayer) const override
PCB_TOOL_BASE * m_tool
bool GetSignalAggregate(PNS::NET_HANDLE aNetP, PNS::NET_HANDLE aNetN, long long &aExtraLength, long long &aExtraDelay) const override
void Commit() override
void DisplayRatline(const SHAPE_LINE_CHAIN &aRatline, PNS::NET_HANDLE aNet) override
std::unordered_map< BOARD_ITEM *, std::vector< BOARD_ITEM * > > m_replacementMap
wxString GetNetName(PNS::NET_HANDLE aNet) const override
~PNS_KICAD_IFACE() override
Represent a contiguous set of PCB layers.
int Start() const
bool Overlaps(const PNS_LAYER_RANGE &aOther) const
int End() const
PNS_LAYER_RANGE Intersection(const PNS_LAYER_RANGE &aOther) const
PNS_PCBNEW_DEBUG_DECORATOR(PNS::ROUTER_IFACE *aIface)
void AddPoint(const VECTOR2I &aP, const KIGFX::COLOR4D &aColor, int aSize, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void AddShape(const BOX2I &aBox, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void AddItem(const PNS::ITEM *aItem, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
virtual void Message(const wxString &msg, const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
void SetView(KIGFX::VIEW *aView)
void AddShape(const SHAPE *aShape, const KIGFX::COLOR4D &aColor, int aOverrideWidth=0, const wxString &aName=wxT(""), const SRC_LOCATION_INFO &aSrcLoc=SRC_LOCATION_INFO()) override
std::vector< PNS::ITEM * > m_clonedItems
int NetCode(PNS::NET_HANDLE aNet) override
std::unordered_map< TEMP_CLEARANCE_CACHE_KEY, int > m_tempClearanceCache
PNS_PCBNEW_RULE_RESOLVER(BOARD *aBoard, PNS::ROUTER_IFACE *aRouterIface)
bool IsDrilledHole(const PNS::ITEM *aItem) override
void ClearTemporaryCaches() override
bool QueryConstraint(PNS::CONSTRAINT_TYPE aType, const PNS::ITEM *aItemA, const PNS::ITEM *aItemB, int aLayer, PNS::CONSTRAINT *aConstraint) override
int ClearanceEpsilon() const override
BOARD_ITEM * getBoardItem(const PNS::ITEM *aItem, PCB_LAYER_ID aBoardLayer, int aIdx=0)
bool IsKeepout(const PNS::ITEM *aObstacle, const PNS::ITEM *aItem, bool *aEnforce) override
const SHAPE_LINE_CHAIN & HullCache(const PNS::ITEM *aItem, int aClearance, int aWalkaroundThickness, int aLayer) override
int Clearance(const PNS::ITEM *aA, const PNS::ITEM *aB, bool aUseClearanceEpsilon=true) override
void ClearCacheForItems(std::vector< const PNS::ITEM * > &aItems) override
bool IsNonPlatedSlot(const PNS::ITEM *aItem) override
bool HasUserDefinedPhysicalConstraint() override
std::unordered_map< CLEARANCE_CACHE_KEY, int > m_clearanceCache
int DpNetPolarity(PNS::NET_HANDLE aNet) override
bool IsNetTieExclusion(const PNS::ITEM *aItem, const VECTOR2I &aCollisionPos, const PNS::ITEM *aCollidingItem) override
bool IsInNetTie(const PNS::ITEM *aA) override
PNS::NET_HANDLE DpCoupledNet(PNS::NET_HANDLE aNet) override
bool DpNetPair(const PNS::ITEM *aItem, PNS::NET_HANDLE &aNetP, PNS::NET_HANDLE &aNetN) override
PNS::ROUTER_IFACE * m_routerIface
std::unordered_map< HULL_CACHE_KEY, SHAPE_LINE_CHAIN > m_hullCache
std::optional< bool > m_hasUserPhysicalConstraint
wxString NetName(PNS::NET_HANDLE aNet) override
@ DM_SHAPE
Shape body only, in the normal or collision color.
@ DM_SHADOW
Clearance halo only, drawn behind board items.
void SetWidth(int aWidth)
void SetClearance(int aClearance)
static constexpr double PathOverlayDepth
void SetColor(const KIGFX::COLOR4D &aColor)
double GetOriginDepth() const
void SetDepth(double aDepth)
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I::extended_type ecoord
Definition seg.h:40
VECTOR2I B
Definition seg.h:46
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:116
const VECTOR2I & GetP1() const
Definition shape_arc.h:115
const VECTOR2I & GetP0() const
Definition shape_arc.h:114
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int Width() const
Get the current width of the segments in the chain.
void SetWidth(int aWidth) override
Set the width of all segments in the chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
const std::vector< VECTOR2I > & CPoints() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
void GetTriangle(int index, VECTOR2I &a, VECTOR2I &b, VECTOR2I &c) const
Represent a set of closed polygons.
bool IsTriangulationUpToDate() const
virtual void CacheTriangulation(bool aSimplify=false, const TASK_SUBMITTER &aSubmitter={}, bool aBuildIndexes=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
unsigned int TriangulatedPolyCount() const
Return the number of triangulated polygons.
int OutlineCount() const
Return the number of outlines in the set.
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
void Append(int aX, int aY)
Append a new point at the end of the polygon.
An abstract shape on 2D plane.
Definition shape.h:124
virtual VECTOR2I GetStart() const
Definition shape.h:296
virtual VECTOR2I GetEnd() const
Definition shape.h:297
virtual const BOX2I BBox(int aClearance=0) const =0
Compute a bounding box of the shape, with a margin of aClearance a collision.
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition vector2d.h:574
static constexpr extended_type ECOORD_MAX
Definition vector2d.h:72
VECTOR2_TRAITS< int32_t >::extended_type extended_type
Definition vector2d.h:69
Handle a list of polygons defining a copper zone.
Definition zone.h:70
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition zone.cpp:1516
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:832
bool GetDoNotAllowVias() const
Definition zone.h:850
bool GetDoNotAllowPads() const
Definition zone.h:852
bool GetDoNotAllowTracks() const
Definition zone.h:851
SHAPE_POLY_SET * Outline()
Definition zone.h:421
SHAPE_POLY_SET GetBoardOutline() const
Definition zone.cpp:951
bool GetDoNotAllowFootprints() const
Definition zone.h:853
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:133
bool HasKeepoutParametersSet() const
Accessor to determine if any keepout parameters are set.
Definition zone.h:823
@ VIA_DIAMETER_CONSTRAINT
@ DIFF_PAIR_GAP_CONSTRAINT
@ TRACK_WIDTH_CONSTRAINT
@ EDGE_CLEARANCE_CONSTRAINT
@ LENGTH_CONSTRAINT
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
@ CLEARANCE_CONSTRAINT
@ MAX_UNCOUPLED_CONSTRAINT
@ SKEW_CONSTRAINT
@ HOLE_CLEARANCE_CONSTRAINT
@ HOLE_SIZE_CONSTRAINT
@ PHYSICAL_CLEARANCE_CONSTRAINT
@ HOLE_TO_HOLE_CONSTRAINT
#define _(s)
@ NO_RECURSE
Definition eda_item.h:52
#define ROUTER_TRANSIENT
transient items that should NOT be cached
#define IN_EDIT
Item currently edited.
EDA_UNITS
Definition eda_units.h:44
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
Definition hash.h:28
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START
Definition layer_ids.h:170
@ ALWAYS_FLASHED
Always flashed for connectivity.
Definition layer_ids.h:182
@ LAYER_RATSNEST
Definition layer_ids.h:249
@ LAYER_SELECT_OVERLAY
Selected items overlay.
Definition layer_ids.h:276
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Cu
Definition layer_ids.h:61
@ Margin
Definition layer_ids.h:109
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:167
@ F_Cu
Definition layer_ids.h:60
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
@ APPEARANCE
Visibility flag has changed.
Definition view_item.h:49
Push and Shove diff pair dimensions (gap) settings dialog.
CONSTRAINT_TYPE
Definition pns_node.h:52
void * NET_HANDLE
Definition pns_item.h:55
@ MK_LOCKED
Definition pns_item.h:45
STL namespace.
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ PTH
Plated through hole pad.
Definition padstack.h:97
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:99
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:120
BARCODE class definition.
VIATYPE
@ SHOW_WITH_VIA_WHILE_ROUTING_OR_DRAGGING
@ SHOW_WHILE_ROUTING
@ SHOW_WITH_VIA_ALWAYS
@ SHOW_WITH_VIA_WHILE_ROUTING
static bool isEdge(const PNS::ITEM *aItem)
static bool isHole(const PNS::ITEM *aItem)
static bool isCopper(const PNS::ITEM *aItem)
#define ENTERED_GROUP_MAGIC_NUMBER
@ RPT_SEVERITY_IGNORE
#define PNS_SEMI_SOLID
@ SH_SEGMENT
line segment
Definition shape.h:44
@ SH_ARC
circular arc
Definition shape.h:50
@ SH_LINE_CHAIN
line chain (polyline)
Definition shape.h:45
VECTOR2I::extended_type ecoord
const PNS::ITEM * A
bool operator==(const CLEARANCE_CACHE_KEY &other) const
const PNS::ITEM * B
CLEARANCE_CACHE_KEY(const PNS::ITEM *aA, const PNS::ITEM *aB, bool aFlag)
const PNS::ITEM * item
bool operator==(const HULL_CACHE_KEY &other) const
Struct to control which optimisations the length calculation code runs on the given path objects.
TRACK_CLEARANCE_MODE m_TrackClearance
An abstract function object, returning a design rule (clearance, diff pair gap, etc) required between...
Definition pns_node.h:74
wxString m_RuleName
Definition pns_node.h:78
bool m_IsTimeDomain
Definition pns_node.h:81
MINOPTMAX< int > m_Value
Definition pns_node.h:76
CONSTRAINT_TYPE m_Type
Definition pns_node.h:75
bool operator<(const PARTICIPANT &o) const
bool operator==(const PARTICIPANT &o) const
TEMP_CLEARANCE_CACHE_KEY(const PNS::ITEM *aA, const PNS::ITEM *aB, bool aFlag)
bool operator==(const TEMP_CLEARANCE_CACHE_KEY &o) const
static PARTICIPANT makeParticipant(const PNS::ITEM *aItem)
A data structure to contain basic geometry data which can affect signal propagation calculations.
int64_t DiffPairCouplingGap
The gap between coupled tracks.
const NETCLASS * NetClass
The net class this track belongs to.
int64_t Width
The width (in internal units) of the track.
bool IsDiffPairCoupled
Whether this track or via is a member of a coupled differential pair.
PCB_LAYER_ID Layer
The layer this track is on.
std::size_t operator()(const CLEARANCE_CACHE_KEY &k) const noexcept
std::size_t operator()(const HULL_CACHE_KEY &k) const noexcept
std::size_t operator()(const TEMP_CLEARANCE_CACHE_KEY &k) const noexcept
KIBIS top(path, &reporter)
const SHAPE_LINE_CHAIN chain
arc1_slc SetWidth(0)
wxString result
Test unit parsing edge cases and error handling.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:98
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:95
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:96
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:100
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition typeinfo.h:81
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:82
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:99
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:87
@ PCB_GRID_ITEM_T
a subgrid placed on a board
Definition typeinfo.h:238
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:94
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:97
@ PCB_DRILL_CHART_T
class PCB_DRILL_CHART, a live drill chart derived from PCB_TABLE
Definition typeinfo.h:239
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:55
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707