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